Skip to content

Commit

Permalink
Merge pull request #304 from regexident/master
Browse files Browse the repository at this point in the history
Fixed #303 (deep_merge/stringify_keys/symbolize_keys not working via hash.extend(…))
  • Loading branch information
michaelherold committed Jun 10, 2015
2 parents b7405dc + 489309a commit edeef56
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
@@ -1,6 +1,7 @@
## Next Release

* Your contribution here.
* [#304](https://github.com/intridea/hashie/pull/304): Ensured compatibility of `Hash` extensions with singleton objects - [@regexident](https://github.com/regexident).

## 3.4.2 (6/2/2015)

Expand Down
4 changes: 3 additions & 1 deletion lib/hashie/extensions/deep_merge.rb
Expand Up @@ -3,7 +3,9 @@ module Extensions
module DeepMerge
# Returns a new hash with +self+ and +other_hash+ merged recursively.
def deep_merge(other_hash, &block)
dup.deep_merge!(other_hash, &block)
copy = dup
copy.extend(Hashie::Extensions::DeepMerge) unless copy.respond_to?(:deep_merge!)
copy.deep_merge!(other_hash, &block)
end

# Returns a new hash with +self+ and +other_hash+ merged recursively.
Expand Down
11 changes: 7 additions & 4 deletions lib/hashie/extensions/stringify_keys.rb
Expand Up @@ -15,7 +15,7 @@ def stringify_keys!
# Return a new hash with all keys converted
# to strings.
def stringify_keys
dup.stringify_keys!
StringifyKeys.stringify_keys(self)
end

module ClassMethods
Expand All @@ -25,7 +25,7 @@ module ClassMethods
def stringify_keys_recursively!(object)
case object
when self.class
object.stringify_keys!
stringify_keys!(object)
when ::Array
object.each do |i|
stringify_keys_recursively!(i)
Expand All @@ -43,6 +43,7 @@ def stringify_keys_recursively!(object)
# test.stringify_keys!
# test # => {'abc' => 'def'}
def stringify_keys!(hash)
hash.extend(Hashie::Extensions::StringifyKeys) unless hash.respond_to?(:stringify_keys!)
hash.keys.each do |k|
stringify_keys_recursively!(hash[k])
hash[k.to_s] = hash.delete(k)
Expand All @@ -54,8 +55,10 @@ def stringify_keys!(hash)
# to strings.
# @param [::Hash] hash
def stringify_keys(hash)
hash.dup.tap do | new_hash |
stringify_keys! new_hash
copy = hash.dup
copy.extend(Hashie::Extensions::StringifyKeys) unless copy.respond_to?(:stringify_keys!)
copy.tap do |new_hash|
stringify_keys!(new_hash)
end
end
end
Expand Down
13 changes: 8 additions & 5 deletions lib/hashie/extensions/symbolize_keys.rb
Expand Up @@ -15,17 +15,17 @@ def symbolize_keys!
# Return a new hash with all keys converted
# to symbols.
def symbolize_keys
dup.symbolize_keys!
SymbolizeKeys.symbolize_keys(self)
end

module ClassMethods
# Symbolize all keys recursively within nested
# hashes and arrays.
# @api private
def symbolize_keys_recursively!(object)
object.symbolize_keys! if object.respond_to? :symbolize_keys!

case object
when self.class
symbolize_keys!(object)
when ::Array
object.each do |i|
symbolize_keys_recursively!(i)
Expand All @@ -43,6 +43,7 @@ def symbolize_keys_recursively!(object)
# Hashie.symbolize_keys! test
# test # => {:abc => 'def'}
def symbolize_keys!(hash)
hash.extend(Hashie::Extensions::SymbolizeKeys) unless hash.respond_to?(:symbolize_keys!)
hash.keys.each do |k|
symbolize_keys_recursively!(hash[k])
hash[k.to_sym] = hash.delete(k)
Expand All @@ -54,8 +55,10 @@ def symbolize_keys!(hash)
# to symbols.
# @param [::Hash] hash
def symbolize_keys(hash)
hash.dup.tap do | new_hash |
symbolize_keys! new_hash
copy = hash.dup
copy.extend(Hashie::Extensions::SymbolizeKeys) unless copy.respond_to?(:symbolize_keys!)
copy.tap do |new_hash|
symbolize_keys!(new_hash)
end
end
end
Expand Down
20 changes: 20 additions & 0 deletions spec/hashie/extensions/deep_merge_spec.rb
Expand Up @@ -42,4 +42,24 @@ class DeepMergeHash < Hash
expect(h1).to eq expected_hash
end
end

context 'from extended object' do
subject { Hash }
let(:h1) { subject.new.merge(a: 100, c: { c1: 100 }).extend(Hashie::Extensions::DeepMerge) }
let(:h2) { { b: 250, c: { c1: 200 } } }
let(:expected_hash) { { a: 100, b: 250, c: { c1: 200 } } }

it 'does not raise error' do
expect { h1.deep_merge(h2) } .not_to raise_error
end

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
end
23 changes: 23 additions & 0 deletions spec/hashie/extensions/stringify_keys_spec.rb
Expand Up @@ -80,6 +80,29 @@ def invoke(method)
include_examples 'stringify_keys!'
end
end

context 'singleton methods' do
subject { Hash }
let(:object) { subject.new.merge(a: 1, b: { c: 2 }).extend(Hashie::Extensions::StringifyKeys) }
let(:expected_hash) { { 'a' => 1, 'b' => { 'c' => 2 } } }

describe '.stringify_keys' do
it 'does not raise error' do
expect { object.stringify_keys } .not_to raise_error
end
it 'produces expected stringified hash' do
expect(object.stringify_keys).to eq(expected_hash)
end
end
describe '.stringify_keys!' do
it 'does not raise error' do
expect { object.stringify_keys! } .not_to raise_error
end
it 'produces expected stringified hash' do
expect(object.stringify_keys!).to eq(expected_hash)
end
end
end
end

describe Hashie do
Expand Down
23 changes: 23 additions & 0 deletions spec/hashie/extensions/symbolize_keys_spec.rb
Expand Up @@ -85,6 +85,29 @@ def invoke(method)
include_examples 'symbolize_keys!'
end
end

context 'singleton methods' do
subject { Hash }
let(:object) { subject.new.merge('a' => 1, 'b' => { 'c' => 2 }).extend(Hashie::Extensions::SymbolizeKeys) }
let(:expected_hash) { { a: 1, b: { c: 2 } } }

describe '.symbolize_keys' do
it 'does not raise error' do
expect { object.symbolize_keys }.not_to raise_error
end
it 'produces expected symbolized hash' do
expect(object.symbolize_keys).to eq(expected_hash)
end
end
describe '.symbolize_keys!' do
it 'does not raise error' do
expect { object.symbolize_keys! }.not_to raise_error
end
it 'produces expected symbolized hash' do
expect(object.symbolize_keys!).to eq(expected_hash)
end
end
end
end

describe Hashie do
Expand Down

0 comments on commit edeef56

Please sign in to comment.