DEV Community

Akshay Khot
Akshay Khot

Posted on • Originally published at akshaykhot.com

How to Access Hash Values Like Methods in Ruby

In Ruby, if you want to access hash values like methods on an object, use ActiveSupport::OrderedOptions. This class inherits from Hash and provides dynamic accessor methods.

Typically, you'd do this with a Hash.

person = {
    name: "Jason",
    company: "Basecamp"
}

person[:company] # 'Basecamp'
Enter fullscreen mode Exit fullscreen mode

Using OrderedOptions, you can write

require "active_support/ordered_options"

person = ActiveSupport::OrderedOptions.new

# set the values
person.name = "Jason"
person.company = "Basecamp"

# access the values
person.name  # => 'Jason'
person.company # => 'Basecamp'
Enter fullscreen mode Exit fullscreen mode

Implementation

Behind the scenes, Rails implements this feature using metaprogramming in Ruby. It uses the method_missing method to handle the method call.

def method_missing(name, *args)
  name_string = +name.to_s
  if name_string.chomp!("=")
    self[name_string] = args.first   # set the value
  else
    bangs = name_string.chomp!("!")

    # get the value
    if bangs
      self[name_string].presence || raise(KeyError.new(":#{name_string} is blank"))
    else
      self[name_string]
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

You can read the complete source code here. For more details on metaprogramming in Ruby, read my notes of the Metaprogramming Ruby 2 book.

Real-World Usage

Propshaft is an asset pipeline library for Rails. It uses OrderedOptions to define the config.assets settings, instead of creating a new configuration object. You can read the complete source on Github.

class Railtie < ::Rails::Railtie
    config.assets = ActiveSupport::OrderedOptions.new

    config.assets.paths          = []
    config.assets.excluded_paths = []
    config.assets.version        = "1"
    config.assets.prefix         = "/assets"
end
Enter fullscreen mode Exit fullscreen mode

Now, this doesn't mean you have to replace all your hashes with instances of OrderedOptions. It's better to use them with configuration-like objects, which often results in more readable code.

Hope that helps. Let me know what you think about this approach.

Top comments (2)

Collapse
 
jeremyf profile image
Jeremy Friesen

I wasn't aware of this class; thank you for sharing. In the past I'd used (and removed) OpenStruct.

Collapse
 
software_writer profile image
Akshay Khot

Thanks, Leonid!