Monday, June 14, 2010

Deep_merge: Ruby Recursive Merging for Hashes

Ruby provides some nice merge capabilities in hash and array. But it rightly doesn’t give us recursive merging, because it’s too poorly defined to standardize. However, recursive merging sometimes solves problems that can’t be solved other ways.
Take this code:
h1 = {:x => {:y => [4,5,6], :z => [7,8,9]}}
h2 = {:x => {:y => [1,2,3], :z => 'xyz'}}
If you want to merge these two hashes, what should happen? Well there are several possibilities. Let’s see how deep_merge handles it:
h2.deep_merge!(h1)
# results: h2 = {:x=>{:z=>[7, 8, 9], :y=>[1, 2, 3, 4, 5, 6]}}
# notice we overwrote 'xyz'! (That's what the bang means)
# Let's try it without the bang:
h1 = {:x => {:y => [4,5,6], :z => [7,8,9]}}
h2 = {:x => {:y => [1,2,3], :z => 'xyz'}}
h2.deep_merge(h1)
# results: h2 = {:x=>{:z=>"xyz", :y=>[1, 2, 3, 4, 5, 6]}}
# notice 'xyz' didn't get overwritten this time. No bang.
Let’s get a little more complicated with a “knockout” merge. We introduce a special string “–” which can “knockout” an element in an existing hash or array element:
h1 = {:x => {:y => ["d","e","--c"]}}
h2 = {:x => {:y => ["a","b","c"]}}
h2.ko_deep_merge!(h1)
# h2 = {:x=>{:y=>["a", "b", "d", "e"]}}
# notice no "c" any more!
Many of these features are configurable to your needs – feel free to read up in the source code. Home page and installation instructions are here: http://trac.misuse.org/science/wiki/DeepMerge

http://www.misuse.org/science/2008/05/19/deep_merge-ruby-recursive-merging-for-hashes/

No comments: