Skip to content

Commit

Permalink
Added block to deep merge extension
Browse files Browse the repository at this point in the history
  • Loading branch information
Ilya Kamenko committed Dec 29, 2014
1 parent 337a980 commit 8efa387
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* [#252](https://github.com/intridia/hashie/pull/252): Add support for conditionally required Hashie::Dash attributes - [@ccashwell](https://github.com/ccashwell).
* [#256](https://github.com/intridia/hashie/pull/256): Inherit key coercions - [@Erol](https://github.com/Erol).
* [#259](https://github.com/intridia/hashie/pull/259): Fix handling of default proc values in Mash - [@Erol](https://github.com/Erol).
* [#260](https://github.com/intridia/hashie/pull/260): Add block to deep merge extension - [@galathius](https://github.com/galathius).
* Your contribution here.

## 3.3.2 (11/26/2014)
Expand Down
28 changes: 16 additions & 12 deletions lib/hashie/extensions/deep_merge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,32 @@ module Hashie
module Extensions
module DeepMerge
# Returns a new hash with +self+ and +other_hash+ merged recursively.
def deep_merge(other_hash)
dup.deep_merge!(other_hash)
def deep_merge(other_hash, &block)
dup.deep_merge!(other_hash, &block)
end

# Returns a new hash with +self+ and +other_hash+ merged recursively.
# Modifies the receiver in place.
def deep_merge!(other_hash)
_recursive_merge(self, other_hash)
def deep_merge!(other_hash, &block)
_recursive_merge(self, other_hash, &block)
self
end

private

def _recursive_merge(hash, other_hash)
if other_hash.is_a?(::Hash) && hash.is_a?(::Hash)
other_hash.each do |k, v|
hash[k] = hash.key?(k) ? _recursive_merge(hash[k], v) : v
end
hash
else
other_hash
def _recursive_merge(hash, other_hash, &block)
other_hash.each do |k, v|
hash[k] = if hash[k].is_a?(::Hash) && v.is_a?(::Hash)
_recursive_merge(hash[k], v, &block)
else
if block_given? && hash.key?(k)
block.call(k, hash[k], v)
else
v
end
end
end
hash
end
end
end
Expand Down
35 changes: 27 additions & 8 deletions spec/hashie/extensions/deep_merge_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,35 @@ class DeepMergeHash < Hash

subject { DeepMergeHash }

let(:h1) { subject.new.merge(a: 'a', a1: 42, b: 'b', c: { c1: 'c1', c2: { a: 'b' }, c3: { d1: 'd1' } }) }
let(:h2) { { a: 1, a1: 1, c: { c1: 2, c2: 'c2', c3: { d2: 'd2' } } } }
let(:expected_hash) { { a: 1, a1: 1, b: 'b', c: { c1: 2, c2: 'c2', c3: { d1: 'd1', d2: 'd2' } } } }

it 'deep merges two hashes' do
expect(h1.deep_merge(h2)).to eq expected_hash
context 'without &block' do
let(:h1) { subject.new.merge(a: 'a', a1: 42, b: 'b', c: { c1: 'c1', c2: { a: 'b' }, c3: { d1: 'd1' } }) }
let(:h2) { { a: 1, a1: 1, c: { c1: 2, c2: 'c2', c3: { d2: 'd2' } } } }
let(:expected_hash) { { a: 1, a1: 1, b: 'b', c: { c1: 2, c2: 'c2', c3: { d1: 'd1', d2: 'd2' } } } }

it 'deep merges two hashes' do
expect(h1.deep_merge(h2)).to eq expected_hash
end

it 'deep merges another hash in place via bang method' do
h1.deep_merge!(h2)
expect(h1).to eq expected_hash
end
end

it 'deep merges another hash in place via bang method' do
h1.deep_merge!(h2)
expect(h1).to eq expected_hash
context 'with &block' do
let(:h1) { subject.new.merge(a: 100, b: 200, c: { c1: 100 }) }
let(:h2) { { b: 250, c: { c1: 200 } } }
let(:expected_hash) { { a: 100, b: 450, c: { c1: 300 } } }
let(:block) { Proc.new { |_, this_val, other_val| this_val + other_val } }

it 'deep merges two hashes' do
expect(h1.deep_merge(h2, &block)).to eq expected_hash
end

it 'deep merges another hash in place via bang method' do
h1.deep_merge!(h2, &block)
expect(h1).to eq expected_hash
end
end
end

0 comments on commit 8efa387

Please sign in to comment.