まつもと ゆきひろ@トヨタケーラムです.

今回は「例外処理」です.これであともうひとつになりました.
# 例題のプログラムを作らないとな.
--
例外処理

プログラムの動作に例外的な状況はつきものだ.ファイルをオープ
ンしようとすれば,ファイルが存在しないかも知れないし,書き込
もうとすれば,ディスクがいっぱいかも知れない.こういう状況を
考慮していないプログラムは品質が悪いといわれる.

問題は例外的な状況が発生したかどうかが,いちいち「今の処理は
大丈夫でしたか」と確認しなければ分からないことだ.例外的な状
況で処理が正しく行われていないのに続きを実行すれば,当然問題
が起きる.例外的な状況が発生したら,そのまま処理を続けてはい
けないのだ.

rubyではこういう例外的な状況では「例外」が発生する.特になに
も対処しなければ,「例外」はプログラムの実行を中断する.これ
で例外的な状況に対処せずに処理を続けてしまう心配は無い.

 ruby> file = open("/file_not_exist")
 ERR: No such file or directory - /file_not_exist

Cなどならオープンできたかプログラマがチェックする必要がある
が.rubyでは「例外が発生していないのでちゃんと処理が行われた」
と仮定することができる.Cで書くとこういう風になる.

 FILE *file = fopen("/file_not_exist", "r");
 if (file == NULL) { /* エラー処理 */ }

エラー処理する必要がない分,プログラムがすっきりするのが分か
るだろう.

先程も説明したように,例外が発生すると,プログラムの実行は中
断される.が,それでは嬉しくないことも多いだろう.例外の原因
に対応してプログラムを継続したい場合もあるはずだ.そういう時
には'begin'を使って,例外を捕捉する必要がある.使い方はこう
だ.

 ruby> begin
 ruby|   file = open("/file_not_exists")
 ruby| rescue
 ruby|   file = STDIN
 ruby| end
 nil
 ruby> print file, "==", STDIN, "\n"
 #<IO:0xbff58> == #<IO:0xbff58>
 nil

openに失敗したので,fileにSTDINが代入されたのが分かるだろう.
	beginは本体を実行している最中に例外が起きるとrescue以下のエ
ラー処理を実行する.

beginには「やり直し」の機能もある.これには`retry'を使う.
rescueの中でretryが使われるとbeginのはじめから実行をやり直す.
これを応用するとこんな感じになる.

 ruby> fname = "file_not_exists"
 ruby> begin
 ruby|   file = open(fname)
 ruby|   # なにか file を使った処理
 ruby| rescue
 ruby|   fname = "file_exists"
 ruby|   retry
 ruby| end
 nil

fileのオープンに失敗するとfnameに代わりのファイル名を代入し
てやり直すわけだ.処理の流れは以下のようになる.

 * openで例外が発生する
 * rescue以下へ,fnameに再代入する
 * retryでbeginの最初に
 * 今度はopenで成功する
 * 本来の処理

しかし,例えば再代入した名前のファイルも存在しなければ,この
例では無限ループに陥ってしまう.retryを使う時には,例外処理
に気を使った方が良い.

rubyのライブラリはエラーが起きた時に例外を発生させるようになっ
ているが,もちろん自分で例外を発生させることができる.例外を
発生させるには`fail'を使う.failには例外の状況を説明する文字
列を引数に与える.この文字列は説明する必要がない時には省略で
きる.この文字列は後から変数`$!'で参照できる.

 ruby> fail "test error"
 ERR: test error
 ruby> begin
 ruby|   fail "test2"
 ruby| rescue
 ruby|   print $!, "\n"
 ruby| end
 test2
 nil