
The Splat Operator
Suppose you want a method to have arguments and you want to accept a varying number of them. Ruby has a special syntax to account for this case. It is called the splat operator and is denoted as *. Actually, this is called the single splat operator. Since Ruby 2.0, there is also a double splat operator, **. Let's take a look at both of these.
The Single Splat (*) Operator
The single splat operator, *, is actually a way to work with arrays. Remember from earlier that Ruby really implements arguments as arrays behind the scenes? The splat operator allows us to build arrays together into a single variable or to splat them out into multiple variables. One of the main uses of the splat operator is to use it as a catch-all method argument. In other words, you can pass multiple arguments to a method call, and if the method signature defines an argument with the splat operator, it will combine all those arguments into the one variable.
Consider the following example:
def method_with_any_number_of_args(*args)
puts args.class
puts args
end
In this method signature, we have a single argument called args, which is denoted by the splat operator. This tells Ruby that the method can be called with any number of arguments and to splat them into a variable as an array.
It's not very common to use this form of method signature. Using this form requires more code to parse the array for specific arguments and can lend the code to be more error-prone and hard to debug. It's also not clear by reading the method signature what types of arguments the method can handle.
That said, knowing the splat operator exists and how it works can come in handy. We'll learn in the final chapter about a special Ruby method called method_missing, which uses the splat operator. In brief, this method is called by Ruby on an object when the object receives a message (method) that is not defined.
Let's take a look at some uses of the splat operator:
method_with_any_number_of_args(5, "asdf", [1,2,3])
Here, we pass three arguments of varying types and all arguments are put into the args variable as an array that can be further processed.
A useful usage of the splat operator is to assemble arguments as an array, and then to splat them out as arguments:
args = []
args << 5
args << "asdf"
args << [1,2,3]
method_with_any_number_of_args(*args)
We can also use the splat operator to send our assembled arguments, even if the method signature has traditional positional arguments:
def foo(arg1, arg2)
puts arg1, arg2
end
args = [1,2]
foo(*args)
The Double Splat (**) Operator
The double splat operator arrived with Ruby 2.0 and pairs with its keyword arguments. Whereas the single splat operator can be used for splatting positional arguments into a single argument, the double splat operator is used for splatting keyword arguments into a single argument.
Let's take look at a method with keyword arguments:
def log_message(message:, time: Time.now)
return "[#{time}] #{message}"
end
log_message(message: "This is the message to log")
The output should be as follows:

Figure 4.14: Output with keyword arguments
Now let's implement the same method with the double splat operator:
def log_message(**params)
puts params.inspect
end
log_message(message: "This is the message to log", time: Time.now)
The output should be as follows:

Figure 4.15: Using the double splat operator
Let's perform an exercise in which we will implement the splat operator.
Exercise 4.02: Creating a Method to Take Any Number of Parameters
In this exercise, we will write a method that emulates an API client that can take any number of parameters. Additionally, we will call the method using the single splat operator.
A common idiom is to assemble arguments in this way if there are conditions determining which arguments to pass to the method. Let's take a look at an example using an API client that makes a web request. The web request method can take any number of arguments:
- Open the IDE and create a new file. First, we need to create a method that implements a method called get_data and takes the url, headers, and params variables, which use the splat operator:
def get_data(url, headers = {}, *params)
puts "Calling #{url}"
if headers.length > 0
puts "Headers: #{headers}"
else
puts "No headers"
end
params.each do |param|
puts "Found param: #{param}"
end
end
- Write a method that assembles parameters into an array:
def assemble_params(include_headers = false, include_date_in_search = false, only_show_my_records = true)
headers = {accept: "application/json"}
url = "https://exampleapi.com"
args = [url]
args << headers if include_headers
params = []
params << "date=#{Time.now}" if include_date_in_search
params << "myrecords=true" if only_show_my_records
args << params if params.length > 0
end
- Call methods with different values using the splat operator:
get_data(*assemble_params)
get_data(*assemble_params(true))
get_data(*assemble_params(false, true, false))
The output should be as follows:
Figure 4.16: Output of the method taking multiple parameters
We have written a method that emulates an API client that can take any number of parameters.