Возращаемые значения rescue/ensure в Ruby
24/01/2018
Иногда бывают такие дни, когда хочется просто поэксперементировать с нестандартным кодом на языке программирования, которым зарабатываешь на хлеб. Сегодня я бы хотел поделиться некоторыми ньюансами и неочевидными поведениями rescue
и ensure
конструкций Ruby. Напомню, что в Ruby результат последнего выражения внутри метода или begin/end
блока возвращается неявно, и это считается хорошей практикой. Однако, можно и явно указывать return
и возвращать результат, например, досрочно. Это играет определенную роль в поведении rescue
и ensure
, поэтому я буду отдельно проверять поведение при явном и неявном возврате результата.
def a
raise
1
rescue
2
end
#=> :a
a
#=> 2 ---> Стандартное неявное возвращение результата из rescue
def b
raise
1
rescue
return 2
end
#=> :b
b
#=> 2 ---> Стандартное явное возвращение результата из rescue
def c
raise
1
rescue
return 2
ensure
3
end
#=> :x
c
#=> 2 ---> ensure не перекрывает результат rescue
def d
raise
1
rescue
return 2
ensure
return 3
end
#=> :d
d
#=> 3 ---> ensure перекрывает результат rescue
Думаю вы заметили разницу между методами c
и d
– return
внутри ensure
подменяет результат из resuce
. Лично меня пример метода d
каждый раз приводит в легкое удивление. Давайте теперь посмотрим, что происходит, если внутри rescue
или ensure
вызывается исключение.
def e
raise
rescue
raise 'A'
end
#=> :e
e
#=> RuntimeError: A ---> Ожидаемо вываливаемся с исключением 'A'
def f
raise
ensure
raise 'B'
end
#=> :f
f
#=> RuntimeError: B ---> Ожидаемо ли вываливаемся с исключением 'B'?
def g
raise
rescue
raise 'A'
ensure
raise 'B'
end
#=> :g
g
#=> RuntimeError: B ---> Опаньки, исключение 'A' было проглочено исключением 'B'
def h
raise
rescue
raise 'A'
ensure
end
#=> :h
h
#=> RuntimeError: A ---> Ожидаемо вываливаемся с исключением 'A'
def i
raise
rescue
raise 'A'
ensure
return 3
end
#=> :i
i
#=> 3 ---> Опаньки, исключение 'A' было проглочено ensure как и в примере g
Будьте внимательны во время написания кода обработки ошибок и старайтесь покрывать его тестами, в том числе и на возвращаемый результат.