inject vs. each_with_object

I tweeted about this a while back, but I thought I’d write about how I ran into problems with inject and how each_with_object made it all better.

So I was originally using inject to create a hash of video game data from an array of div elements I was parsing with hpricot like so:

div_elements.inject({}) do |hash, div_element|
  game_name = div_element.at("//p/a").inner_text
  last_played_online_time = div_element.at("//p/strong").inner_text
  hash[game_name] = last_played_online_time
  hash
end

But sometimes, a user had never played a game online, so the text in the strong element I was checking for the time would contain something like “not played” in this case. I thought I could easily solve this by doing:

div_elements.inject({}) do |hash, div_element|
  game_name = div_element.at("//p/a").inner_text
  last_played_online_time = div_element.at("//p/strong").inner_text
  next if last_played_online_time =~ /not played/i
  hash[game_name] = last_played_online_time
  hash
end

But this was bad. Next would return nil, setting the accumulator to nil and causing bad errors on the next pass through the block. each_with_object did not have this problem. Changing things to use it looked like:

div_elements.each_with_object({}) do |div_element, hash|
  game_name = div_element.at("//p/a").inner_text
  last_played_online_time = div_element.at("//p/strong").inner_text
  next if last_played_online_time =~ /not played/i
  hash[game_name] = last_played_online_time
end

So not that different! But better. I didn’t have to worry about returning the accumulator, making things a little simpler.