Chris Zetter

Keyword Arguments in Ruby 2.0

One of the new features of Ruby 2.0 are keyword arguments.

Keyword arguments make it easier to create methods that take optional named arguments. You can now do this:

def exclaim(text, exclamation: '!', number: 7)
  text + exclamation * number
end

exclaim('hello', number: 4) #=> 'hello!!!!'

# equivalent:
exclaim('hello', {:number => 4}) #=> 'hello!!!!'

Keyword arguments in the method definition must be symbols given in the new-style hash syntax, but in the method call you may use the old-style hash syntax.

Compare this to the current common pattern of using a hash to represent options:

def old_exclaim(text, options = {})
  exclamation = options[:exclamation] || '!'
  number = options[:number] || 7

  text + exclamation * number
end

Take care when refactoring old hash-style arguments to the new keyword arguments, while in most cases only the method definition needs to change, the new syntax will raise an ArgumentError when you call it with an argument that isn’t defined in the method signature. This will prevent spelling mistakes that would otherwise cause the call to succeed with a incorrect set of arguments.

exclaim('hello', start_exclamation: '¡')  #=> raises: unknown keyword: start_exclamation (ArgumentError)

You can stop an ArgumentError being raised and deal with arbitrary keyword arguments by using a double-splat (double asterisk) to capture all keywords not already assigned and puts them in a hash:

def keyword_test(matched: '1', **additional_arguments)
  return additional_arguments
end

keyword_test(matched: 1, unmatched: 2) #=> {unmatched: 2}

As well as less lines of boiler-plate code, another win of using keyword arguments is that it avoids the false trap common when dealing with option hashes- when you default an argument you must do so on it’s presence, not on it’s truthiness otherwise you will never be able to set an argument to false:

options = {to_uppercase:  false}

# incorrect (always overriding nil and false):
options[:to_uppercase] || true # => true

# correct (allowing nil and false):
options.fetch(:to_uppercase, true) # => false

So the result is a useful pattern that replaces a more verbose and error prone one. Just remember: don’t refactor for the sake of it. Using keywords arguments will mean your code can’t be used with Ruby 1.9.x anymore and could cause API breaks if users are calling methods with unexpected options.

Update: Required keyword arguments in Ruby 2.1

Ruby 2.1 introduces required keyword arguments. You can use required argument by skipping the default value. You’ll get a ArgumentError if you don’t supply the argument:

def exclaim(text, exclamation: '!', number:)
  text + exclamation * number
end

exclaim('Yo', number: 5) # => 'Yo!!!!!'
exclaim('Yo') # raises: ArgumentError: missing keyword: number

More about Ruby 2.0

For more reading about Ruby 2.0 I recommend reading:

Read more by me, follow me on twitter or subscribe.