summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasiliy Ermolovich <younash@gmail.com>2012-03-25 16:05:32 +0300
committerVasiliy Ermolovich <younash@gmail.com>2013-02-12 10:32:30 +0300
commite94b70f20600d460c5123f5f9324fa36822ea69a (patch)
treeadc9041d49bc31ea5036c1410f17230a5dc49ddd
parentf7cb5e2b3c3ea3edd66ed2f9865eac7d7db80359 (diff)
downloadhashie-e94b70f20600d460c5123f5f9324fa36822ea69a.tar.gz
add DeepMerge extension
-rw-r--r--README.markdown25
-rw-r--r--lib/hashie/extensions/deep_merge.rb16
-rw-r--r--spec/hashie/extensions/deep_merge_spec.rb20
3 files changed, 54 insertions, 7 deletions
diff --git a/README.markdown b/README.markdown
index 30504c7..80061c4 100644
--- a/README.markdown
+++ b/README.markdown
@@ -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 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"}
-This extension *will* allow you to easily include a recursive merging
-system to any Hash descendant.
+ 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
diff --git a/lib/hashie/extensions/deep_merge.rb b/lib/hashie/extensions/deep_merge.rb
index f019be3..ce821de 100644
--- a/lib/hashie/extensions/deep_merge.rb
+++ b/lib/hashie/extensions/deep_merge.rb
@@ -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
diff --git a/spec/hashie/extensions/deep_merge_spec.rb b/spec/hashie/extensions/deep_merge_spec.rb
new file mode 100644
index 0000000..d835381
--- /dev/null
+++ b/spec/hashie/extensions/deep_merge_spec.rb
@@ -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