As stated by the other answers, the *
operator is used to turn an array into an argument list.
But what if the object is not an array, as in your case? Then Ruby will call #to_a
on the object, if defined, and use the returned array instead. Otherwise, the object itself is used.
Here's the case where the object is neither an array nor does it define #to_a
:
x = *4 # => [4]
If the object defines #to_a
, it will be called and used, as in the case of Range
:
x = *0..1 # => [0, 1]
To prove this, we can prepend a module to trace the call to #to_a
:
module Trace
def to_a
puts "#to_a called"
super
end
end
Range.prepend(Trace)
x = *0..1
# prints "#to_a called"
# => [0, 1]
Note that Ruby will not call #to_a
if your object already is of type Array
.
We can use this on our custom types as well:
class Foo
def to_a
[1, 2, 3]
end
end
x = *Foo.new # => [1, 2, 3]
By the way, Ruby's nil
also implements #to_a
. This allows us to pass nil
as an argument as if nothing was passed, because nil.to_a
returns []
:
def count(*args)
args.count
end
count # => 0
count(*0..1) # => 2
count(*nil) # => 0
This can be useful when you have a variable that could be nil
that you pass to a method which has a default value:
def say_hi(name = "Jane")
puts "Hi, #{name}"
end
name = nil
say_hi(*name) # prints "Hi, Jane"
But if we remove NilClass#to_a
:
NilClass.undef_method(:to_a)
say_hi(*name) # prints "Hi, "