February 14, 2024
Anonymous Block Forwarding in Ruby
You probably have used (or at least heard about) the argument forwarding feature in Ruby, which was added in Ruby 2.7, that lets you forward all the arguments passed to a method, as they are, to another method, using the three dots ... syntax.
This includes all positional, named, and even block arguments.
def execute(action="", **options)
p action # get
p options # {:url=>"/test", :values=>[201, 202]}
yield "fake response"
end
def perform(...)
# execute receives all the arguments
# received by the perform function
execute(...)
end
perform action="get", url: "/test", values: [201, 202] do |result|
p result # "fake response"
end
Did you know that there's a similar shorthand to forward a block anonymously? I learned this very recently (yesterday!), and I love it.
Notice the perform method in the following example:
def execute(&blk)
yield "response 1"
blk.call "response 2"
end
def perform(&)
# execute receives the same block
# received by the perform function
execute(&)
end
perform do |result|
p result
end
# Output:
# "response 1"
# "response 2"
Earlier, you'd have done something like:
def perform(&blk)
execute(&blk)
end
But starting in Ruby 3.1, you can do this:
def perform(&)
execute(&)
end
Pretty cool, right? Also looks pretty nice, in my opinion. What do you think?
If you like this syntax, and would like to enforce it via Rubocop (Rails 8 ships with a default Rubocop linter out of box), you can use the following Rule:
Naming/BlockForwarding:
EnforcedStyle: anonymous
On the other hand, if you prefer the older explicit version, enforce it with this rule:
Naming/BlockForwarding:
EnforcedStyle: explicit
P.S. For an in-depth explanation, I suggest reading this post from zverok. It goes into much more depth.
Subscribe to get future posts via email (or grab the RSS feed)
Comments (2)
Pretty nice! Thanks for the article (again)
Very cool.