2016-08-29 125 views
0

我正在嘗試創建類似於Rails assert_difference的minitest斷言,但它檢查的不僅僅是數字差異。訪問Ruby中方法調用的塊範圍內的變量

這是我目前的執行:

Minitest::Assertions.module_eval do 

    def assert_changed(expression, &block) 
    unless expression.respond_to?(:call) 
     expression = lambda{ eval(expression, block.binding) } 
    end 
    old = expression.call 
    block.call 
    refute_equal old, expression.call 
    end 

end 
在我的測試套件

現在我做叫它如下:

# this is working 
username = 'Jim' 
assert_changed lambda{ username } do 
    username = 'Bob' 
end 

# this is not working 
username = 'Jim' 
assert_changed 'username' do 
    username = 'Bob' 
end 

第一次調用assert_changed使用Lambda(或PROC)工作得很好。使用帶變量名稱的字符串的第二次調用不起作用。

當它碰上這條線:expression = lambda{ eval(expression, block.binding) } 我不斷收到錯誤TypeError: no implicit conversion of Proc into String。有人可以向我解釋如何讓這個工作?

注意:我從Rails的assert_difference方法中得到了eval(expression, block.binding)的想法。

+0

雖然我沒有看到你在你的問題中這樣做,但確實看起來像你試圖評估一個被捕獲的塊時得到的錯誤。 –

+1

我想這是因爲你重新定義了變量*表達式*,然後在lambda中使用 –

回答

1

當它碰到這條線:expression = lambda{ eval(expression, block.binding) }我不斷收到錯誤TypeError: no implicit conversion of Proc into String

我有理由相信,你得到這個錯誤擊中該行而是擊打時,當這一個:

old = expression.call 

所以,異常沒有被分配引發的,但稍後,當Proccall ed和eval得到執行。

此時,它會調用Proc存儲在expression中。存儲在expressionProc看起來是這樣的:

eval(expression, block.binding) 

的第一個參數Kernel#eval必須的東西是隱式轉換爲String(即東西,響應to_str),但它是一個Proc。埃爾戈,你得到一個TypeError

,使這項工作很可能是隻重命名變量最簡單的方法:

new_expression = expression 
unless expression.respond_to?(:call) 
    new_expression = lambda{ eval(expression, block.binding) } 
end 
old = new_expression.call 
block.call 
refute_equal old, new_expression.call 

個人而言,我可能已經寫它更像是這樣的:

module Minitest::Assertions 
    def assert_changed(expression, &block) 
    new_expression = if expression.respond_to?(:call) 
     expression 
    else 
     -> { block.binding.eval(expression) } 
    end 

    old = new_expression.() 
    block.() 

    refute_equal old, new_expression.() 
    end 
end 

沒有(無用)Module#module_eval,並使用call運算符語法和-> stabby lambda文字語法。

+0

謝謝你解釋這個問題相當好。當錯誤指向不同的行時,它向我投擲了一個循環。 –