Using Hashes as Caches

One of the coolest features of Ruby’s Hash class is that you can customize how it behaves when it can’t find a key. Stupid example:

# Everybody knows that you can communicate with foreigners by 
# speaking loudly and slowly
english_to_french = Hash.new{|hash, key|
  hash[key] = key.upcase.split(//).join(" ") + "?!"
}
english_to_french["restroom"]   # => "R E S T R O O M?!"

One particularly useful application of this feature is to use a Hash as a cache for some slow operation. Here’s a snippet from Firetower, where a Hash is being used as a table of user accounts. If an unknown user ID is requested, the Hash makes a web service call to retrieve the requested data, stores it away, and returns it.

      @users = Hash.new do |cache, user_id|
        data = session.get(subdomain, "/users/#{user_id}.json")
        cache[user_id] = data['user']
      end