2016-08-29 127 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

谢谢你解释这个问题相当好。当错误指向不同的行时,它向我投掷了一个循环。 –