Ensure you understand ensure
rubyLet’s look at this code:
def func1
puts "one"
return
puts "two"
ensure
puts "ensure"
end
How the result will look? Of course you’ll never see "two"
, but what about "ensure"
?
[13] pry(main)> func1
one
ensure
nil
[14] pry(main)>
Even you return from a function without exceptions, ensure
gets executed.
Another example:
def func2
10.times do |num|
begin
puts "iteration #{num}"
next if num.even?
puts "after iteration #{num}"
ensure
puts "ensure"
end
end
end
And let’s look at result:
[18] pry(main)> func2
iteration 0
ensure 0
iteration 1
after iteration 1
ensure 1
iteration 2
ensure 2
iteration 3
after iteration 3
ensure 3
iteration 4
ensure 4
iteration 5
after iteration 5
ensure 5
iteration 6
ensure 6
iteration 7
after iteration 7
ensure 7
iteration 8
ensure 8
iteration 9
after iteration 9
ensure 9
10
[19] pry(main)>
It was very surprising for me in a contrast with Ruby’s “least surprise principle”. But this is how it works:
Marks the final, optional clause of a begin/end block, generally in cases where the block also contains a rescue clause. The code in the ensure clause is guaranteed to be executed, whether control flows to the rescue block or not.
Conclusion
Every time execution leaves begin
block, ensure
gets executed no matter what: exception, return, next, break, etc.