Argument splatting
When we already have values collected in an array or hash, Ruby lets us expand them directly into a method call using * and **. * turns an array into positional arguments, while ** turns a hash into keyword arguments.
def build_url(host, path, protocol: "https", port: 443)
"#{protocol}://#{host}:#{port}#{path}"
end
segments = ["example.com", "/docs"]
options = { protocol: "http", port: 3000 }
build_url(*segments, **options)
# => "http://example.com:3000/docs"
def proxy_call(*args, **kwargs)
build_url(*args, **kwargs)
end
proxy_call("rubylang.org", "/en", port: 80)
# => "https://rubylang.org:80/en"
There is a beautiful symmetry in this syntax: the same *args and **kwargs syntax we use to capture arguments in a method definition is also used to forward them elsewhere. Useful for wrapper methods, delegation and little bits of metaprogramming.
History
Expanding positional arguments with * has been part of Ruby since its inception.
Expanding keyword arguments with ** arrived together with keyword arguments in Ruby 2.0, released in 2013.
Ruby 3.0, released on Christmas 2020, fully separated keyword arguments from positional hashes. That made splatting with ** more explicit and predictable, especially when forwarding arguments between methods.
The original argument expansion may have been inspired by Perl, which implicitly splats arrays and hashes when used in a method call, though it is worth noting that Python uses the same * and ** syntax for argument unpacking as well.
Som interesting discussion on the design of Ruby's keyword arguments can be found on the Ruby issue tracker: https://bugs.ruby-lang.org/issues/5474