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.