THE RUBY SPLAT

In Ruby, there are many ways to construct an array. If defined, calling #to_a on an object will return an array of that object. Place a bare list of objects that respond to #to_a method inside square brackets and you‘ve got an array thanks to the literal array constructor.

1, 2, 3, 4, 5

[1, 2, 3, 4, 5]

For the opposite effect, enter Ruby’s splat, commonly known as “star” or (my personal favorite) the “unarray”.

[*[3, 4], *[5, 6]]
=> [3, 4, 5, 6]

dogs = [“fido”, “rover”, “dixie”]
[dogs] => [[“fido”, “rover”, “dixie”]]
[*dogs] => [“fido”, “rover”, “dixie”]

In this example, an array of dog names is set to the variable dogs. When wrapped in square brackets, dogs becomes a nested array. To take it a step further, we can splat our dogs array and send it as a single argument to a method call. Watch as splat unwraps the array of dogs:

def all_dogs(*dogs)
puts dogs
end
all_dogs(*dogs)
fido
rover
dixie

Pretty nifty!

Splat does this by simply calling to_a on the object(s) if defined. Objects of classes Array or Hash will respond to splat. Objects belonging to classes without to_a defined (String, Fixnum, FalseClass, etc.) will remain unchanged.

Think of splat as a sort of sponge, a catch-all, whose job is to absorb any “extra” arguments. Note: Ruby will assign all “un-splatted” arguments first, leaving any strays to our splat sponge:

x, *y = [1, 2, 3, 4]
x => 1
y => [2, 3, 4]

Splat can be used anywhere in the arguments list. Assignment delegation is based on splat’s placement in the list, however:

*a, b, c, d = [1, 2, 3]

a => []
b => 1
c => 2
d => 3

The three elements in the above array are first assigned to variables b, c and d respectively, leaving nothing for *a. Oh, and to those of you chomping at the bit to splat everything to pieces, usage is limited to once per list!

a, *b, *c = [1, 2, 3, 4, 5]
=>
syntax error, unexpected *

Also, take care when using splat with optional arguments as Ruby cannot determine which of the two (splatted args or default args) should have priority. Both are, after all, somewhat defaulty. Thus, the following method definition is a no-go:

def wont_work(name, *args, optional=nil)
#...some code
end