From 55c15e0dd5bc242c90728d1d20b334fec4f75c7a Mon Sep 17 00:00:00 2001 From: Michael Herold Date: Tue, 6 Feb 2018 20:31:39 -0600 Subject: Document Dash double-splat operator gotchas Let this be a lesson, folks: don't subclass the Hash class! For more information, see the following: https://github.com/intridea/hashie/issues/353#issuecomment-363294886 --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'README.md') diff --git a/README.md b/README.md index 60162b0..784b73b 100644 --- a/README.md +++ b/README.md @@ -695,6 +695,38 @@ p = Tricky.new('trick' => 'two') p.trick # => NoMethodError ``` +### Potential gotchas + +Because Dashes are subclasses of the built-in Ruby Hash class, the double-splat operator takes the Dash as-is without any conversion. This can lead to strange behavior when you use the double-splat operator on a Dash as the first part of a keyword list or built Hash. For example: + +```ruby +class Foo < Hashie::Dash + property :bar +end + +foo = Foo.new(bar: 'baz') #=> {:bar=>"baz"} +qux = { **foo, quux: 'corge' } #=> {:bar=> "baz", :quux=>"corge"} +qux.is_a?(Foo) #=> true +qux[:quux] +#=> raise NoMethodError, "The property 'quux' is not defined for Foo." +qux.key?(:quux) #=> true +``` + +You can work around this problem in two ways: + +1. Call `#to_h` on the resulting object to convert it into a Hash. +2. Use the double-splat operator on the Dash as the last argument in the Hash literal. This will cause the resulting object to be a Hash instead of a Dash, thereby circumventing the problem. + +```ruby +qux = { **foo, quux: 'corge' }.to_h #=> {:bar=> "baz", :quux=>"corge"} +qux.is_a?(Hash) #=> true +qux[:quux] #=> "corge" + +qux = { quux: 'corge', **foo } #=> {:quux=>"corge", :bar=> "baz"} +qux.is_a?(Hash) #=> true +qux[:quux] #=> "corge" +``` + ### Dash Extension: PropertyTranslation The `Hashie::Extensions::Dash::PropertyTranslation` mixin extends a Dash with -- cgit v1.2.1