Access variable from the block's scope inside a method call in Ruby -
i trying create minitest assertion similiar rails assert_difference
checks differences not numeric one.
here current implementation:
minitest::assertions.module_eval 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
now in test suite call doing following:
# working username = 'jim' assert_changed lambda{ username } username = 'bob' end # not working username = 'jim' assert_changed 'username' username = 'bob' end
the first call assert_changed
using lambda (or proc) works fine. second call using string variable name not working.
when hits line: expression = lambda{ eval(expression, block.binding) }
keep getting error typeerror: no implicit conversion of proc string
. can please explain me how work?
note: got eval(expression, block.binding)
idea rails assert_difference
method.
when hits line:
expression = lambda{ eval(expression, block.binding) }
keep getting errortypeerror: no implicit conversion of proc string
.
i'm reasonably sure not error when hitting line rather when hitting one:
old = expression.call
so, exception not triggered assignment, rather later, when proc
call
ed , eval
gets executed.
at point, call proc
stored in expression
. proc
stored in expression
looks this:
eval(expression, block.binding)
the first argument kernel#eval
must implicitly convertible string
(i.e. responds to_str
), proc
. ergo, typeerror
.
the easiest way make work rename variable:
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
personally, have written more this:
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
without (useless) module#module_eval
, , using call
operator syntax , ->
stabby lambda literal syntax.
Comments
Post a Comment