Ruby Language Yielding to blocks


Example

You can send a block to your method and it can call that block multiple times. This can be done by sending a proc/lambda or such, but is easier and faster with yield:

def simple(arg1,arg2)
  puts "First we are here:  #{arg1}"
  yield
  puts "Finally we are here:  #{arg2}"
  yield
end
simple('start','end') { puts "Now we are inside the yield" }

#> First we are here:  start
#> Now we are inside the yield
#> Finally we are here:  end
#> Now we are inside the yield

Note that the { puts ... } is not inside the parentheses, it implicitly comes after. This also means we can only have one yield block. We can pass arguments to the yield:

def simple(arg)
  puts "Before yield"
  yield(arg)
  puts "After yield"
end
simple('Dave') { |name| puts "My name is #{name}" }

#> Before yield
#> My name is Dave
#> After yield

With yield we can easily make iterators or any functions that work on other code:

def countdown(num)
  num.times do |i|
    yield(num-i)
  end
end

countdown(5) { |i| puts "Call number #{i}" }

#> Call number 5
#> Call number 4
#> Call number 3
#> Call number 2
#> Call number 1

In fact, it is with yield that things like foreach, each and times are generally implemented in classes.

If you want to find out if you have been given a block or not, use block_given?:

class Employees
  def names
    ret = []
    @employees.each do |emp|
      if block_given?
        yield(emp.name)
      else
        ret.push(emp.name) 
      end
    end

    ret
  end
end

This example assumes that the Employees class has an @employees list that can be iterated with each to get objects that have employee names using the name method. If we are given a block, then we'll yield the name to the block, otherwise we just push it to an array that we return.