Ruby : block as parameter
A coworker asked me to refactor some code using a block passed as parameter to a method.
If you are not familiar with Ruby blocks the thing is you can bundle up some lines of code inside a "do-end" block (or {} if it's a one line or if you like to mess up with your brain).
Using blocks is fun, it's a nice way to bundle up a series of actions :
[1,2,3].each do |i|
puts i
i += 2
puts i
end
But you can also write a method that will take a block as parameter. The method can then run the block at any time by calling yield :
def foo_m(_a, &block)
if (_a % 2) == 0
puts "hooray"
else
yield
end
end
[1,2,3,4,5].each do |i|
foo_m i do
puts "something is odd here"
end
end
what's happening ?
The foo_m method is simple : it outputs "hooray" if the a parameter is an even number and *yield if that's not the case. When the method yields it then pass the hand to the block, or rather we could say "it runs the block". So when the _a is odd the string "something is odd here" will be outputted.
To me it feels both awesome and strange as the block code will only be run if the method does yield at some point. And there lies the strangeness of the thing : it makes the code a bit difficult to read : it's not "straightforward" (to me).
What do you think ? Is there a better way to explain this and to keep the code readable ?
Written by Thomas Riboulet
Related protips
1 Response
It's not really strange, if you have used the each
method, you are straight up using blocks. What you might be missing here is that you can do the iteration within your own method, like so:
def foo_m(collection, &block)
collection.each do |i|
if (i % 2) == 0
puts "hooray"
else
yield
end
end
end
Which you then use like this:
foo_m([1,2,3,4,5]) do
puts "something is odd here"
end