Ruby 2.0 introduced support for keyword arguments.

If you’re already familiar with keyword arguments, feel free to skip to the next bit!

Keyword arguments

Keyword arguments give you a convenient shorthand for using hashes as an argument to a method. So something like the following:

def foo ( args ) raise ArgumentError , "missing keyword: key" unless args [ :key ] if ( unknowns = args . keys . select { | key | key != :key }) . any? raise ArgumentError , "unknown keywords: #{ unknowns . join ( ", " ) } " end key = args [ :key ] key end foo ( key : "value" ) # => "value" foo ({}) # ArgumentError: missing keyword: key foo ( other_key : "other_value" ) # ArgumentError: missing keyword: key foo ( key : "value" , other_key : "other_value" ) # ArgumentError: unknown keywords: other_key def bar ( args = {}) value = args . fetch ( :key , "default_value" ) if ( unknowns = args . keys . select { | key | key != :key }) . any? raise ArgumentError , "unknown keywords: #{ unknowns . join ( ", " ) } " end value end bar ( key : "value" ) # => "value" bar ({}) # => "default_value" bar ( other_key : "other_value" ) # ArgumentError: unknown keywords: other_key bar ( key : "value" , other_key : "other_value" ) # ArgumentError: unknown keywords: other_key

Can now be written like this:

def foo ( key :) key end foo ( key : "value" ) # => "value" foo ({}) # ArgumentError: missing keyword: key foo ( other_key : "other_value" ) # ArgumentError: missing keyword: key foo ( key : "value" , other_key : "other_value" ) # ArgumentError: unknown keyword: other_key def bar ( key : "default_value" ) key end bar ( key : "value" ) # => "value" bar ({}) # => "default_value" bar ( other_key : "other_value" ) # ArgumentError: unknown keyword: other_key bar ( key : "value" , other_key : "other_value" ) # ArgumentError: unknown keyword: other_key

Double splat!

There is a new operator, the double splat, that is sort of the splat for keyword arguments. This is most easily explained in yet another “before and after” example.

Ruby 1.9:

def foo ( args ) raise ArgumentError , "missing keyword: key" unless args [ :key ] key = args [ :key ] everything_else = args . delete_if { | k , _ | k == :key } [ key , everything_else ] end foo ( key : "value" , other_key : "other_value" ) # => ["value", {:other_key=>"other_value"}]

Ruby 2.0:

def foo ( key :, ** everything_else ) [ key , everything_else ] end foo ( key : "value" , other_key : "other_value" ) # => ["value", {:other_key=>"other_value"}]

Pretty cute!

**_, the starsnake

But what if I want to use the new shorthand syntax without raising an error on any extra unused keys? In code:

def foo ( args ) raise ArgumentError , "missing keyword: key" unless args [ :key ] # if (unknowns = args.keys.select { |key| key != :key }).any? # raise ArgumentError, "unknown keywords: #{unknowns.join(", ")}" # end key = args [ :key ] key end foo ( key : "value" ) # => "value" foo ( key : "value" , other_key : "other_value" ) # => "value"

Introducing, the starsnake **_ (sorry, couldn’t come up with a good name).

def foo ( key :, ** _ ) key end foo ( key : "value" ) # => "value" foo ( key : "value" , other_key : "other_value" ) # => "value"

If you don’t know about Ruby’s magic underscore (a syntax borrowed from Perl) you can read about it here. Basically, _ is Ruby’s variable name for storing values you don’t need.

There may be some debate as to whether having a triple symbol expression or allowing arbitrary keys into your method is actually a good idea, but that’s outside the scope of this post. ;)