
Not exactly new, passing blocks to Hash.new has been around for a while (since the 1.8.0 release I think). This can be used to supply a default value or action for accessing keys not in the hash.
hash = Hash.new {|h,k| h[k] = "Default Value"}
hash = Hash.new {|h,k| raise "No Such Key #{k}"}
Note, the objects yielded to the block are the hash and the key (not a key and a value, which is an easy but nonsensical mistake to make).
In the first example above we didn’t just return a default value, we also assigned to the appropriate key in the hash — next time we try to access the hash using this key we will get the default value directly instead of having to evaluate the block again. This point of view — a hash with a block attached to generate default values — is useful, but not terribly interesting.
Turning the view around we have a block with an attached cache — giving us simple memoization. Here’s a little memoized factorial calculator:
fact = Hash.new {|h, n| n < 2 ? h[n] = 1 : h[n] = h[n-1] * n}
p fact[4] #--> 24
p fact #--> {1=>1, 2=>2, 3=>6, 4=>24}
Now, there are obvious limitations: the [] hash method takes a single object as a key so you can’t pass multiple parameters directly (you’d need to wrap them in an array or something), and, parameter caching will be based on the #hash method of the objects used as keys. Another limitation is cache size and expiry — in which case you might want to try the memoize module available on the RAA.