Ruby's Splat and Double-Splat Operators
Splat *
The splat *
operator in Ruby is used for converting array elements into individual arguments or collecting arguments into an array.
Parallel Assignment
When used in parallel assignment the variable with the splat will collect all unassigned values from the right hand side:
first, second, *rest = [1, 2, 3, 4, 5]
p first
# 1
p second
# 2
p rest
# [3, 4, 5]
first, *rest, last = 1, 2, 3, 4, 5
p first
# 1
p last
# 5
p rest
# [2, 3, 4]
Unpacking Arrays
When used with an array, each of the array elements will be treated as an individual argument (similar to Javascript’s Spread):
ids = [1, 2, 3]
new_ids = [0, *ids]
p new_ids
# [0, 1, 2, 3]
This can also be used with method calls to pass each array element as an individual argument:
class Person
def initialize(first, last)
@first, @last = first, last
end
def name
"#{@first} #{@last}"
end
end
names = ['James', 'Smith']
person = Person.new(*names)
p person.name
# "James Smith"
Variable Length Argument Lists
When used in method definitions, the method will accept an undetermined amount of arguments and collect them into an array:
class Account
attr_reader :balance
def initialize
@balance = 0
end
def deposit(*amounts)
amounts.each { |a| @balance += a }
end
end
account = Account.new
account.deposit(10)
p account.balance
# 10
account.deposit(150, 25, 23, 18)
p account.balance
# 226
Double-Splat **
The double-splat **
operator has similar behavior to the single-splat but is intended for use with hashes and keyword arguments.
Unpacking Hashes
Hashes can be “unpacked” into other hashes:
name = { first_name: 'Tim', last_name: 'Jones' }
attrs = { **name, address: '100 Main St' }
p attrs
# {:first_name=>"Tim", :last_name=>"Jones", :address=>"100 Main St"}
Variable Keyword Arguments
Methods defined with keyword arguments will raise an error if they receive any other options besides those that are defined. A way to make these methods more flexible is to use a double-splat to capture any undefined arguments passed and collect them into a hash:
def format_transaction(amount:, type:, **options)
{
amount: amount,
type: type,
options: options
}
end
trx = format_transaction(
amount: 10.40,
type: 'deposit',
client: 'Alo LLC',
ref: 'Invoice #123'
)
p trx
# {:amount=>10.4, :type=>"deposit", :options=>{:client=>"Alo LLC", :ref=>"Invoice #123"}}
Variable Length Argument Lists with Options
The double-splat can also be combined with a single-splat in method definitions to accept variable length arguments with an (optional) options hash as the last argument:
def log(*values, **options)
output = values.join(' | ')
puts [options[:service], output].compact.join(' :: ')
end
log('Firefox', 'Mac OSX', '123.131.11.1')
# Firefox | Mac OSX | 123.131.11.1
log('Firefox', 'Mac OSX', '123.131.11.1', service: 'API')
# API :: Firefox | Mac OSX | 123.131.11.1