Как только каждый программист 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 из этого или есть встроенное решение для предотвращения быстрого возврата из вложенного блока, который я пропустил?