Featured image

When you use blocks in your Ruby code, one of the crucial issues is ensuring a correct exit from them based on a specific condition. To achieve this, developers typically use the following keywords: next, break, return, and the catch/throw construct. In most cases, to exit the current iteration or the block itself, you should use break. For nested blocks, catch/throw is the way to go. These options will immediately interrupt execution and pass control to the code following the calling method or the catch block. When using the next keyword, you will move to the next iteration of the block. However, if there are no more iterations, the execution will yield to the code following yield or block.call inside the method to which you passed the block. On the other hand, when using return, you will completely exit the method where the block was originally defined (due to Ruby’s lexical scoping).

# Using the 'next' keyword to exit a block (1)
def method_with_block
  puts 'Start method_with_block'
  yield
  puts 'End method_with_block'
end

def next_example
  puts 'Start next_example'
  method_with_block do
    puts 'Start block'
    next if true
    puts 'End block'
  end
  puts 'End next_example'
end

next_example
# Start next_example
# Start method_with_block
# Start block
# End method_with_block
# End next_example
# Using the 'break' keyword to exit a block (2)
def method_with_block
  puts 'Start method_with_block'
  yield
  puts 'End method_with_block'
end

def break_example
  puts 'Start break_example'
  method_with_block do
    puts 'Start block'
    break if true
    puts 'End block'
  end
  puts 'End break_example'
end

break_example
# Start break_example
# Start method_with_block
# Start block
# End break_example
# Using the 'return' keyword to exit a block (3)
def method_with_block
  puts 'Start method_with_block'
  yield
  puts 'End method_with_block'
end

def return_example
  puts 'Start return_example'
  method_with_block do
    puts 'Start block'
    return if true
    puts 'End block'
  end
  puts 'End return_example'
end

return_example
# Start return_example
# Start method_with_block
# Start block
# Using the 'catch/throw' construct to break out of nested blocks (4)
def method_with_block
  puts 'Start method_with_block'
  yield
  puts 'End method_with_block'
end

def catch_example
  puts 'Start catch_example'
  catch :exit do
    method_with_block do
      puts 'Start block 1'
      method_with_block do
        puts 'Start block 2'
        # next, break - will exit only the inner block
        # return - will terminate the method
        throw :exit if true
        puts 'End block 2'
      end
      puts 'End block 1'
    end
  end
  puts 'End catch_example'
end

catch_example
# Start catch_example
# Start method_with_block
# Start block 1
# Start method_with_block
# Start block 2
# End catch_example

What methods do you use to exit a block? Do you know any other ways to terminate a block’s execution (well, besides raise and exit/abort, of course)?