Splats and tuples

A method can receive a variable number of arguments by using a splat (*), which can appear only once and in any position:

  1. def sum(*elements)
  2. total = 0
  3. elements.each do |value|
  4. total += value
  5. end
  6. total
  7. end
  8. sum 1, 2, 3 #=> 6
  9. sum 1, 2, 3, 4.5 #=> 10.5

The passed arguments become a Tuple in the method’s body:

  1. # elements is Tuple(Int32, Int32, Int32)
  2. sum 1, 2, 3
  3. # elements is Tuple(Int32, Int32, Int32, Float64)
  4. sum 1, 2, 3, 4.5

Arguments past the splat argument can only be passed as named arguments:

  1. def sum(*elements, initial = 0)
  2. total = initial
  3. elements.each do |value|
  4. total += value
  5. end
  6. total
  7. end
  8. sum 1, 2, 3 # => 6
  9. sum 1, 2, 3, initial: 10 # => 16

Arguments past the splat method without a default value are required named arguments:

  1. def sum(*elements, initial)
  2. total = initial
  3. elements.each do |value|
  4. total += value
  5. end
  6. total
  7. end
  8. sum 1, 2, 3 # Error, missing argument: initial
  9. sum 1, 2, 3, initial: 10 # => 16

Two methods with different required named arguments overload between each other:

  1. def foo(*elements, x)
  2. 1
  3. end
  4. def foo(*elements, y)
  5. 2
  6. end
  7. foo x: "something" # => 1
  8. foo y: "something" # => 2

The splat argument can also be left unnamed, with the meaning “after this, named arguments follow”:

  1. def foo(x, y, *, z)
  2. end
  3. foo 1, 2, 3 # Error, wrong number of arguments (given 3, expected 2)
  4. foo 1, 2 # Error, missing argument: z
  5. foo 1, 2, z: 3 # OK

Splatting a tuple

A Tuple can be splat into a method call by using *:

  1. def foo(x, y)
  2. x + y
  3. end
  4. tuple = {1, 2}
  5. foo *tuple # => 3

Double splats and named tuples

A double splat (**) captures named arguments that were not matched by other arguments. The type of the argument is a NamedTuple:

  1. def foo(x, **other)
  2. # Return the captured named arguments as a NamedTuple
  3. other
  4. end
  5. foo 1, y: 2, z: 3 # => {y: 2, z: 3}
  6. foo y: 2, x: 1, z: 3 # => {y: 2, z: 3}

Double splatting a named tuple

A NamedTuple can be splat into a method call by using **:

  1. def foo(x, y)
  2. x - y
  3. end
  4. tuple = {y: 3, x: 10}
  5. foo **tuple # => 7