23

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

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

begin
  # my code
rescue Errno
  # handle exception
end

上面的想法似乎不起作用,因此有类似的东西可以起作用吗?

4

4 回答 4

29

所有Errno异常子类SystemCallError

动态创建模块Errno以将这些操作系统错误映射到 Ruby 类,每个错误号生成自己的SystemCallError. 由于子类是在模块中创建的Errno,它的名称将开始Errno::

所以你可以陷阱SystemCallError然后做一个简单的名字检查:

rescue SystemCallError => e
  raise e if(e.class.name.start_with?('Errno::'))
  # do your thing...
end
于 2012-07-12T18:30:07.413 回答
4

这是另一个有趣的选择。可以适应你想要的。

粘贴最有趣的部分:

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​​ 何时删除了 lambda 支持,rescue请发表评论。

于 2014-08-11T19:29:55.343 回答
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
于 2012-07-12T18:25:47.977 回答
2

这是一个更通用的解决方案,如果您想拯救一些 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>"

我猜这比需要检查异常名称的解决方案性能略好。

于 2012-07-12T18:43:58.007 回答