Over the next week or so I’ll be sharing Ruby idioms and flourishes that I quite like. Today I’d I’ll show a few tiny uses of splat! that make me tremble with delight.
Splat! – For Beginners
Splat! is the star (*) operator, typically used in Ruby for defining methods that take an unlimited number of arguments:
def sprintf(string, *args)
end
It can also be used to convert an array to the multiple-argument form when invoking a function:
some_ints = [1,2,3]
sprintf("%%i %%i %%i", *some_ints)
Splat! – For Wizards
Array to Hash Conversion
The best use of splat! for invoking a infinite-arity functions I’ve ever seen is the recipe for converting an array to a hash. Suppose you have an array of pairs:
array = [[key_1, value_1], [key_2, value_2], ... [key_n, value_n]]
You would like to produce from it the hash: {key1 => value1 ... }
You could inject
down the array, everybody loves inject, but there is a better way:
Hash[*array.flatten]
Amazing right? This relies on the the fact that the Hash class implements the []
(brackets) operator and behaves thusly:
Hash[key1, value1, ...] = { key1 => value1, ... }
Heads or tails?
Splat! can be used for more than just method definition and invocation. My personal favorite use is destructuring assignment. I read this in Active Record’s source code recently:
def sanitize_sql_array(ary)
statement, *values = ary
...
end
This is invoked when you do something like User.find(:all, :conditions => ['first_name = ? and last_name = ?', 'nick', 'kallen'])
. Splat! is used here is to get the head and tail of the conditions array. Of course, you could use always use shift
, but the functional style used here is quite beautiful. Consider another example:
first, second, *rest = ary
One final trivium (#to_splat
aka #to_ary
)
You can actually customize the behavior of the splat operator. In Ruby 1.8, implement #to_ary
and in 1.9 it’s #to_splat
. For example
class Foo
def to_ary
[1,2,3]
end
end
a, *b = Foo.new
a # => 1
b # => [2,3]
This also works for method invocation:
some_method(*Foo.new) == some_method(1,2,3)
When I first learned this at RubyConf I thought this was mind-blowing. I have since never used it.
About the Author