2012-07-12 57 views
18

有沒有辦法在某個命名空間下解決所有異常?例如,我想拯救所有的Errno :: *異常(Errno :: ECONNRESET,Errno :: ETIMEDOUT)。我可以繼續將它們全部列在我的例外行,但我想知道我是否可以做類似的事情。如何解救某個命名空間下的所有異常?

begin 
    # my code 
rescue Errno 
    # handle exception 
end 

以上的想法似乎沒有工作,因此有什麼類似的工作嗎?

+0

您是否嘗試搶救一切,檢查名稱空間,並重新提高,如果它不是? – 2012-07-12 18:10:59

+0

@dave我主要想知道是否有一個更容易/更清潔的方式來捕捉基於命名空間的例外 – gylaz 2012-07-12 18:38:18

+0

不能,除非有一些共同點,如答案中所示 – 2012-07-12 18:52:20

回答

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下的類。這兩套是相同的,所以只需拯救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。 – 2012-07-12 18:31:27

+0

@ muistooshort不讓我的驗證碼無效嗎?我假設搜索'ObjectSpace'就足以發現未記錄的類。除非一些內置的ruby庫增加了更多的子類。 – Kelvin 2012-07-12 18:33:57

+0

問題是「This returns'true' for me」part,尤其是* for me *。一個gem(甚至應用程序本身)可以提供一個不屬於Errno的SystemCallError的子類。 – 2012-07-12 19:27:39

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

這是另一個有趣的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解決原來的網站。

原來lambda不接受我最近的ruby版本。看來選擇是使用什麼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 

如果有人知道,當紅寶石刪除lambda支持rescue請評論。

+1

+1我從來不知道你可以通過一個lambda作爲異常匹配器 – Kelvin 2014-08-12 19:23:53

+1

'救援條款(TypeError)所需的類或模塊'看起來不起作用? – 2014-12-06 09:54:44

+0

有趣的,因爲它在寫作時已經爲我工作。如果你檢查我提到的來源,你可以看到這不是我的發明,而是爲其他人工作。目前我只能在ruby 1.9.x下運行。另外我的觀點表明它已經爲一些人工作。另外我看到有人聲稱它在2.1.2上工作(https://gist.github.com/panthomakos/1230515#gistcomment-1298427)。我現在很難找到我使用類似的東西,因爲我想知道它是否在默默停止工作。 – akostadinov 2016-07-27 16:24:07