sellarafaeli
sellarafaeli

Reputation: 1177

How can I override Hash native brackets ([] access)

I want to override the Hash class native brackets in ruby.

Note I don't want to override them in a class that inherits from Hash (no subclassing), I want to actually override Hash itself, such that any hash anywhere will always inherit my behavior.

Specifically (bonus points for..) - I want this in order to natively emulate a hash with indifferent access. In JavaScript I would modify the prototype, Ruby is known for its metaprogramming, so I hope this is possible.

So what I am aiming for is:

>> # what do I do here to overload Hash's []?...
>> x = {a:123} # x is a native Hash
>> x[:a] # == 123, as usual
>> x['a'] # == 123, hooray!

I've tried: 1)

class Hash
  define_method(:[]) { |other| puts "Hi, "; puts other }
end

and

class Hash
  def []
    puts 'bar'
  end
end

Both crash irb.

Upvotes: 7

Views: 3524

Answers (3)

Michael K Madison
Michael K Madison

Reputation: 2209

If using Rails HashWithIndifferentAccess supports this functionality already, even if using Ruby you can weigh including Active Support to have this functionality.

Upvotes: 0

sellarafaeli
sellarafaeli

Reputation: 1177

This seems to get the job done.

class Hash
  def [](key)
    value = (fetch key, nil) || (fetch key.to_s, nil) || (fetch key.to_sym, nil)     
  end

  def []=(key,val)
    if (key.is_a? String) || (key.is_a? Symbol) #clear if setting str/sym
        self.delete key.to_sym
        self.delete key.to_s        
    end
    merge!({key => val})
  end
end

And now:

user = {name: 'Joe', 'age' => 20} #literal hash with both symbols and strings as keys
user['name'] == 'Joe' # cool!
user[:age] == 20      # cool!

For more details see: http://www.sellarafaeli.com/blog/ruby_monkeypatching_friendly_hashes

Upvotes: 8

Boris Stitnicky
Boris Stitnicky

Reputation: 12578

class Hash
  def [] key
    value = fetch key rescue
    case key
    when Symbol then "#{value}, as usual"
    when String then "#{value}, hooray!"
    else value end
  end
end

Upvotes: 3

Related Questions