What are options hashes?

44,629

Solution 1

Options hash is a nice concept enabled by a feature of ruby parser. Say, you have a method with some required arguments. Also you may pass some optional arguments. Over time you may add more optional arguments or remove old ones. To keep method declaration clean and stable, you can pass all those optional arguments in a hash. Such method would look like this:

def foo(arg1, arg2, opts = {})
  opts.to_s # just return a string value of opts
end

So it has two required values and last argument with default value of hash. If you don't have any optional arguments to pass, you call it like this:

foo(1, 2) # => "{}"

If you do have something optional, you call it like this:

foo(1, 2, {truncate: true, redirect_to: '/'}) # => "{:truncate=>true, :redirect_to=>\"/\"}"

This code is so idiomatic to ruby that its parser actually allows you to omit curly braces when passing hash as a last argument to a method:

foo(1, 2, truncate: true, redirect_to: '/') # => "{:truncate=>true, :redirect_to=>\"/\"}"

If you use rails, for example, you'll see options hashes everywhere. Here, I opened just a random controller in my app:

class ProductsController < ApplicationController
  before_filter :prepare_search_params, only: :index
                                    #    ^^^^^^^^^^ options hash here

So, in short: options hash is argument of a method which is located last and has default value of {}. And you normally pass hashes to it (hence the name).

Solution 2

Options hashes are used a lot when need to pass optional arguments to method.

For example, if method has one-two optional args, you can write

def method(arg1, arg2 = nil, arg3 = nil)
  ...
end

But if you have more optional arg it's getting ugly to assign them to nil every time. Here comes the options hash which allows you to write

def method(arg1, options={})
  @arg1 = arg1
  @arg2 = options[:arg2]
  ....
  @arg15 = options[:arg15]
end

Solution 3

An options hash refers to the convention of passing options to methods using a hash ({}) like so

my_func(arg1, arg2, {:opt1 => 'foo', :opt2 => 'bar'})

The convention is for the options hash to be the last argument so that it can be made optional. E.g.

def my_func(argument1, argument2, options = {})
   ...
end

So an options hash isn't anything special. It's just an optional final argument that is a hash. Options hashes are so handy and common that the interpreter also lets you leave off the braces (this is the one "special" part about them)

my_func(arg1, arg2, :opt1 => 'foo', :opt2 => 'bar')

Combined with Ruby's Symbol hash key shortcut and optional parentheses, this can end looking really clean:

my_func arg1, arg2, opt1: 'foo', opt2: 'bar'

Solution 4

Since all these answers are correct, ruby 2 improved the support to keywords arguments.

You can define your method with the default hash params as *args, and rid the options = {}.

def foo(bar: 'initial')
  puts bar
end

foo # => 'initial'
foo(bar: 'final') # => 'final'

Required arguments: you need a colon after the key (also you need ruby 2.1)

def foo(bar:)
  puts bar
end

foo # => ArgumentError: missing keyword: bar
foo(bar: 'baz') # => 'baz'   

Optional arguments, you can set the default to nil

def foo(bar: nil, baz: 'aaa')
  puts "#{bar}:#{baz}"
end

foo # => ':aaa'
foo(baz: 'zab') # => ':zab'
foo(bar: 'rab', baz: 'zab') # => 'rab:zab'
foo(bin: 'bin') # => ArgumentError: unknown keyword: bin

Also you can use the standard positional args with this new hash parameters notation. You will find more information at this blog and at the oficial documentation.

Bonus: The refactor is easy because you can rid the options hash of your method without change the calls of it. But... this is not completely true, if you have a call with an unexpected option you will get an ArgumentError: unknown keyword: invalid_arg.

Solution 5

Reverse Merge is the best way to implement options hashes in ruby/rails:

def set_state_application(options_hash)
  options_hash.reverse_merge!(send_email: true, other_default_val: 'a') #will set defaults
  self.update_column(:status_id, VendorEnums::VendorStatus::APPLICATION)
  VendorMailer.email_application(self) if options_hash[:send_email]
  save_state
end
Share:
44,629
Admin
Author by

Admin

Updated on August 30, 2020

Comments

  • Admin
    Admin almost 4 years

    Will someone please explain options hashes? I am working through the ruby course from testfirst.org. Exercise 10 (temperature_object) requires knowledge of options hashes.