Search code examples
rubyyield

Is there a concise syntax for chaining yield calls in Ruby?


I have a method that iterates over some records and does something with them, optionally yielding a result -- something analogous to:

@evens = []
def foo(numbers)
  numbers.each do |r|
    even = r % 2 == 0
    @evens << r if even
    yield "#{r}: #{even}" if block_given?
  end
end

I have a second method that fetches records and passes them to the first method, something analogous to:

def bar(count)
  numbers = (0..count).to_a
  foo(numbers)
end

I want to change this method to also take an optional block, yielding the results from the first method. What I've come up with so far:

def bar(count)
  numbers = (0..count).to_a
  foo(numbers) do |result|
    yield result if block_given?
  end
end

This feels like about two more lines and one more if block_given? check than I ought to need. Is there a more concise way to simply say "yield whatever this method call yields, if anything"?


Solution

  • When defining a method in Ruby, you can also optionally define the block as a special named argument:

    def bar(count, &block)
      #...
    end
    

    Then, in the method, you can pass the block (or generally: any Proc object) as a block to a method. Thus, the following method will be fully equivalent to your bar method:

     def bar(count, &block)
      numbers = (0..count).to_a
      foo(numbers, &block)
    end
    

    Note that even when defining a &block argument in the method's signature, it is not mandatory to pass a block. If you don't pass one, block will be nil in the method body.