关于ruby:如何在rescue子句中修改异常消息?

How do I modify the exception message in a rescue clause?

在下文中,['a', nil, 'c']上的迭代将在nil处失败,因为您无法执行nil + 'd'。 我想拯救该消息,修改它,并将其传递给另一个存储错误的方法。

1
2
3
4
5
6
7
8
9
10
number = 0
begin
  ['a', nil, 'c'].each_with_index do |entry, i|
    entry + 'd'
    number = i
  end
rescue => e
  e.message="#{e.message} (happened at entry: #{number})"
  store_exception(e)
end

问题是,方法message=不存在。 我该怎么做?


您可以创建自定义异常并将其用作代理对象

1
2
3
4
5
6
7
8
9
10
11
12
class ProxyException < StandardError; end

number = 0
begin
  ['a', nil, 'c'].each_with_index do |entry, i|
    entry + 'd'
    number = i
  end
rescue => e
  e = ProxyException.new"#{e.message} (happened at entry: #{number})"
  store_exception(e)
end


答案基于@ fl00r答案,但略微更"花哨":

1
2
3
4
5
6
7
8
9
10
11
12
13
class ProxyException < BasicObject
  def initialize(exception, message=nil)
    @exception, @message = exception, message
  end

  def message
    @message || @exception.message
  end

  def method_missing(method_name, *args, &block)
    @exception.public_send(method_name, *args, &block)
  end
end

那简单地说:

1
2
3
4
5
6
7
8
9
10
number = 0
begin
  ['a', nil, 'c'].each_with_index do |entry, i|
    entry + 'd'
    number = i
  end
rescue => e
  e = ProxyException.new e,"#{e.message} (happened at entry: #{number})"
  store_exception(e)
end

ProxyException完全不可见,因为它将所有方法(包括classobject_id)委托给异常对象,因此它保留异常类和回溯。


通常,您不应该对EXPECTED环境使用异常(问问自己:如果删除所有异常处理代码,我的代码是否会起作用?)。 这是一个预期的情况,您可以通过在将数组传递给each_with_index之前调用compact来轻松避免:

1
['a', nil, 'c'].compact #=> ["a","c"]