如何拯救某个命名空间下的所有异常?

时间:2012-07-12 17:59:04

标签: ruby exception-handling

有没有办法挽救某个命名空间下的所有异常?

例如,我想拯救所有Errno :: *异常(Errno :: ECONNRESET,Errno :: ETIMEDOUT)。我可以继续在我的例外行列出所有内容,但我想知道我是否可以做类似的事情。

begin
  # my code
rescue Errno
  # handle exception
end

上述想法似乎不起作用,因此有类似的东西能起作用吗?

4 个答案:

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

我猜这会比需要检查异常名称的解决方案稍微好一些。