2011-07-08 45 views
4

我想寫一個版本的assert_difference將接受一個哈希作爲參數,這樣,而不是寫如何用ruby中的給定綁定創建塊?

assert_difference 'thing1', 1 do 
    assert_difference ['thing2a', 'thing2b'], 2 do 
    assert_difference 'thing3', -3 do 
     # some triple-indented code 
    end 
    end 
end 

我可以寫

assert_difference 'thing1' => 1, ['thing2a', 'thing2b'] => 2, 'thing3' => 3 do 
    # some single-indented code 
end 

我得儘可能

def assert_difference_with_hash_support(expression, difference = 1, message = nil, &block) 
    if expression.is_a? Hash 
    expression.each do |expr, diff| 
     block = lambda do 
     assert_difference_without_hash_support expr, diff, &block 
     end 
    end 
    block.call 
    else 
    assert_difference_without_hash_support(expression, difference, message, &block) 
    end 
end 
alias_method_chain :assert_difference, :hash_support 

但這不起作用,因爲assert_difference在評估表達式時使用了塊的綁定。我想要做的是創造與原來綁定一個新的塊 - 像這樣:

b = block.send :binding 
    expression.each do |expr, diff| 
     block = lambda(b) do 
     assert_difference_without_hash_support expr, diff, &block 
     end 
    end 
    block.call 

,但我還沒有看到創建比當前綁定以外的任何新區塊的方式。如何使用給定的綁定創建塊?

回答

2

也許我錯過了一些東西,但我認爲你正在嘗試使用非常複雜的ruby特性,而它們對於解決你的問題是不必要的。

我的解決辦法是:

def assert_hash(hash, &block) 
    if hash.length > 1 
    assert_difference(*hash.shift) do 
     assert_hash(hash, &block) 
    end 
    else 
    assert_difference(*hash.first, &block) 
    end 
end 

當然它缺少走樣,但是這不是問題的關鍵。

編輯:

與自定義綁定創建塊的答案是:沒有。但是你可以調用具有不同綁定的代碼塊,或者通過binding方法捕獲代碼,或者僅通過提供具有綁定相關的對象。

既可以使用eval用於此目的(它接受綁定對象作爲第二個參數)或更好instance_evalclass_evalinstance_execclass_exec。您可以開始挖掘Jay Fields' Thoughts blog entry

相關問題