しょんぼり技術メモ

まいにちがしょんぼり

Rubyの例外について

Rubyのbegin-rescueについて勘違いしていたのでメモ。

Rubyでは、Object->Exception->StandardErrorのような継承構造になっており、独自の例外クラスを作って識別する際には、Exceptionを継承するのではなく、StandardErrorを継承した方が(俺の)思っているとおりの動作になる。

Exceptionを継承した場合、rescue句でクラス名を省略したブロックではハンドルされない。
StandardErrorを継承した場合、rescue句でクラスを省略したブロックでもハンドルされる。

もっとも、他の例外に埋もれないように独自例外を使うような気もするので、Exceptionから継承してもいいのかな?とも思う。この辺は哲学を学ばないとダメかもしれない。

ひとまず、テストコードを書いて確かめたのでメモしておく。この辺詳しい人教えてください。

#!/usr/bin/ruby -Ku
# -*- coding: utf-8 -*-
require 'pp'

class TestError < StandardError; end
class TestException < Exception; end

class Test
  def raise_error
    raise TestError, "exception message of TestError"
  end

  def raise_exception
    raise TestException, "exception message of TestException"
  end
end

t = Test.new

puts "・StandardExceptionを継承した場合は、rescueでクラス名を指定しなくてもハンドルできる"
begin
  puts " クラス名を指定しない場合"
  t.raise_error
rescue
  puts "caught raise_error's exception: #{$!.message}"
end
puts


puts "・Exceptionを継承した場合は、rescueでクラス名を指定しないとハンドルできない"
begin
  puts " クラス名を指定する場合"
  t.raise_exception
rescue TestException
  puts "caught raise_exception's exception: #{$!.message}"
end
puts

begin
  puts " クラス名を指定しない場合(rescueでハンドルできず、最後のputsまでたどり着かない)"
  t.raise_exception
rescue
  puts "caught raise_exception's exception: #{$!.message}"
end


puts "exit..."

実行結果:

・StandardExceptionを継承した場合は、rescueでクラス名を指定しなくてもハンドルできる
 クラス名を指定しない場合
caught raise_error's exception: exception message of TestError

・Exceptionを継承した場合は、rescueでクラス名を指定しないとハンドルできない
 クラス名を指定する場合
caught raise_exception's exception: exception message of TestException

 クラス名を指定しない場合(rescueでハンドルできず、最後のputsまでたどり着かない)
./exception.rb:14:in `raise_exception': exception message of TestException (TestException)
        from ./exception.rb:41