Obsługa wyjątków: ENSURE a zwracana wartość

ensure exception rails return ruby

Obsługując wyjątki (exceptions), aby zapewnić sobie wykonanie jakiegoś bloku niezależnie od jego wystąpienia lub nie – korzystamy z ensure
Warto jednak zwrócić uwagę na to co zwraca w ten sposób skonstruowany kod.

Exceptions – szybkie przypomnienie struktury

W Ruby możemy w prosty sposób przechwytywać wyjątki występujące w trakcie wykonywania kodu

  • przechwytujemy za pomocą rescue (+klasa wyjątku do przechwycenia)
  • umieszczamy kod w bloku begin ... end lub w obrębie metody
  • za pomocą ensure możemy zdefiniować kod, który niezależnie od wysytąpienia wyjątku bądź nie powinien zostać wykonany

Przykładowe użycie

def test_meth(val)
  @new_val = 100 / val
rescue ZeroDivisionError
  @new_val = 100
ensure
  @new_val = @new_val * 2
end

Pomijając sensownośc takiej metody, możemy zinterpretować ją następująco:
Podziel 100 przez podaną wartość a następnie upewnij się, że wynik został pomnożony przez 2.
Jeżeli zdarzy się, że podana wartość to 0 – nie dziel tej setki.

ENSURE – o czym warto pamiętać

Na czym polega więc pułapka ensure‘a?
W Rubym przyzwyczajeni jesteśmy do tego, że zwracana wartość jest wynikiem ostatniej operacji.

W przypadku ensure tak się nie dzieje!
Kod z bloku zostanie wykonany ale nie jest wartością zwracaną
Wracając do naszego przykładu:

def test_meth(val)
  @new_val = 100 / val
rescue ZeroDivisionError
  @new_val = 100
ensure
  @new_val = @new_val * 2
end


test_result = test_meth(10)

puts @new_val
# ==> 20
# wartość faktycznie została podwojona w bloku ensure

puts test_result
# ==> 10
# ...ale wartość zwrotna całej metody to wcześniejsze wykonanie

# w przypadku zera

test_result_0 = test_meth(0)

puts @new_val
# ==> 200

puts test_result_0
# ==> 100
# wartość zwrotna całej metody to wartość z bloku rescue

TL;DR

Kod zamknięty w bloku ensure jest zawsze wykonany, ale nie jest wartością zwracaną