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:
1 some_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):
1 def some_method(thing, options = {}) 2 #... 3 end
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:
1 def some_method(thing, options = {}) 2 options.reverse_merge!({:key1 => 'default'}) 3 #... 4 end
If you do not have access to ActiveSupport, you can use ruby’s Hash#merge2 as an alternative:
1 def some_method(thing, options = {}) 2 options = {:key1 => 'default'}.merge(options) 3 #... 4 end
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:
1 def default!(defaults = {}) 2 defaults.each do |key, value| 3 self[key] = value if self[key].nil? 4 end 5 self 6 end
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 self.has_key?(key). Or you can simply rewrite this in terms of Hash#merge4:
1 def default!(defaults = {}) 2 replace(defaults.merge(self)) 3 end
1 Which builds on ruby’s Hash#merge.
2 Or merge-bang (merge!).
3 Slightly modified for readability.
4 ActiveSupport does something similar.