Permalink
Browse files

Mash: fix deep_merge/deep_update and make `merge` deep by default

`deep_update` was broken because it wasn't recursive at all. Also,
since `merge` wasn't implemented in Mash it was also broken as a
consequence of not normalizing the keys. This makes `merge` deep
by default to be consistent with `update` and `merge!` which were
deep before.
  • Loading branch information...
1 parent bbb21e2 commit 309ddd41caf2a1a3cc9761232b21aa3eaeb9b86f @mislav committed Aug 16, 2010
Showing with 44 additions and 8 deletions.
  1. +8 −2 lib/hashie/mash.rb
  2. +36 −6 spec/hashie/mash_spec.rb
View
@@ -96,14 +96,20 @@ def key?(key)
# Performs a deep_update on a duplicate of the
# current mash.
def deep_merge(other_hash)
- dup.deep_merge!(other_hash)
+ dup.deep_update(other_hash)
end
+ alias_method :merge, :deep_merge
# Recursively merges this mash with the passed
# in hash, merging each hash in the hierarchy.
def deep_update(other_hash)
other_hash.each_pair do |k,v|
- regular_writer(convert_key(k), convert_value(other_hash[k], true))
+ key = convert_key(k)
+ if regular_reader(key).is_a?(Mash) and v.is_a?(::Hash)
+ regular_reader(key).deep_update(v)
+ else
+ regular_writer(key, convert_value(v, true))
+ end
end
self
end
View
@@ -67,12 +67,42 @@
@mash.author.website.should == Hashie::Mash.new(:url => "http://www.mbleigh.com/")
end
- it "#deep_update should recursively Hashie::Mash Hashie::Mashes and hashes together" do
- @mash.first_name = "Michael"
- @mash.last_name = "Bleigh"
- @mash.details = Hashie::Hash[:email => "michael@asf.com"].to_mash
- @mash.deep_update({:details => {:email => "michael@intridea.com"}})
- @mash.details.email.should == "michael@intridea.com"
+ context "#deep_update" do
+ before do
+ @mash.first_name = "Michael"
+ @mash.last_name = "Bleigh"
+ @mash.details!.email = "michael@asf.com"
+ @mash.details.address = "Nowhere road"
+ end
+
+ it "should recursively Hashie::Mash Hashie::Mashes and hashes together" do
+ @mash.deep_update(:details => {:email => "michael@intridea.com", :city => "Imagineton"})
+ @mash.first_name.should == "Michael"
+ @mash.details.email.should == "michael@intridea.com"
+ @mash.details.address.should == "Nowhere road"
+ @mash.details.city.should == "Imagineton"
+ end
+
+ it "should make #update deep by default" do
+ @mash.update(:details => {:address => "Fake street"}).should eql(@mash)
+ @mash.details.address.should == "Fake street"
+ @mash.details.email.should == "michael@asf.com"
+ end
+
+ it "should clone before a #deep_merge" do
+ duped = @mash.deep_merge(:details => {:address => "Fake street"})
+ duped.should_not eql(@mash)
+ duped.details.address.should == "Fake street"
+ @mash.details.address.should == "Nowhere road"
+ duped.details.email.should == "michael@asf.com"
+ end
+
+ it "regular #merge should be deep" do
+ duped = @mash.merge(:details => {:email => "michael@intridea.com"})
+ duped.should_not eql(@mash)
+ duped.details.email.should == "michael@intridea.com"
+ duped.details.address.should == "Nowhere road"
+ end
end
it "should convert hash assignments into Hashie::Mashes" do

0 comments on commit 309ddd4

Please sign in to comment.