Как только каждый программист Ruby обнаруживает, что вызовы или procs, содержащие инструкции return
, могут быть опасны, поскольку это может выйти из вашего текущего контекста:
def some_method(&_block)
puts 1
yield
# The following line will never be executed in this example
# as the yield is actually a `yield-and-return`.
puts 3
end
def test
some_method do
puts 2
return
end
end
test
# This prints "1\n2\n" instead of "1\n2\n3\n"
В случаях, когда вы хотите быть абсолютно уверены, что некоторые из ваших кодов запускаются после вызова блока или proc, вы можете использовать конструкцию begin ... ensure
. Но поскольку ensure
также вызывается, если во время урока есть исключение, требуется немного больше работы.
Я создал крошечный модуль, который рассматривает эту проблему двумя разными способами:
-
Используя
safe_yield
, выясняется, действительно ли возвращаемый блок или proc возвращается с использованием ключевого словаreturn
. Если это так, возникает исключение.unknown_block = proc do return end ReturnSafeYield.safe_yield(unknown_block) # => Raises a UnexpectedReturnException exception
-
Используя
call_then_yield
, вы можете вызвать блок, а затем убедиться, что выполняется второй блок, даже если первый блок содержит операторreturn
.unknown_block = proc do return end ReturnSafeYield.call_then_yield(unknown_block) do # => This line is called even though the above block contains a `return`. end
Я собираюсь создать быстрый Gem из этого или есть встроенное решение для предотвращения быстрого возврата из вложенного блока, который я пропустил?