methodhash 0.5 released

  • Thread starter Fredrik Johansson
  • Start date

F

Fredrik Johansson

I created a small "lab tool" that makes life easier for me. It's
basically a Hash that you can't put values into, the values can only
be obtained from a method that you define. I created it with the idea
that a calculation should only have to be done once. I paste the
README file below.
Please let me know what you think!

Best regards,
Fredrik Johansson



NAME

methodhash

SYNOPSIS

A Hash subclass for automatic storage of values obtained from a
method
defined by the user. Useful for lengthy calculations on large
datasets.

URI

http://github.com/fredrikj/methodhash

INSTALL

gem install methodhash

DESCRIPTION

A Hash subclass that defines its values from a specified method.
Use it by creating a subclass of MethodHash, and define a method
with the name "mymethod" in it.
Like this (same code in samples/samples.rb):

# 1. Simple use
class AddOne < MethodHash
def mymethod(a)
sleep 3
a + 1
end
end

a = AddOne.new
a # {}
a[1] # 2
a[7] # 8
a # {1=>2, 7=>8}
puts a.dump # --- !map:AddOne
# 1: 2
# 7: 8


# 2. With a file
b = AddOne.new '/tmp/one.yml'
b # {}
b[1] # 2
b.dump # '/tmp/one.yml'
c = AddOne.new '/tmp/one.yml'
puts c.inspect # {1=>2}


# 3. Some protection against data corruption.
class AddTwo < MethodHash
def mymethod(a)
a + 2
end
end

begin
d = AddTwo.new '/tmp/one.yml' # ArgumentError: Path holds class
AddOne
rescue
puts $!
end


# 4. Saving exceptions arising from mymethod.
class AddOneFaulty < MethodHash
def mymethod(a)
rand(2)==0 ? raise("Epic Fail!") : a+1
end
end

e = AddOneFaulty.new
e[1] # RuntimeError: Epic Fail! # If something bad
happened
e # {1=>"ERROR: Epic Fail!"}
e.retry_errors # false
e[1] # RuntimeError: Epic Fail! # Still keeping
the error
e.retry_errors=true # true
e[1] # 2 # If better luck
this time
e # {1=>2}


# 5. A more complex setting
class AddThree < MethodHash
def initialize(path1=nil, path2=nil, mypath=nil)
@one = AddOne.new(path1)
@two = AddTwo.new(path2)
super(mypath)
end

def mymethod(a)
@one[a] + @two[a] - a
end

def dump
@one.dump
@two.dump
super
end
end

f = AddThree.new( '/tmp/one.yml', '/tmp/two.yml')
puts f[3]
f.dump


# 6. With two arguments
class Add < MethodHash
def mymethod(a,b)
a + b
end
end




HISTORY
0.5.0

Initial version
 
Ad

Advertisements

R

Robert Klemme

I created a small "lab tool" that makes life easier for me. It's
basically a Hash that you can't put values into, the values can only
be obtained from a method that you define. I created it with the idea
that a calculation should only have to be done once. I paste the
README file below.
Please let me know what you think!
http://raa.ruby-lang.org/project/memoize/

A Hash subclass that defines its values from a specified method.
Use it by creating a subclass of MethodHash, and define a method
with the name "mymethod" in it.
Like this (same code in samples/samples.rb):

# 1. Simple use
class AddOne < MethodHash
def mymethod(a)
sleep 3
a + 1
end
end

a = AddOne.new
a # {}
a[1] # 2
a[7] # 8
a # {1=>2, 7=>8}
puts a.dump # --- !map:AddOne
# 1: 2
# 7: 8

You can do this with a Hash already:

irb(main):001:0> a = Hash.new {|h,k| printf("calc %p\n",k);h[k] = k + 2}
# add two
=> {}
irb(main):002:0> a[1]
calc 1
=> 3
irb(main):003:0> a[1]
=> 3
irb(main):004:0> a[5]
calc 5
=> 7
irb(main):005:0> a[5]
=> 7
irb(main):006:0> a
=> {1=>3, 5=>7}
irb(main):007:0>

Granted, serialization to a file needs a few lines more.

Kind regards

robert
 
F

Fredrik Johansson

You can do this with a Hash already:

Sure (I learned that from Ruby Best Practices. great book!), but I
would like to argue that it's a bit more tidy to define a class (a
subclass of MethodHash) in one place, which I can then reuse for
anything I need to. But I don't claim to have revolutionized the world
with this. :)
Granted, serialization to a file needs a few lines more.

The use I have of it is that some calculations I have made that took
some time to do, is easily available at any time later by just
remembering the class name I used for it. Maybe the name MethodHash is
misleading...
 
G

Gregory Brown

Sure (I learned that from Ruby Best Practices. great book!), but I
would like to argue that it's a bit more tidy to define a class (a
subclass of MethodHash) in one place, which I can then reuse for
anything I need to. But I don't claim to have revolutionized the world
with this. :)

Doing so introduces an inheritance relationship, which is rarely a
good thing in Ruby.
You might want to check out the link Robert suggested, for memoize.

http://raa.ruby-lang.org/project/memoize/

It also handles file based caching and is one idiomatic way of doing
what you're trying to do here.

-greg
 
Ad

Advertisements

R

Robert Klemme

Sure (I learned that from Ruby Best Practices. great book!), but I
would like to argue that it's a bit more tidy to define a class (a
subclass of MethodHash) in one place, which I can then reuse for
anything I need to.

Well, there are multiple ways to reuse code and maintain DRY. You do
not necessarily need a class for that.

def add_two
Hash.new {|h,k| h[k] = k + 2}
end

or, a more generic variant

def make_cache
Hash.new {|h,k| h[k] = yield(k)}
end

AddTwo = make_cache {|x| x + 2}

etc.
But I don't claim to have revolutionized the world
with this. :)

Well, if you put a library in public then you probably want it to be
used. For that it needs to provide value to others. If it doesn't it's
probably not used and your effort may be in vain. :)
The use I have of it is that some calculations I have made that took
some time to do, is easily available at any time later by just
remembering the class name I used for it. Maybe the name MethodHash is
misleading...

But what you actually want is the *instance* that does the caching,
otherwise you'll loose cached values. Or do you store results somewhere
in a class instance variable?

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top