有沒有辦法在某個命名空間下解決所有異常?例如,我想拯救所有的Errno :: *異常(Errno :: ECONNRESET,Errno :: ETIMEDOUT)。我可以繼續將它們全部列在我的例外行,但我想知道我是否可以做類似的事情。如何解救某個命名空間下的所有異常?
begin
# my code
rescue Errno
# handle exception
end
以上的想法似乎沒有工作,因此有什麼類似的工作嗎?
有沒有辦法在某個命名空間下解決所有異常?例如,我想拯救所有的Errno :: *異常(Errno :: ECONNRESET,Errno :: ETIMEDOUT)。我可以繼續將它們全部列在我的例外行,但我想知道我是否可以做類似的事情。如何解救某個命名空間下的所有異常?
begin
# my code
rescue Errno
# handle exception
end
以上的想法似乎沒有工作,因此有什麼類似的工作嗎?
所有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
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
「SystemCallError的所有子類都是Errno下的類」並不一定成立。所有Errno異常記錄爲SystemCallErrors,但不保證所有SystemCallErrors都是Errnos。 – 2012-07-12 18:31:27
@ muistooshort不讓我的驗證碼無效嗎?我假設搜索'ObjectSpace'就足以發現未記錄的類。除非一些內置的ruby庫增加了更多的子類。 – Kelvin 2012-07-12 18:33:57
問題是「This returns'true' for me」part,尤其是* for me *。一個gem(甚至應用程序本身)可以提供一個不屬於Errno的SystemCallError的子類。 – 2012-07-12 19:27:39
這裏是一個更通用的解決方案,在情況下,你想救出一些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>"
我想這比執行需要檢查異常的名稱的解決方案略勝一籌。
這是另一個有趣的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我從來不知道你可以通過一個lambda作爲異常匹配器 – Kelvin 2014-08-12 19:23:53
'救援條款(TypeError)所需的類或模塊'看起來不起作用? – 2014-12-06 09:54:44
有趣的,因爲它在寫作時已經爲我工作。如果你檢查我提到的來源,你可以看到這不是我的發明,而是爲其他人工作。目前我只能在ruby 1.9.x下運行。另外我的觀點表明它已經爲一些人工作。另外我看到有人聲稱它在2.1.2上工作(https://gist.github.com/panthomakos/1230515#gistcomment-1298427)。我現在很難找到我使用類似的東西,因爲我想知道它是否在默默停止工作。 – akostadinov 2016-07-27 16:24:07
您是否嘗試搶救一切,檢查名稱空間,並重新提高,如果它不是? – 2012-07-12 18:10:59
@dave我主要想知道是否有一個更容易/更清潔的方式來捕捉基於命名空間的例外 – gylaz 2012-07-12 18:38:18
不能,除非有一些共同點,如答案中所示 – 2012-07-12 18:52:20