Ruby Enumerable with underlying Hash

282 views Asked by At

I have a class that uses Enumerable and Forwardable mixins. The things is that even though #each has been implemented (or delegated), #member? (which also comes with Enumerable) is not working properly.

require "forwardable"
class RestrictedHash
  include Enumerable
  extend Forwardable

  def_delegators :@hash, :[], :[]=, :each

  def initialize
    @hash = {}
  end
end

r_h = RestrictedHash.new
r_h[:a] = []
r_h.member?(:a)       #=> false
r_h.member?(:a, [])   #=> Wrong number of arguments (2 for 1)
r_h.member?([:a, []]) #=> true

h = {}
h[:a] = []
h.member?(:a)         #=> true
h.member?([:a, []])   #=> false

Any ideas of why I am getting this difference in behavior?

1

There are 1 answers

3
mikej On BEST ANSWER

The reason for this is that the each method on a Hash yields pairs of key and value so for your example @hash:

irb(main):001:0> h = {}
=> {}
irb(main):002:0> h[:a] = []
=> []
irb(main):003:0> h.each { |i| puts i.inspect }
[:a, []]

This means that when the implementation of member? in Enumerable uses each to check if the value specified is a member it will successfully find ([:a, []] but not the key :a on its own.

In the Hash class itself member? is implemented to call rb_hash_has_key.