TIL: Detecting block returns in Ruby
I was doing some research on introspecting Ruby on Rails database transactions for a Reddit thread, and came across this Rails PR that had some new Ruby behavior for me: detecting an early return
from a block.
Some background: A Ruby language feature, that can frequently surprise people, is that using return
within a Ruby block will return not only from the block itself, but also from the block’s caller too. Using next
is really the only truly safe way to interrupt a block early; even break
can be troublesome if the block is called by an enumerator. Also, next
can take a return value too, just like return
e.g. next my_value
.
I found the Rails PR interesting, because it has a method for detecting and warning on an early return. Here’s a simplified example:
def some_method(&block)
block.call
completed = true # won't be called if the block returns early
ensure
if completed
puts "ok"
else
puts "returned early"
end
end
some_method { return } # => "returned early"
some_method { next } # => "ok"
This works because the methods ensure
block will always be called, even if #some_method
returns early. That was a novel implementation for me.