πŸŽ“ 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.