有没有办法挽救某个命名空间下的所有异常?
例如,我想拯救所有Errno :: *异常(Errno :: ECONNRESET,Errno :: ETIMEDOUT)。我可以继续在我的例外行列出所有内容,但我想知道我是否可以做类似的事情。
begin
# my code
rescue Errno
# handle exception
end
上述想法似乎不起作用,因此有类似的东西能起作用吗?
答案 0 :(得分:28)
所有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
答案 1 :(得分: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
答案 2 :(得分: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
请参阅原始站点以获取ruby 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
如果有人知道ruby在rescue
删除lambda支持的时间,请发表评论。
答案 3 :(得分: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>"
我猜这会比需要检查异常名称的解决方案稍微好一些。