2012-07-12 9 views
18

特定の名前空間ですべての例外を救済する方法はありますか?特定の名前空間ですべての例外を救済するにはどうすればよいですか?

たとえば、すべてのErrno :: *例外(Errno :: ECONNRESET、Errno :: ETIMEDOUT)を救いたいです。私は先に進んで例外ラインでそれらをすべてリストアップすることができますが、私は私のようなことをすることができるかどうか疑問に思っていました。

begin 
    # my code 
rescue Errno 
    # handle exception 
end 

上記の考えはうまくいかないと思われますので、同様のことができますか?

+0

名前空間を確認して、それが再現されていないかどうかを確認しましたか? –

+0

@dave私は主に、名前空間に基づく例外 – gylaz

+0

答えに示されているような共通点がある場合を除いて、いいえ –

答えて

24

すべてErrno exceptions subclass SystemCallError:各エラー番号は、独自の生成とErrnoは、Rubyのクラスにこれらのオペレーティングシステムエラーをマップするために動的に作成され

モジュール、サブクラスはSystemCallErrorです。モジュールErrnoにサブクラスが作成されると、その名前はErrno::から始まります。その後、

ですから、トラップSystemCallError可能性とは、単純な名前のチェックを実行します。ここでは

rescue SystemCallError => e 
    raise e if(e.class.name.start_with?('Errno::')) 
    # do your thing... 
end 
3

Errnoの下にあるすべてのクラスは、SystemCallErrorのサブクラスです。 SystemCallErrorのすべてのサブクラスは、Errnoのクラスです。 2つのセットは同一なので、SystemCallErrorを救済するだけです。これは、外部ライブラリを使用していないことを前提としています。

は2セット(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 
+0

"SystemCallErrorのすべてのサブクラスがErrnoのクラスです"が必ずしも成立しません。すべてのErrno例外はSystemCallErrorsであると文書化されていますが、すべてのSystemCallErrorsがErrnosになるという保証はありません。 –

+0

@muistooshortは私の認証コードが正しく機能しないのですか?私は、 'ObjectSpace'を検索することは、文書化されていないクラスを発見するのに十分であると考えています。組み込みのruby libにいくつかのサブクラスが追加されていない限り。 – Kelvin

+0

問題は「これは私のために「真実」を返します。特に私にとっては*です。宝石(またはアプリケーション自体)は、ErrnoではないSystemCallErrorのサブクラスを提供することができます。 –

1

をあなたには、いくつかのerrnoタイプではなく他の人を救出したい場合には、より一般的なソリューションです。

我々は

module MyErrnoModule; end 

を救出するすべてのエラークラスによって含まれるカスタムモジュールを作成してアップ「各」コールに、自分の好みに合わせて、この配列をカスタマイズします。

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>" 

私は、これは例外の名前をチェックする必要があるソリューションよりもわずかに良好に機能すると思います。

3

もう1つ興味深いのはalternativeです。あなたが望むものに適応することができます。

貼り最も興味深い部分:

def match_message(regexp) 
    lambda{ |error| regexp === error.message } 
end 

begin 
    raise StandardError, "Error message about a socket." 
rescue match_message(/socket/) => error 
    puts "Error #{error} matches /socket/; ignored." 
end 

はルビー1.8.7解決のために元のサイトを参照してください。

最近のルビーバージョンではラムダが受け入れられません。オプションは1.8.7で働いていたものを使用することですが、それはすべての比較で新しいクラスを作成するために遅くIM(だと思われるので、私はそれを使用することはお勧めしませんともそれを試していない:。

def exceptions_matching(&block) 
    Class.new do 
    def self.===(other) 
     @block.call(other) 
    end 
    end.tap do |c| 
    c.instance_variable_set(:@block, block) 
    end 
end 

begin 
    raise "FOOBAR: We're all doomed!" 
rescue exceptions_matching { |e| e.message =~ /^FOOBAR/ } 
    puts "rescued!" 
end 

場合誰かがルビーがラムダサポートを削除したときを知っていますrescue

+1

+1 lambdaを例外マッチャーとして渡すことができませんでした – Kelvin

+1

'レスキュー句(TypeError)'に必要なクラスまたはモジュールが動作しないように見えますか? –

+0

執筆の時点で私のために働いたので面白いです。私が言及したソースをチェックすると、それが私の発明ではなく、他の人のために働いていたことが分かります。現在、私はそれをruby 1.9.xの下でしか動かすことができません。また、私のupvotesはそれがいくつかの人々のために働いていることを示しています。また、2.1.2(https://gist.github.com/panthomakos/1230515#gistcomment-1298427)で動作すると主張する人もいます。私は黙って仕事が止まったかどうか疑問に思っているので、今どこで何か似たようなものを使ったところを見つけるのは難しい時があります – akostadinov

関連する問題