hashie/hashie

Hashie::Mash and Keyword arguments doesn't work as hashes

Bhacaz opened this issue · 4 comments

I was expecting that a Hashie::Mash object act like an Hash when passing it to a function which define keyword arguments.

def test(hello:)
    puts hello
end

h = Hashie::Mash.new(hello: 'world') # => #<Hashie::Mash hello="world">

test(h) # => ArgumentError: wrong number of arguments (given 1, expected 0)

# Work around
test(h.to_h.symbolize_keys) # => world

Mash stores its keys internally as strings because Symbols used to not be garbage collected. That means the keys are not going to match against keyword arguments by default since keyword arguments are Symbols.

You can use the SymbolizeKeys extension make your Mash work with keyword arguments, as seen below:

[1] pry(main)> def test(hello:)
[1] pry(main)*   puts hello
[1] pry(main)* end
=> :test
[2] pry(main)> class MyMash < Hashie::Mash
[2] pry(main)*   include Hashie::Extensions::Mash::SymbolizeKeys
[2] pry(main)* end
=> MyMash
[3] pry(main)> test(MyMash.new(hello: 'world'))
world

We should probably document this. Would you be interested in submitting a short PR to document this gotcha?

The garbage collection problem was fixed in MRI 2.2, so maybe we can go even further and store things "as is"?

The "as is" storage causes a ~30% performance hit, which we talked about here. We also have the KeepOriginalKeys extension to add that behavior if you don't mind the performance hit.

I don't think a 30% performance hit is something I want to introduce in the main Mash, what do you think?

Right on @michaelherold.