Inject the Hash before you tap it

There is a Ruby best practices blog that is exploring the uses of Object#tap, particularly with respect to building hashes, as per the example they give:

 
   def ugly  
     results = {}  

     [:x, :y, :z].each do |letter|  
       results[letter] = rand(100)  
     end  

     results  
   end  
 
   def sexy  
     returning({}) do |results|  
       [:x, :y, :z].each do |letter|  
         results[letter] = rand(100)  
       end  
     end  
   end

There is a lot of commentary as to which of the two is better. But in programming there is always another way! In code we are building a hash from an array. This is exactly the kind of thing Ruby’s Enumerable#inject method is for. Some of the commenteres on the blog have pointed this out.

   def very_sexy
     [:x, :y, :z].inject({}) do |results, letter|
       results[letter] = rand(100)
       results
     end
   end  

I use this often enough to write a method for the tedious aspects of having to return the hash

module Enumerable
  def inject_hash(hash = {}) 
    inject(hash) {|(h,item)| yield(h,item); h}
  end 
end
   def smokin
     [:x, :y, :z].inject_hash do |results, letter|
       results[letter] = rand(100)
     end
   end  

I am excited about the inclusion of Object#tap in Ruby 1.9, but it should be used mostly as a debugging tool or to overcome poorly designed interfaces. Frequent use in your own code could be a code smell.

© Greg Weber. All original code snippets are placed in the public domain.
Written on Wed Aug 5 19:57:39 2009.
Tagged as ruby.
Send author an email.