我如何能够轻松地以编程方式确定LocalJumpError
是否因呼叫者立即无法向方法提供所需的块,或者从该方法的更深层次以及它调用的其他方式而产生?
通过“轻松”,我的意思是我想避免$!.backtrace
上的字符串检查/ regexen。适用于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
答案 0 :(得分:1)
要确定LocalJumpError是否是由忘记传递块的用户引起的,您需要知道两件事:用户是否提供了块以及该方法是否需要块。第一个很简单:只需检查blk是否为零。然而第二个是不可能的(至少在红宝石中)。
所以我认为解析堆栈跟踪是最好的选择。
答案 1 :(得分:0)
可以检查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的goto &sub
,也许?),例如。 (在1.9下,LJE回溯浅而不是caller(0)
堆栈,因为1.9显式地将rescue
块计为离散堆栈帧。
现在,这可能不适用于非MRI,但我怀疑解析调用堆栈是否可以从一个实现移植到另一个实现。