Akshay Khot
Posted on April 27, 2022
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'
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'
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
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
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.
Posted on April 27, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024