ruby Hash#merge with block; who knew?

I just noticed that ruby Hash#merge has a form that takes a block, where you can customize how the merging happens.

This makes it easy to write your own custom-fitted #deep_merge. (I actually noticed it existed when looking at the source for Rails3 ActiveSupport #deep_merge.)

It’s hard to write a ‘general purpose’ deep merge of hashes, exactly what you want in a deep-merge sort of depends on your situtation and the nature of your data. For instance, the ActiveSupport one was not what I wanted, as it didn’t handle combining arrays.

Here’s one that does what I needed. Yeah, could have monkey-patched it onto Hash instead, leading to more OO-looking code when calling, but I get a bad feeling from monkey-patching onto standard library objects, so generally don’t.

 # Merges new_hash into source_hash, without modifying arguments, but
 # will merge nested arrays and hashes too. Also will NOT merge nil or blank
 # from new_hash into old_hash
 def deep_safe_merge(source_hash, new_hash)
   source_hash.merge(new_hash) do |key, old, new|
     if new.respond_to?(:blank) && new.blank?
        old        
     elsif (old.kind_of?(Hash) and new.kind_of?(Hash))
        deep_merge(old, new)
     elsif (old.kind_of?(Array) and new.kind_of?(Array))
        old.concat(new).uniq
     else
        new
     end
   end
 end

This entry was posted in General. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s