Здесь:
expr = expr.respond_to?(:call) ? expr : ->{ eval(expr) }
В результате вы получите Proc в expr
, который является закрытием над expr
, поэтому, когда Proc оценивается, он пытается eval
сам, потому что expr
внутри лямбды находится сама лямбда.
Здесь:
foo = expr
expr = expr.respond_to?(:call) ? expr : ->{ eval(foo) }
замыкание превышает foo
, что относится к исходному строковому значению expr
, поэтому нетПричудливая путаница с ссылками на себя, и вы в конечном итоге будете использовать eval
в строке.