【问题标题】:How to determine the origin of a LocalJumpError?如何确定 LocalJumpError 的来源?
【发布时间】:2009-09-18 04:41:49
【问题描述】:

我如何以编程方式轻松地确定 LocalJumpError 是由调用者立即未能向方法提供所需块引起的,还是来自该方法及其调用的其他方法的更深层次?

“轻松地”是指我想避免$!.backtrace 上的字符串检查/正则表达式。适用于 1.8 和 1.9 的解决方案也是首选。

动机:当我在 ruby​​ 中搞砸了一个方法调用时,通常是因为我输入了错误的方法 (NoMethodError)、输入了错误的参数数量 (ArgumentError) 或忽略了传递必要的块(LocalJumpError)。

对于 ruby​​ 中的代理或装饰包装对象,我想将这些 调用程序或 API 错误与可能引发相同类的 实现程序或环境错误区分开来的错误。例如:

...
def method_missing(sym, *args, &block)
  @wrapped.__send__(sym, *args, &block)
rescue NoMethodError
  raise MyApp::BadInvocation, "duh - no such method" unless @wrapped.respond_to?(sym)
  raise
rescue ArgumentError
  raise MyApp::BadInvocation, "duh - wrong arg count" \
    unless _args_fit_arity?(@wrapped.method(sym), args)
  raise
rescue LocalJumpError
  # XXX - what is the test?
  raise
end

【问题讨论】:

    标签: ruby proxy decorator


    【解决方案1】:

    要判断LocalJumpError是否是由于用户忘记传递block导致的,你需要知道两件事:用户是否提供了block,方法是否需要block。第一个很简单:只需检查 blk 是否为 nil。然而,第二个是不可能的(至少在普通的红宝石中)。

    所以我想解析堆栈跟踪是你最好的选择。

    【讨论】:

    • +1 我没有想到要检查是否实际提供了一个块。 (但仍然不喜欢解析回溯本身。)
    • @sepp2k,我想我找到了更好的选择......稍后会发布。
    • @sepp2k,我认为我赢得了严格的准确性,但你赢得了简单,这是一个更好的标准。 :)
    【解决方案2】:

    人们可以检查 backtrace 的相对深度,以尽最大努力将调用者错误与调用堆栈中更深的后续错误区分开来:

    def lje_depth_from_send
      Class.new { def lje; yield end }.new.__send__ :lje
    rescue LocalJumpError
      return $!.backtrace.size - caller(0).size
    end
    
    def method_missing(sym, *args, &block)
      ...
    rescue LocalJumpError
      if !block_given? and ($!.backtrace.size - caller(0).size) == lje_depth_from_send
        raise MyApp::BadInvocation, "duh - you forgot to supply a block"
      end
      raise
    end
    

    有趣的是,这种相对深度计算从 MRI 1.8 变为 MRI 1.9 —— 前者跟踪 send,后者似乎默默地忽略它(也许是ala perl 的goto &sub?),例如. (在 1.9 下,LJE 回溯比caller(0) 堆栈,因为1.9 明确地将rescue 块计为离散堆栈帧。

    现在,这在非 MRI 下可能不起作用,但我怀疑调用堆栈的解析是否可以从一个实现移植到另一个实现。

    【讨论】:

      猜你喜欢
      • 2011-08-25
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 2022-11-15
      • 1970-01-01
      • 2020-05-21
      相关资源
      最近更新 更多