例外が発生しても発生しなくても行いたい処理がある場合、「ensure」を使います。似たような仕組みに「else」がありますが、こちらは、例外が発生しなかった場合のみ実行される処理を記述できます。exception06.rbに例を示しましょう。
require_relative "exception01" begin teapot = Teapot.new("coffee") teapot.pour_out rescue UnacceptableRequidError => e puts "Rescued in 'UnacceptableRequiedError => e'" p e rescue NoMethodError, ZeroDivisionError => e puts "Rescued in 'rescue NoMethodError, ZeroDivisionError => e'" p e rescue StandardError => e # rescue => e でもOK puts "Rescued in 'rescue StandardError => e'" p e else puts "There are no errors." ensure puts "Ensure" end
$ ruby exception06.rb Rescued in 'UnacceptableRequiedError => e' #<UnacceptableRequidError: unacceptable> Ensure
実行結果の4行目から、rescueによる例外処理の後にensureの中身が実行されていることが分かります。ここではbegin〜rescue間で例外が発生した場合のみを確かめているので、begin〜rescue間のコードをいろいろと変えてみて、ensureやelseの動作を確かめてみてください。
例外が発生した場合でも、リトライしたいというケースもあります。そのような場合、rescue節でretryを使うことにより、再度begin〜rescue間の処理を行えます。exception07.rbにリトライの例を示します。
require_relative "exception01" begin retry_count ||= 0 puts "Try..." teapot = Teapot.new(%w(coffee tea beer wine).sample) puts teapot.pour_out rescue UnacceptableRequidError => e retry_count += 1 retry if retry_count < 3 end
$ ruby exception07.rb Try... Try... tea
$ ruby exception07.rb Try... Try... Try...
ここでは、7行目で文字列の配列とArray#sampleメソッドを使うことで、「coffee」「tea」「beer」「wine」の中からランダムに一つ選び出して、Teapotオブジェクトの初期値に設定しています。選び出された文字列が「tea」でなければ、UnacceptableRequidErrorが発生して10行目に処理が移ります。
rescue節の中では、リトライ回数を表すretry_countを1増やして、retryを実行しています。ただし、無限ループとならないよう、後置ifを使って試行回数を3回までに制限しています。もし3回以内であれば、再度begin〜rescueが実行されます。
ちょっと乱暴ですが、時には「例外を握りつぶして、nilなどの値を返したい」場合があります。そのような場合は、後置rescueを使えます。pryを起動して以下のコードを実行してみましょう。
[1] pry(main)> require_relative "exception01" => true [2] pry(main)> Teapot.new("coffee") rescue nil => nil
[2]のように、rescueしたい対象のコードの末尾にrescueと返したいオブジェクトを記述することで、例外が起こった場合に特定のオブジェクトを返せます。
ただし、この書き方ではStandardErrorしか捕捉できないことに注意してください。ここでは、Teapot.newはUnacceptableRequidErrorを発生させますが、その例外は捕捉されてnilが返されます。
今回は、他のオブジェクト指向言語でもポピュラーな仕組みである例外処理について解説しました。今回の知識を活用することにより、ファイルが存在しない場合など、実行時に起こる不測の事態に対処できるようなプログラムを書くことができるようになりました。
次回は、入出力やスレッドについて解説します。これらの仕組みを活用すれば、OSで利用できるコマンドと連携したRubyプログラムを書くことができるなど、日々のちょっとした問題解決にRubyを利用する助けになります。お楽しみに!
麻田 優真(Rails技術者認定シルバー試験問題作成者)
イタリア、ローマ生まれ。中学生のころHSPに初めて触れ、プログラミングの楽しさを知る。オープンソースやハッカーカルチャーを好む。C#からRubyに転向したときに、動的型付け言語の柔軟性やメタプログラミングの魅力に感動し、Rubyとともにプログラマーとしての人生を歩む決意を固める。
現在は奈良先端科学技術大学院大学で学生として所属するかたわら、株式会社アジャイルウェアでプログラマーとして従事。Ruby on Railsによるコンシューマー向けのWebサービスの開発などに尽力している。
好きなメソッドは、define_method。
Twitter:@Mozamimy、ブログ:http://blog.quellencode.org/
山根 剛司(Ruby業務開発歴7年)
兵庫県生まれ。1997年からベンチャー系のパッケージベンダーで10年間勤務。当時、使用していた言語はJavaとサーバーサイドJavaScript。
2007年よりITコンサル会社に転職し、Rubyと出会って衝撃を受ける。基幹システムをRuby on Railsで置き換えるプロジェクトに従事。それ以来Ruby一筋で、Ruby on Railsのプラグインやgemも開発。
2013年より、株式会社アジャイルウェアに所属。アジャイルな手法で、Ruby on Railsを使って企業向けシステムを構築する業務に従事。
Ruby関西所属。
Twitter:@spring_kuma、Facebook:山根 剛司
Copyright © ITmedia, Inc. All Rights Reserved.