Keyword Arguments in Ruby 2.0

I’m putting together a Ruby 2.0 talk for a local Ruby meetup group and I thought it wouldn’t hurt to write down what I have learned about Keyword Arguments which is a new feature in Ruby 2.0.

Lets start with some pseudo code:

1
2
3
4
5
def link_to(name, url_options = {}, html_options = {})
  puts "name = #{name}"
  puts "url_options = #{url_options}"
  puts "html_options = #{html_options}"
end

Pain points when using multiple hashes for arguments are a) if you just want to specify html_options you need to remember at what position it was and b) in the example above you need to set url_options to either {}, nil or something else just to get to html_options:

1
2
3
4
link_to("Home", {}, :class => "active")
# name = Home
# url_options = {}
# html_options = {:class=>"active"}

Keyword Arguments to the rescue!

1
2
3
4
5
def link_to(name, url_options: {}, html_options: {})
  puts "name = #{name}"
  puts "url_options = #{url_options}"
  puts "html_options = #{html_options}"
end

url_options: {} and html_options: {} looks like Ruby 1.9 Hash syntax. Here’s how you would specify only html_options:

1
2
3
4
link_to("Home", :html_options => { :class => "active" })
# name = Home
# url_options = {}
# html_options = {:class=>"active"}

This may seem like it just makes you type more characters but think about previously mentioned pain points. You no longer need to be concerned about argument position and you don’t need to care about url_options because it gets set to {} by default.

Speaking about defaults, you have to set default value for each keyword argument or you could use **whatever_variable_name at the end (note double **) of method definition which will capture the rest of key/value pairs:

1
2
3
4
5
6
7
8
9
10
def link_to(name, url_options: {}, **other_options)
  puts "name = #{name}"
  puts "url_options = #{url_options}"
  puts "other_options = #{other_options}"
end

link_to("Home", :class => "active", :url_options => { :clickable => false })
# name = Home
# url_options = {:clickable=>false}
# other_options = {:class=>"active"}

Notice how I’m ignoring argument position and specifying url_options last but it still assigns everything correctly. Pretty neat, right?

One more nice thing – you can use another method (of same object) to set default value and you can even reuse previous arguments. Here’s a trivial example just to showcase how it works:

1
2
3
4
5
6
7
8
9
10
11
12
def temperature(celsius, fahrenheit: to_fahrenheit(celsius))
  puts "#{celsius}°C"
  puts "#{fahrenheit}°F"
end
 
def to_fahrenheit(celsius)
  celsius * 9 / 5 + 32
end
 
temperature(36)
# 36°C
# 96°F

So there you go. I like this feature and I’m pretty sure it will be used quite a lot once Ruby 2.0 gets adopted by more developers.

Comments