`binding` does not capture block
@eregon Continuing from https://github.com/rails/sdoc/pull/314#issuecomment-1744589304...
Here is a reproduction stripped down from https://github.com/rails/sdoc/pull/314:
require "erb"
def render(template_string)
ERB.new(template_string).result(binding)
end
render("<%= yield %>") { "x" }
The original test failure (before I added the workaround) was due to ERB#result raising LocalJumpError: no block given (yield). The tests all pass on CRuby >= 2.7.
Thank you for the report. It can be simplified to just:
def render
eval('yield', binding)
end
p render { "x" }
If we look at the stacktrace with eval('puts caller(0)', binding):
(eval):1:in `render' # block available here
bind.rb:2:in `eval'
bind.rb:2:in `render' # block passed here
bind.rb:5:in `<main>'
So the eval is treated like a block inside render.
So there is probably an issue where we don't correctly look for the surrounding block with eval.
FWIW, somewhat related: https://bugs.ruby-lang.org/issues/15554
warning: use yield in eval will not be supported in Ruby 3.
(although that's not the exact warning on CRuby master)