4.3 例外の生成と発生
4.1、4.2では標準ライブラリが発生させた例外を捕捉する方法を説明した。このページでは自分で例外を生成してその例外を発生させる(処理を中断させる)方法を説明する。
自分で例外を発生させる時には以下のように記述する。
# (1)
raise [例外オブジェクト]
# (2)
raise [例外オブジェクトの型], [メッセージ], [トラック情報]
# (3)
raise [例外オブジェクトの型], [メッセージ]
# (4)
raise [メッセージ]
一つひとつ順番に見ていこう。 まず(1)の書き方は単純に、例外オブジェクトを生成して発生させる方法である。それ以下の三つはこれを基本に書かれている。 (2)は、例外を発生させる時に一緒にオブジェクトを生成する方法だ。メッセージは4.2で説明した通り、例外を捕捉して表示したときに表示される文字列である。トラック情報というのは例外が発生した実行位置のことだが、この実行位置というのはコード上の位置ではなく、コンピュータが命令を読み込みに行ったスタック情報を指している。階層の低い情報なので、高度なプログラムを書かない限り必要になることはないだろう。 (3)は(2)からトラック情報を省略する方法で振る舞いは(2)とほぼ同じだ。 (4)は(3)からさらに例外オブジェクトの型を省略する方法である。この方法を使うと、自動的に例外オブジェクトの型はRuntimeErrorになる(Javaなど多くのプログラミング言語では例外オブジェクトの型にはExceptionという名前が付けられるが、Rubyでは慣例的にErrorという名前が付けられることが多い)。
では、4.1から通して見てきたテキストファイルをコピーする例で例外を発生させるように書き換えてみよう。
begin
raise 'text/ directory has not found.' if exists_dir_of?('text') == false # raiseを追加
input_file = open('text/input.txt', 'w+')
output_file = open('text/output.txt', 'w')
rescue RuntimeError => e # RuntimeErrorに特定
puts e
Dir::mkdir('text')
retry
else
output_file.write("==Copy start==\n")
output_file.write(input_file.read)
output_file.write("==Copy end==\n")
input_file.close
output_file.close
ensure
puts 'finish.'
end
exists_dir_of?(dir_name)メソッドはdir_nameという名前のディレクトがあればtrue、なければfalseを返す自作メソッドである(標準ライブラリのメゾッドにはない)。
上の例は思った通りに動いてくれるが、普通は例外処理はこのような使い方はしない。というのも、begin節内でraiseを定義して例外を捕捉するならば、if文で条件分岐すれば済むからだ。例外処理は普通、begin節の処理で使用するメソッド内に隠れた例外を捕捉するために使用する。実際に、上の例の様にraiseを書かなくても4.1、4.2の時点で例外は捕捉できていたので、ここでは無駄な例外を発生させていることになる。