ruby blocks、 Yield、 Proc & Lambda

Ruby blocks allow a section of code to be passed to methods without first storing that section of code into any variable.

[1,2,3].each {puts "bobo"}

In the case given above, { puts "bobo" } is the section of code that is being passed to the method each. As we can see, this section of code is not stored in a variable first. That’s why, some people say that Ruby blocks are used to pass anonymous code to methods.

Here, by anonymous, the only thing they mean is that the block of code is not first stored in a variable.

Let’s look at one more example. In this case, the code inside the do end is a Ruby block.

[1, 2, 3].each do
  puts "bobo"
end
4.times { puts "nice" }

4.times do
puts "nice"
end

also accept arguments. Here is an example:

[1, 2, 3].each { |m| puts m }

yield is a special thing in Ruby. Using yield, a method can ask a block to be executed.

def hello
  puts "world"
  yield if block_given?
  puts "hello ruby"
end

hello {puts "i like ruby"}

We want to yield to a block only if a block is passed. There is no point in yielding to a block if there is no block. We can solve this by using the block_given? method. block_given? would return true if a block is passed.

Ruby also allows us to explicitly accept a block. In order to do so, the argument must start with an &. Usually, such arguments are named &block.

def hello(&block)
    puts "world"
    block.call
    puts "hello ruby "
end

hello {puts "i like ruby"}

The proc keyword defines a block. This way, we can store the block in a variable. Later, we can call that block using the call method.

hello = proc { puts "hello world" }
hello.call  // hello world

Procs can also take arguments.

hello = proc { |n| puts "hello #{n}" }
hello.call("world")  // hello world

Ruby also has something called lambda which is very similar to a proc. lambda enforces arity. It means, if a lambda accepts 2 arguments but if we’re trying to pass it 3 arguments, then the lambda will raise an error. On the other hand, a proc will ignore the extra argument.

hello =lambda { |n| puts "hello #{n}" }
hello.call("world")  // hello world