Last Updated: September 10, 2023
·
47.36K
· mcansky

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 ?

1 Response
Add your 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
7 months ago ·