-
Notifications
You must be signed in to change notification settings - Fork 313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed #303 (deep_merge/stringify_keys/symbolize_keys not working via hash.extend(…)) #304
Conversation
Hmm ... I've thought about it a little bit and I came to a conclusion. I think duck-checking for this would be more appropriate, since ActiveSupport and the deep_merge gem, as well as others provide functionality like Duck-checking also makes it a little more readable than checking the singleton class of the object: copy = dup
copy.extend(Hashie::Extensions::DeepMerge) unless copy.respond_to?(:deep_merge!)
copy.deep_merge!(other_hash, &block) Does anyone else have thoughts on the matter? Also, this needs a change log entry and some style cleanup (per Rubocop) before we can merge it. |
@michaelherold But the dup'ed object either already has a deep_merge method (when included in it's class – in which case one would rather use the existing method instead of explicitly extending that one object) or does not get one at all (because it's a newly created object of the original objects class). So both checks are effectively equal to each other. |
They're not quite equivalent to each other. If our DeepMerge extension is unthinkingly placed on an object that already knows how to deep merge, then I think the question becomes: what do we want the behavior of our mixins to be when they are extended onto an object that already has those methods? Option 1: always use our implementation. Option 2: use the object's pre-existing implementation, if available. This behavior can be show with this little proof-of-concept: class BaseClass
def my_method
puts 'base class bare method'
end
def my_method!
puts 'base class bang method'
end
end
module DuckCheckingExtension
def my_method
copy = dup
copy.extend(DuckCheckingExtension) unless copy.respond_to?(:my_method!)
copy.my_method!
end
def my_method!
puts 'extension method'
end
end
module SingletonCheckingExtension
def my_method
copy = dup
copy.extend(SingletonCheckingExtension) unless (class << copy; self; end).included_modules.include?(SingletonCheckingExtension)
copy.my_method!
end
def my_method!
puts 'extension method'
end
end
test = BaseClass.new
test.extend(DuckCheckingExtension)
test.my_method
#=> base class bang method
test2 = BaseClass.new
test2.extend(SingletonCheckingExtension)
test2.my_method
#=> extension method The duck checking is also significantly faster on the proof-of-concept, since we're not building and checking the singleton class: require 'benchmark'
GC.disable
N = 1_000_000
Benchmark.bmbm do |x|
x.report(:duck) { N.times { test.my_method } }
x.report(:singleton) { N.times { test2.my_method } }
end
|
There're some build errors, to start. Also please squash these commits. |
…keys on extended singleton objects.
@michaelherold Do you see any issues with this? Feel free to merge if you like. |
Fixed #303 (deep_merge/stringify_keys/symbolize_keys not working via hash.extend(…))
Thanks a bunch! 🙇 |
## 3.4.3 (10/25/2015) * [#314](hashie/hashie#314): Added a `StrictKeyAccess` extension that will raise an error whenever a key is accessed that does not exist in the hash - [@pboling](https://github.com/pboling). * [#304](hashie/hashie#304): Ensured compatibility of `Hash` extensions with singleton objects - [@regexident](https://github.com/regexident). * [#306](hashie/hashie#306): Added `Hashie::Extensions::Dash::Coercion` - [@marshall-lee](https://github.com/marshall-lee). * [#310](hashie/hashie#310): Fixed `Hashie::Extensions::SafeAssignment` bug with private methods - [@marshall-lee](https://github.com/marshall-lee). * [#313](hashie/hashie#313): Restrict pending spec to only Ruby versions 2.2.0-2.2.2 - [@pboling](https://github.com/pboling). * [#315](hashie/hashie#315): Default `bin/` scripts: `console` and `setup` - [@pboling](https://github.com/pboling).
Fixes issue #303