2009-09-18 42 views
0

如何輕鬆地並以編程方式確定LocalJumpError是由調用者立即失敗而產生的,該方法是否爲方法提供了所需的塊,或者來自該方法的更深層和調用的其他方法的深層?如何確定LocalJumpError的來源?

「容易」,我的意思是我想避免字符串檢查/ regexen在$!.backtrace。適用於1.8和1.9的解決方案也是優選的。

動機:當我把事情弄糟在紅寶石的方法調用,通常是因爲我輸入了錯誤的方法(NoMethodError),得到的參數錯誤(ArgumentError)或忽視傳遞一個必要的塊(LocalJumpError)的數量。

對於紅寶石代理或裝飾包裝對象,我想從實施者或環境錯誤可以提高錯誤的同一類別區分這些主叫或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 

回答

1

要找出是否LocalJumpError被用戶遺忘傳遞塊造成的,你需要知道兩件事情:無論用戶提供的塊和方法是否需要一個塊。第一個很簡單:只要檢查blk是否爲零。然而,第二個是不可能的(至少在普通的紅寶石中)。

所以我想解析堆棧跟蹤是你最好的選擇。

+0

+1我沒有想過檢查塊是否實際提供。 (不過,不喜歡解析回溯*本身*) – pilcrow 2009-09-18 14:33:17

+0

@ sepp2k,我想我發現了一個更好的選擇......稍後會發布。 – pilcrow 2009-09-19 02:40:35

+0

@ sepp2k,我認爲我贏得了嚴格的準確性,但是爲了簡單起見,這是一個更好的標準。 :) – pilcrow 2009-09-24 13:53:00

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這個相對深度計算的變化到磁共振成像1.9 - 前軌跡發送,後者似乎默默地省略它(阿拉貝爾的goto &sub,也許?),例如。 (低於1.9,LJE回溯爲caller(0)堆棧更淺,因爲1.9明確將rescue塊計爲離散堆棧幀)。

現在,這可能無法在非MRI下工作,但我懷疑調用堆棧的解析也可以從一個實現移植到另一個。