Ruby blocks are fairly easy to pickup, use, and make work if you just follow the common examples. But at some point you might realize that you don’t really understand what is going on in the same way as you might with variable assignment or a method call.

Let’s start with a basic definition of a block. A block is an anonymous function that can be passed into other Ruby methods. Those methods will run their own code and then yield to the block at some point and run its code.

# Here is a simple example using yield:

# .\ruby\blocks.rb
def yield_method(a, b)
  puts a
  yield 
  puts b
end

yield_method("AAA", "BBB"){puts "CCCC"}

$ ruby .\ruby\blocks.rb
AAA
CCCC
BBB

Ruby has other light-weight anonymous functions like lambda and procs. Ruby blocks are similar to lambdas in the ways they are used. For example you can do [1,2,3].each { |n| puts n } or you can do [1, 2, 3].each lambda { |n| puts n }. But blocks are different from lambdas and procs because both of those are objects that can be assigned.

# Ruby blocks cannot be directly assigned to a variable because there is no class for Block. A block can't be an object and thus can't be an instance. For example:

block = { "Hello world" }

$ ruby .\ruby\blocks.rb
./ruby/blocks.rb:12: syntax error, unexpected '}', expecting =>
block = { "Hello world" }

# If you want to assign a block to a variable then what you want is either a Proc object or a Lambda:

proc_object = Proc.new { puts "Hello world" }
=> #<Proc:0x0000021603616898 (irb):1

You can also write Ruby methods that take blocks with multiple yields. Example:

# .\ruby\blocks.rb
def double_yield_method(a, b)
  puts a
  yield
  yield 
  puts b
end

double_yield_method("AAA", "BBB"){puts "2 CCCC"}

$ ruby .\ruby\blocks.rb
AAA
2 CCCC
2 CCCC
BBB

Ok, so now you know that blocks are different than procs and lambdas. You also know how to write a method that takes a block and yields to it one or more times. What happens if the method caller doesn’t pass in a block to you method.

# If you try to run a method that yields to a block without passing in a block you get an error. Example:

# .\ruby\blocks.rb
def yield_method
  yield 
end

yield_method

$ ruby .\ruby\blocks.rb
Traceback (most recent call last):
        1: from ./ruby/blocks.rb:1:in `<main>'
./ruby/blocks.rb:48:in `yield_method': no block given (yield) (LocalJumpError)

# You can guard against this by using block_given? Example:

# .\ruby\blocks.rb
def yield_method(a, b)
  puts a
  if block_given?
    yield 
  end
  puts b
end

yield_method("AAA", "BBB")

$ ruby .\ruby\blocks.rb
AAA
BBB

Ok, that should give you a better overview of how blocks work so you will be more confident using them or implementing methods which receive them.

More about blocks:

The differences between Ruby blocks, procs, lambdas, and closures.