hashie/hashie

Mash's respond_to? and method call do not behave in consistently

davidstosik opened this issue · 1 comments

Here is a simple example:

mash = Hashie::Mash.new(a: 1)
mash.a
#=> 1
mash.b
#=> nil
mash.respond_to?(:b)
#=> false # but I expected true, as I just showed it responds!

This becomes an issue when I use a delegator on a Hashie::Mash object:

class Foo < SimpleDelegator
  def initialize(hash)
    super(Hashie::Mash.new(hash))
  end
end

# This class can be initiated with a simple hash:
foo = Foo.new(a: 1)

# and will also delegate method calls to the Mash object
foo.a
#=> 1

The problem arises when I try to call an undefined method: foo.b. Because Mash is able to respond nil, I was expecting Foo to respond the same, but that is not what happens!

# Expected
foo.b
#=> nil

# Actual
foo.b
# NoMethodError: undefined method `b' for #<Hashie::Mash a=1>

For consistency, I would like to suggest either of the following approaches:

1. All method calls fetch from the hash
If mash.b returns nil, then mash.respond_to?(:b) should return true.
Implementation.

2. Non-existing keys produce undefined methods
If mash.respond_to?(:b) returns false, then mash.b should raise NoMethodError.
Implementation.

I think I prefer the option 1, but it conflicts with the way log_collision? is implemented.

Good read: method_missing, Politely. (And this is a mirror of Polite Programmer talk that article mention.)

I think we would merge anything that doesn't break existing specs. Be wary of side effects!

https://code.dblock.org/2017/02/24/the-demonic-possession-of-hashie-mash.html