Rubyではプログラム上で異常が発生した時に「例外」が発生し、そこで実行が停止します。これにより、プログラムの構造をシンプルにすることができます。

また、ユーザプログラムで例外を発生させたり、例外を捕捉して回復のための処理を記述することも可能です。

例外を捕捉する

begin-rescue-ensure-end構文で例外を捕捉し、その回復処理を記述することができます。

 ■構文
 begin
   式..
 [rescue [error_type,..] [=> evar] [then]
   式..]..
 [else
   式..]
 [ensure
   式..]
 end
 
 begin
   # 実行する処理
 rescue
   # 例外が発生したときの処理
 else
   # 例外が発生しなかったときに実行される処理
 ensure
   # 例外の発生有無に関わらず最後に必ず実行する処理
 end
 begin
   dest = open("backup/passwd", "w")
   source = open("/etc/passwd")
 rescue
   Dir::mkdir("backup")
   retry
 else
   dest.write(source.read)
   dest.close
   source.close
 ensure
   puts "script end."
 end

特定の例外だけを捕捉する

rescueの後に捕捉する例外を明示することで、特定の例外だけを捕捉することができます。

 begin
   # 略
 rescue Errno::EEXIST
   # Errno::EEXIST(mkdirで既にディレクトリが存在する場合)を捕捉した場合の処理
 end

種類が指定されない場合、”StandardError?”が省略されたと認識されるようです。

例外処理の後に処理をやり直す

rescue節の中でretry文を使うと、例外処理の後に処理をやり直すことができます。

 begin
   dest = open("backup/passwd", "w")
   source = open("/etc/passwd")
 rescue
   Dir::mkdir("backup")
   retry
 else
   dest.write(source.read)
   dest.close
   source.close
 ensure
   puts "script end."
 end

例外の内容を受け取る

rescueの後に”=> (変数)”とすることで上がってきた例外を捕捉できます。つまり、上がってきた例外が指定した変数に代入されます。

 begin
   raise "error!"
 rescue => exc
   p exc
 end

種類の指定と組み合わせることもできます。

 begin
   # ...
 rescue Errno::EEXIST => e
   print "error raised: "
   p e
   # ...
 end

例外を発生させる

raiseを使用すると意図的に例外を発生させることができます。

種類を指定しなければ、RuntimeError?クラスの例外になります。

 raise #=> RuntimeError:
 raise "format error" #=> RuntimeError: format error

種類を指定する場合、ふたつ方法があります。

カンマで区切って例外クラスとメッセージを書く

 raise NotImplementedError #=> NotImplementedError: NotImplementedError
 raise ArgumentError, "invalid argument" #=> ArgumentError: invalid argument

例外オブジェクトを生成して指定する

 raise IndexError.new("index out of range") #=> IndexError: index out of range

いずれの場合も、例外のクラスはExceptionクラスの下位クラスでなければなりません。

独自の例外を定義し発生させる

Exceptionクラスのサブクラスを定義するとユーザ独自の例外クラスを定義することができます。

 class SampleException < Exception; end
 raise SampleException, "format error." #=> format error. (SampleException)

自作の例外を捕まえる時には、名前を明示しなければなりません。

 begin
   raise SampleException
 rescue SampleException
   p "format error"
 end

種類を指定しないrescueで捕まえられるようにするには、StandardError?を使って定義します。

 class SampleException < StandardError; end
 begin
   raise SampleException
 rescue
   # ...
 end

省略記法(def)

メソッド定義全体にかかる場合はbeginとendを省略できるようです。

 def some_method
   begin
     # ...
   rescue
     # ...
   end
 end
 def some_method
   # ...
 rescue
   # ...
 end

else, =>, ensureなどその他の文法も問題なく使えます。

省略記法(後置)

ifなどと同様、rescueでも後置記法ができます。

 begin
   # (1)
 rescue
   # (2)
 end

に対応して

 (1) rescue (2)

とします。 種類を指定して受けることはできませんが、特殊変数 $! によって捕まった例外を表すオブジェクトを参照できます。