blog.waterlow.work

Ruby, Rails, js, etc...

【Ruby】Gold試験対策-例外処理

パーフェクトRubyを読み進めていたのですが、メタプロの理解は少し時間がかかりそうなので平行してGoldの試験対策をしていきます。Rubyアソシエーションによると出題範囲は以下のようになっています。出題範囲のところだけ勉強して模擬問題に取り組んでみます。太字は今日やるとこ。

実行環境
 →コマンドラインオプション、組み込み変数/定数

文法
 →変数と定数、演算子、ブロック、例外処理、大域脱出

オブジェクト指向
 →メソッドの詳細、メソッドの可視性、クラスの詳細、クラスの継承、モジュールの詳細

組み込みライブラリ
 →よく使用されるクラス(Object、Kernel、Module等)
 →よく使用されるモジュール(Enumerable、Comparable等)
 →数値
 →正規表現

標準添付ライブラリ
 →よく使用されるライブラリ(socket、rdoc等)

例外処理

今回は昔Javaをやってた時も苦手意識を感じていた例外処理をやってみます。
例外発生時の基本的な処理の流れは下記サイトの中程に貼ってある図がわかりやすいかもしれません。(Rubyで書くためtry-catchではありませんが。)
JavaScriptと非同期のエラー処理 - Yahoo! JAPAN Tech Blog

簡単なサンプルコード
例外を無理やり発生させます。第二引数(メッセージ)は省略可。第一引数を省略してSrtingだけ渡してもRuntimeErrorとなります。

raise RuntimeError, 'error!' #=> error_test.rb:1:in `<main>': error! (RuntimeError)

例外の補足は以下のように行います。Javaやjsで言うtry-catchみたいな感じ。class、message、backtraceで例外の情報を見れます。

module TestModule
  begin
    raise RuntimeError, "error occurred!"
  rescue => e
    puts "#{e.message}, #{e.class}"
    puts e.backtrace
  rescue RuntimeError, NameError => e
    puts "This is RuntimeError"
    puts "#{e.message}, #{e.class}"
    puts e.backtrace
  else
    puts "non error"
  ensure
    puts "error test end"
  end
end

class TestClass
  include TestModule
end

test = TestClass.new
# error occurred!, RuntimeError
# error_test.rb:3:in `<module:TestModule>'
# error_test.rb:1:in `<main>'

rescueの引数で特定の例外を制御できます。しかも引数の数は可変長。ただ上記のサンプルだと引数で例外を指定しても、1つ目のrescueにつかまってしまいますね。rescueの記述順序には注意。
elseは例外が起こらなかった時の処理を、ensureは例外が発生しようがしまいが行いたい処理を記述します。fileのクローズ等は外に書くよりensureに書くほうがわかりやすいかもですね。

またrescueの後置用法もあります。StandardErrorならばキャッチできます。

1 / 0 rescue false

上のサンプルでは記載されていますが、クラス、モジュール、メソッドの定義に例外処理を組み込むときはbeginとendは要らないようです。

あとはリトライなんて便利なものもあります。

begin
  failed ||= 0
  raise "too small" if rand(10) < 9
rescue => e
  failed += 1
  puts "failed = #{failed}"
  retry if failed < 5
else
  puts "normal end"
end
覚えること

1.例外制御構文(begin、rescue、end)
2.例外クラスの情報取得(message、backtrace)
3.例外でない場合に実行(else)
4.例外有無にかかわらず実行(ensure)
5.例外が発生してもめげずにもう一度実行(retry)