Ruby and the argument collecting hash syntax

Unlike other languages, ruby does not support keyword parameters. As an alternative, we use ruby’s syntactic shorthand to pass a hash as the final argument to a method using the key => value syntax:

1some_method(first_arg, :key1 => value1, :key2 => value2)

some_method will receive a hash as its second argument with the specified key/value pairs. Unlike regular arguments, there is no way to provide default values for the individual key/value pairs (you can provide a default for the hash argument though):

1def some_method(thing, options = {})
2  #...
3end

There are a few ruby idioms for providing default options to an option hash, one of the most common is available in rails, using the core extension Hash#reverse_merge from ActiveSupport1:

1def some_method(thing, options = {})
2  options.reverse_merge!({:key1 => 'default'})
3  #...
4end

If you do not have access to ActiveSupport, you can use ruby’s Hash#merge2 as an alternative:

1def some_method(thing, options = {})
2  options = {:key1 => 'default'}.merge(options)
3  #...
4end

If that seems like too much code to be typing all the time, you can open up Hash and add a method. Careful! This is simple enough to get wrong. Here is some code3 from a very useful rails plugin:

1def default!(defaults = {})
2  defaults.each do |key, value|
3    self[key] = value if self[key].nil?
4  end
5  self
6end

This code works until you want to set a default value to nil. This can be fixed by replacing the conditional on line three with unless has_key?(key). Or you can simply rewrite this in terms of Hash#merge4:

1def default!(defaults = {})
2  replace(defaults.merge(self))
3end

1 Which builds on ruby’s Hash#merge.

2 Or merge-bang (merge!).

3 Slightly modified for readability.

4 ActiveSupport does something similar.

blog comments powered by Disqus