Add block to Extensions::DeepMerge
This commit is contained in:
parent
337a980e35
commit
2846b3e623
|
@ -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 Extensions::DeepMerge - [@galathius](https://github.com/galathius).
|
||||
* Your contribution here.
|
||||
|
||||
## 3.3.2 (11/26/2014)
|
||||
|
|
15
README.md
15
README.md
|
@ -230,6 +230,21 @@ h1.deep_merge(h2) # => { x: { y: [7, 8, 9] }, z: "xyz" }
|
|||
h2.deep_merge(h1) # => { x: { y: [4, 5, 6] }, z: [7, 8, 9] }
|
||||
```
|
||||
|
||||
Like with Hash#merge in the standard library, a block can be provided to merge values:
|
||||
|
||||
```ruby
|
||||
class MyHash < Hash
|
||||
include Hashie::Extensions::DeepMerge
|
||||
end
|
||||
|
||||
h1 = MyHash[{ a: 100, b: 200, c: { c1: 100 } }]
|
||||
h2 = MyHash[{ b: 250, c: { c1: 200 } }]
|
||||
|
||||
h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
|
||||
# => { a: 100, b: 450, c: { c1: 300 } }
|
||||
```
|
||||
|
||||
|
||||
### DeepFetch
|
||||
|
||||
This extension can be mixed in to provide for safe and concise retrieval of deeply nested hash values. In the event that the requested key does not exist a block can be provided and its value will be returned.
|
||||
|
|
|
@ -2,28 +2,33 @@ 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)
|
||||
return self unless other_hash.is_a?(::Hash)
|
||||
_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.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash)
|
||||
_recursive_merge(hash[k], v, &block)
|
||||
else
|
||||
if hash.key?(k) && block_given?
|
||||
block.call(k, hash[k], v)
|
||||
else
|
||||
v
|
||||
end
|
||||
end
|
||||
end
|
||||
hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,16 +7,39 @@ describe Hashie::Extensions::DeepMerge do
|
|||
|
||||
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
|
||||
it 'should return initial hash for arguments that are not hash' do
|
||||
hash = subject.new.merge(a: 'a')
|
||||
expect(hash.deep_merge('abc')).to eq(hash)
|
||||
end
|
||||
|
||||
it 'deep merges another hash in place via bang method' do
|
||||
h1.deep_merge!(h2)
|
||||
expect(h1).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
|
||||
|
||||
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 { |_, 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
|
||||
|
|
Loading…
Reference in New Issue