# Methodhash 0.5 released

**URL:** <https://www.ruby-forum.com/t/methodhash-0-5-released/182895>\
**Category:** Ruby\
**Created:** [February 4, 2010, 12:50pm UTC](https://www.ruby-forum.com/t/methodhash-0-5-released/182895 "2010-02-04T12:50:36Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![fredrikj](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/d9b06d/32.png) [@fredrikj](https://www.ruby-forum.com/u/fredrikj)\
**Post date:** [February 4, 2010, 12:50pm UTC](https://www.ruby-forum.com/t/methodhash-0-5-released/182895/1 "2010-02-04T12:50:36Z")

</div>

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 J.

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

[GitHub - fredrikj/methodhash: A Ruby Hash defined by a method. Enables disk storage of values calculated by method.](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

```

---

<div class="post-metadata">

**Author:** ![fredrikj](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/d9b06d/32.png) [@fredrikj](https://www.ruby-forum.com/u/fredrikj)\
**Post date:** [February 4, 2010, 1:18pm UTC](https://www.ruby-forum.com/t/methodhash-0-5-released/182895/2 "2010-02-04T13:18:07Z")

</div>

On 02/04/2010 12:46 PM, Fredrik J. wrote:

> 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/](http://raa.ruby-lang.org/project/memoize/)

> ```
> 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

---

<div class="post-metadata">

**Author:** ![fredrikj](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/d9b06d/32.png) [@fredrikj](https://www.ruby-forum.com/u/fredrikj)\
**Post date:** [February 4, 2010, 2:05pm UTC](https://www.ruby-forum.com/t/methodhash-0-5-released/182895/3 "2010-02-04T14:05:32Z")

</div>

> 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…

---

<div class="post-metadata">

**Author:** ![fredrikj](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/d9b06d/32.png) [@fredrikj](https://www.ruby-forum.com/u/fredrikj)\
**Post date:** [February 4, 2010, 2:13pm UTC](https://www.ruby-forum.com/t/methodhash-0-5-released/182895/4 "2010-02-04T14:13:44Z")

</div>

On Thu, Feb 4, 2010 at 8:05 AM, Fredrik J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> > 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. 🙂

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/](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

---

<div class="post-metadata">

**Author:** ![fredrikj](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/d9b06d/32.png) [@fredrikj](https://www.ruby-forum.com/u/fredrikj)\
**Post date:** [February 4, 2010, 5:50pm UTC](https://www.ruby-forum.com/t/methodhash-0-5-released/182895/5 "2010-02-04T17:50:20Z")

</div>

On 04.02.2010 14:02, Fredrik J. wrote:

> > 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.

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
