23

特定の名前空間ですべての例外を救済する方法はありますか?

たとえば、すべての Errno::* 例外 (Errno::ECONNRESET、Errno::ETIMEDOUT) をレスキューしたいと考えています。先に進んで例外行にすべてリストすることができますが、次のようなことができるかどうか疑問に思っていました.

begin
  # my code
rescue Errno
  # handle exception
end

上記のアイデアは機能していないようですが、同様に機能するものはありますか?

4

4 に答える 4

29

すべてのErrno例外サブクラスSystemCallError:

ModuleErrnoは、これらのオペレーティング システム エラーを Ruby クラスにマップするために動的に作成され、各エラー番号は の独自のサブクラスを生成しますSystemCallError。サブクラスがモジュールで作成されるとErrno、その名前が始まりErrno::ます。

SystemCallErrorしたがって、トラップしてから簡単な名前チェックを行うことができます。

rescue SystemCallError => e
  raise e if(e.class.name.start_with?('Errno::'))
  # do your thing...
end
于 2012-07-12T18:30:07.413 に答える
3

Errno の下のすべてのクラスは、SystemCallError のサブクラスです。また、SystemCallError のすべてのサブクラスは、Errno の下のクラスです。2 つのセットは同じなので、SystemCallError をレスキューするだけです。これは、一方に追加され、他方には追加されない外部ライブラリを使用していないことを前提としています。

2 つのセットの ID を確認します (active_support を使用):

Errno.constants.map {|name|
  Errno.const_get(name)
}.select{|const|
  Class === const
}.uniq.map(&:to_s).sort ==
    SystemCallError.subclasses.map(&:to_s).sort

これは私に返っtrueてきます。

したがって、あなたの例に適用されます:

begin
  # my code
rescue SystemCallError
  # handle exception
end
于 2012-07-12T18:25:47.977 に答える
2

いくつかの Errno タイプをレスキューし、他のタイプをレスキューしたくない場合の、より一般的な解決策を次に示します。

レスキューしたいすべてのエラー クラスに含まれるカスタム モジュールを作成します。

module MyErrnoModule; end

"each" 呼び出しまで、この配列を好みに合わせてカスタマイズします。

Errno.constants.map {|name|
  Errno.const_get(name)
}.select{|const|
  Class === const
}.uniq.each {|klass|
  klass.class_eval {
    include MyErrnoModule
  }
}

テスト:

begin
  raise Errno::EPERM
rescue MyErrnoModule
  p "rescued #{$!.inspect}"
end

テスト結果:

"rescued #<Errno::EPERM: Operation not permitted>"

これは、例外の名前を確認する必要があるソリューションよりもわずかに優れていると思います。

于 2012-07-12T18:43:58.007 に答える