π The ...
operator
Passing arguments from one method to another is usually a bit of a faff.
Imagine
This is a very contrived example, but, we have a readable_name
method that, for reasons, accepts a name
and a title
argument, as well as uses a block π€·ββοΈ. We use such a method like so
readable_name("John Smith", prefix: "Mr") do |name|
name.upcase!
end
and the method is defined like so
def readable_name(name, prefix:, &block)
readable_name = [prefix, name].join(" ")
if block_given?
yield readable_name
end
readable_name
end
Problem
Time passes on our super useful app and one day, after this readable_name
method is used everywhere, a decision is made to rename it to something else π².
We canβt find and replace the method because that would defeat the purpose of this long-winded example, so we choose to delegate the new human_name
method name to our readable_name
method.
Solution
The solution can be explained by looking at the implementation for different Ruby versions
Ruby < 2.7
def human_name(*args, &block)
readable_name(*args, &block)
end
def readable_name(name, prefix:, &block)
readable_name = [prefix, name].join(" ")
if block_given?
yield readable_name
end
readable_name
end
Ruby 3+
def human_name(*args, **kwargs, &block)
readable_name(*args, **kwargs, &block)
end
def readable_name(name, prefix:, &block)
readable_name = [prefix, name].join(" ")
if block_given?
yield readable_name
end
readable_name
end
Ruby 2.7+
def human_name(...)
readable_name(...)
end
def readable_name(name, prefix:, &block)
readable_name = [prefix, name].join(" ")
if block_given?
yield readable_name
end
readable_name
end
Sum Up
We have 3 different ways to pass the arguments when delegating.
I prefer the Ruby 2.7+ syntax. It highlights that the human_name
method is boring and directs the attention to the readable_name
method. The Ruby 3+ syntax is noisy, making it less obvious which direction to focus.