add DeepMerge extension

This commit is contained in:
Vasiliy Ermolovich 2012-03-25 16:05:32 +03:00
parent f7cb5e2b3c
commit e94b70f206
3 changed files with 54 additions and 7 deletions

View File

@ -34,7 +34,7 @@ applications such as an API client:
include Hashie::Extensions::Coercion
coerce_key :user, User
end
user_hash = {:name => "Bob"}
Tweet.new(:user => user_hash)
# => automatically calls User.coerce(user_hash) or
@ -47,7 +47,7 @@ Hash-like class that is self-propagating.
class SpecialHash < Hash
include Hashie::Extensions::Coercion
coerce_value Hash, SpecialHash
def initialize(hash = {})
super
hash.each_pair do |k,v|
@ -78,7 +78,7 @@ included as individual modules, i.e. `Hashie::Extensions::MethodReader`,
class MyHash < Hash
include Hashie::Extensions::MethodAccess
end
h = MyHash.new
h.abc = 'def'
h.abc # => 'def'
@ -97,10 +97,23 @@ hash in question. This means you can safely merge together indifferent
and non-indifferent hashes arbitrarily deeply without worrying about
whether you'll be able to `hash[:other][:another]` properly.
### DeepMerge (Unimplemented)
### DeepMerge
This extension *will* allow you to easily include a recursive merging
system to any Hash descendant.
This extension allow you to easily include a recursive merging
system to any Hash descendant:
class MyHash < Hash
include Hashie::Extensions::DeepMerge
end
h1 = MyHash.new
h2 = MyHash.new
h1 = {:x => {:y => [4,5,6]}, :z => [7,8,9]}
h2 = {:x => {:y => [7,8,9]}, :z => "xyz"}
h1.deep_merge(h2) #=> { :x => {:y => [7, 8, 9]}, :z => "xyz" }
h2.deep_merge(h1) #=> { :x => {:y => [4, 5, 6]}, :z => [7, 8, 9] }
## Mash

View File

@ -1,7 +1,21 @@
module Hashie
module Extensions
module DeepMerge
# TODO: Implement deep merging.
# Returns a new hash with +self+ and +other_hash+ merged recursively.
def deep_merge(other_hash)
(class << (h = dup); self; end).send :include, Hashie::Extensions::DeepMerge
h.deep_merge!(other_hash)
end
# Returns a new hash with +self+ and +other_hash+ merged recursively.
# Modifies the receiver in place.
def deep_merge!(other_hash)
other_hash.each do |k,v|
(class << (tv = self[k]); self; end).send :include, Hashie::Extensions::DeepMerge
self[k] = tv.is_a?(::Hash) && v.is_a?(::Hash) ? tv.deep_merge(v) : v
end
self
end
end
end
end

View File

@ -0,0 +1,20 @@
require 'spec_helper'
describe Hashie::Extensions::DeepMerge do
class DeepMergeHash < Hash; include Hashie::Extensions::DeepMerge end
subject{ DeepMergeHash }
let(:h1) { subject.new.merge(:a => "a", :b => "b", :c => { :c1 => "c1", :c2 => "c2", :c3 => { :d1 => "d1" } }) }
let(:h2) { { :a => 1, :c => { :c1 => 2, :c3 => { :d2 => "d2" } } } }
let(:expected_hash) { { :a => 1, :b => "b", :c => { :c1 => 2, :c2 => "c2", :c3 => { :d1 => "d1", :d2 => "d2" } } } }
it 'should deep merge two hashes' do
h1.deep_merge(h2).should == expected_hash
end
it 'should deep merge two hashes with bang method' do
h1.deep_merge!(h2)
h1.should == expected_hash
end
end