hash['key'] to hash.key in Ruby

>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #<OpenStruct bar="baz">
>> foo_obj.bar
=> "baz"
>>

What you're looking for is called OpenStruct. It's part of the standard library.


A good solution:

class Hash
  def method_missing(method, *opts)
    m = method.to_s
    if self.has_key?(m)
      return self[m]
    elsif self.has_key?(m.to_sym)
      return self[m.to_sym]
    end
    super
  end
end

Note: this implementation has only one known bug:

x = { 'test' => 'aValue', :test => 'bar'}
x.test # => 'aValue'

If you prefer symbol lookups rather than string lookups, then swap the two 'if' condition


Rather than copy all the stuff out of the hash, you can just add some behaviour to Hash to do lookups.

If you add this defintion, you extend Hash to handle all unknown methods as hash lookups:

class Hash
  def method_missing(n)
    self[n.to_s]
  end
end

Bear in mind that this means that you won't ever see errors if you call the wrong method on hash - you'll just get whatever the corresponding hash lookup would return.

You can vastly reduce the debugging problems this can cause by only putting the method onto a specific hash - or as many hashes as you need:

a={'foo'=>5, 'goo'=>6}
def a.method_missing(n)
   self[n.to_s]
end

The other observation is that when method_missing gets called by the system, it gives you a Symbol argument. My code converted it into a String. If your hash keys aren't strings this code will never return those values - if you key by symbols instead of strings, simply substitute n for n.to_s above.


There are a few gems for this. There's my recent gem, hash_dot, and a few other gems with similar names I discovered as I released mine on RubyGems, including dot_hash.

HashDot allows dot notation syntax, while still addressing concerns about NoMethodErrors addressed by @avdi. It is faster, and more traversable than an object created with OpenStruct.

require 'hash_dot'
a = {b: {c: {d: 1}}}.to_dot
a.b.c.d => 1

require 'open_struct'
os = OpenStruct.new(a)
os.b => {c: {d: 1}}
os.b.c.d => NoMethodError

It also maintains expected behavior when non-methods are called.

a.non_method => NoMethodError

Please feel free to submit improvements or bugs to HashDot.