ensure と raise
CoddyのRubyジャーニー「ロジックとフロー」セクションの一部 — レッスン 46/56。
さらに2つの要素がエラーハンドリングのツールキットを完成させます。
ensure は、begin が正常に終了したか、rescue 節が例外をキャッチしたか、あるいは例外がキャッチされなかった場合でも、何があっても実行されるブロックです。ここはクリーンアップコードを記述する場所です:
begin
puts "opening file"
raise "something broke"
rescue
puts "caught it"
ensure
puts "closing file"
end
# ファイルを開いています
# キャッチしました
# ファイルを閉じていますraise は、独自の例外を作成する方法です。メッセージとして文字列を渡すか、クラスとメッセージを渡します:
def withdraw(amount)
raise ArgumentError, "amount must be positive" if amount <= 0
# ... 引き出し処理を行う
end慣習では、引数が誤っている場合に早期に失敗(fail fast)させるため、メソッドの先頭で早期に raise します。呼び出し側は、適切な回復処理がある場合には rescue するか、あるいはそのまま上位に伝播させることができます。
チャレンジ
簡単以下の処理を行うメソッド safe_divide(a, b) を定義してください:
b == 0の場合、メッセージ"b cannot be zero"を持つArgumentErrorを発生させる- それ以外の場合は
a / bを返す
次に、入力から2つの整数を読み取ります。begin / rescue / ensure の中で safe_divide を呼び出してください:
- 成功した場合は、
Result: <value>を出力する ArgumentErrorが発生した場合は、Error: <message>を出力するensure内では、常にDone.を出力する
入力が 10 / 2 の場合、出力は以下のようになります:
Result: 5
Done.入力が 10 / 0 の場合:
Error: b cannot be zero
Done.チートシート
ensure は何があっても(正常終了、レスキューされた場合、または捕捉されなかった例外が発生した場合でも)実行されます。クリーンアップに使用します:
begin
raise "something broke"
rescue
puts "caught it"
ensure
puts "always runs"
endraise は例外を発生させます。特定の型を発生させるには、クラスとメッセージを渡します:
raise ArgumentError, "amount must be positive" if amount <= 0慣習:不正な引数に対して早期に失敗(fail fast)させるため、メソッドの先頭で早期に raise します。
自分で試してみよう
# TODO: safe_divide(a, b) を定義する。b == 0 のときに ArgumentError を発生させる
a = gets.to_i
b = gets.to_i
# TODO: begin ... Result を print する; rescue ArgumentError => e ... Error を print する; ensure ... Done を print する
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。