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 error typeerror: 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 called , 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

Popular posts from this blog

amazon web services - S3 Pre-signed POST validate file type? -

c# - Check Keyboard Input Winforms -