代码之家  ›  专栏  ›  技术社区  ›  pilcrow

如何确定本地JumpError的来源?

  •  0
  • pilcrow  · 技术社区  · 15 年前

    我如何能够轻松、有计划地确定 LocalJumpError 是由于调用方未能立即为某个方法提供所需的块,还是由于该方法及其调用的其他方法的深层次导致的?

    我的意思是,我想避免在 $!.backtrace . 也优选适用于1.8和1.9的解决方案。

    动机: 当我在Ruby中修改一个方法调用时,通常是因为我输入了错误的方法( NoMethodError )参数个数错误( ArgumentError )或者忽略了通过一个必要的街区( 局部偏振器 )

    对于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
    
    2 回复  |  直到 15 年前
        1
  •  1
  •   sepp2k    15 年前

    要查明localJumpError是否是由用户忘记传递块引起的,您需要知道两件事:用户是否提供了块以及方法是否需要块。第一个很简单:只要检查一下BLK是否为零。第二个是不可能的(至少在纯红宝石中)。

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

        2
  •  0
  •   pilcrow    15 年前

    我们可以检查 相对深度 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——以前的轨迹 发送 ,后者似乎悄悄地忽略了它(ala perl's goto &sub 也许吧?)例如。(在1.9下,Lje回溯是 浅的 caller(0) 堆栈,因为1.9显式计算 rescue 块作为离散堆栈帧)。

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