Ruby/Przetwarzanie wyjątków: ensure

Przetwarzanie wyjątków: ensure

edytuj

Może się tak zdarzyć, że potrzebne jest dodatkowe sprzątanie, gdy metoda kończy swoją pracę. Być może otwarty plik powinien być zamknięty, bufor opróżniony, itp. Jeżeli byłby zawsze tylko jeden punkt wyjścia dla każdej metody, moglibyśmy z pełną ufnością umieścić kod czyszczący w jednym miejscu i wiedzielibyśmy, że zostanie on wykonany. Jednakże, metoda może zwracać wartość z różnych miejsc, lub nasze zamierzone czyszczenie może być niespodziewane ominięte z powodu wyjątku.

begin
  plik = open("/tmp/jakis_plik", "w")
  # ... zapis do pliku ...
  plik.close
end

W powyższym przykładzie, jeżeli wyjątek wystąpiłby w sekcji kodu, w której dokonujemy zapisu do pliku, plik mógłby pozostać otwarty. A my nie chcemy uciekać się tego rodzaju redundancji:

begin
  plik = open("/tmp/jakis_plik", "w")
  # ... zapis do pliku ...
  plik.close
rescue
  plik.close
  fail # ponownie podnosi przechwycony wyjatek
end

Ten kod nie dość, że niezdarny, będzie jeszcze bardziej skomplikowany, ponieważ trzeba będzie obsługiwać każdy return i break.

Z tego powodu dodamy nowe słowo kluczowe do naszego schematu "begin...rescue...end", którym jest ensure. Blok ensure wykonuje się niezależnie od pomyślnego lub niepomyślnego zakończenia bloku begin.

begin
  plik = open("/tmp/jakis_plik", "w")
  # ... zapis do pliku ...
rescue
  # ... obsluga wyjatkow ...
ensure
  plik.close   # ... zawsze wykonywane.
end

Możliwe jest używanie ensure bez rescue i vice versa, ale jeśli używane są razem w tym samym bloku begin...end, rescue musi poprzedzać ensure.