Ruby’s Hash can accept a block when you initialize it. The block is called any time you attempt to access a key that is not present. Hash’s initialization block expects the following format:

Hash.new{|hash, key| ... }

The hash references the hash itself, and the key parameter is the missing key. With this, you can initialize default values in the hash before they get accessed. Here are a few interesting things you can do with a hash’s initialization block.

By setting the value to an array, you can easily group items in a list:

groups = Hash.new{|h,k| h[k] = [] } list = ["cake", "bake", "cookie", "car", "apple"] # Group by string length: list.each{|v| groups[v.length] << v} groups #=> {4=>["cake", "bake"], 6=>["cookie"], 3=>["car"], 5=>["apple"]}

Setting the value to 0 is a good way to count the occurrences of various items in a list:

counts = Hash.new{|h,k| h[k] = 0 } list = ["cake", "cake", "cookie", "car", "cookie"] # Group by string length: list.each{|v| counts[v] += 1 } counts #=> {"cake"=>2, "cookie"=>2, "car"=>1}

Or if you return hashes that return hashes, you can build a tree structure:

tree_block = lambda{|h,k| h[k] = Hash.new(&tree_block) } opts = Hash.new(&tree_block) opts['dev']['db']['host'] = "localhost:2828" opts['dev']['db']['user'] = "me" opts['dev']['db']['password'] = "secret" opts['test']['db']['host'] = "localhost:2828" opts['test']['db']['user'] = "test_user" opts['test']['db']['password'] = "test_secret" opts #=> {"dev"=> {"db"=>{"host"=>"localhost:2828", "user"=>"me", "password"=>"secret"}}, "test"=> {"db"=>{"host"=>"localhost:2828", "user"=>"test_user", "password"=>"test_secret"}} }

A block can also be used to create a caching layer:

require 'net/http' http = Hash.new{|h,k| h[k] = Net::HTTP.get_response(URI(k)).body } http['http://www.google.com'] # makes a request http['http://www.google.com'] # returns cached value

In ruby 1.9 hashes are ordered so you can make the cache a fixed length, and evict old values:

http = Hash.new{|h,k| h[k] = Net::HTTP.get_response(URI(k)).body if h.length > 3 h.delete(h.keys.first) end } http['http://www.google.com'] http['http://www.yahoo.com'] http['http://www.bing.com'] http['http://www.reddit.com'] # this evicts http://www.google.com http.keys #=> ["http://www.yahoo.com", "http://www.bing.com", "http://www.reddit.com"]

You can also use it to compute recursive functions:

factorial = Hash.new do |h,k| if k > 1 h[k] = h[k-1] * k else h[k] = 1 end end

This will cache each result, so if you have computed part of a number’s factorial, it won’t need to compute it again. For instance, factorial[4] will compute the values for 1,2, and 3, and then if you call factorial[3] it will already have the result. This is a somewhat contrived use, but it’s interesting none the less.

As you can see the default block for a Hash has a lot of interesting uses, are there any that you find particularly useful?