1

Consider the following Ruby code:

class Foo
  def bar; 42; end
  def run(code1,code2)
    binding.eval(code1,'c1')
    binding.eval(code2,'c2')
  end
end

Foo.new.run "x=bar ; p x", "p x"

The intent is to dynamically evaluate some code—which creates local variables—and then run additional code that has access to those variables. The result is:

c2:1:in `run': undefined local variable or method `x' for #<Foo:…> (NameError)

Note that the above would only work if the eval mutated the binding, which it only does when modifying existing local variables, not creating new variables. I do not necessarily need (or want) each run to mutate the outer binding, I just need to be able to access the previous binding for subsequent code evaluations.

How can I eval two blocks of code and maintain local variables between them?


For the curious, the real-world application of this is a custom tool that can execute a script file and then drop into a REPL. I want the REPL to have access to all local variables created by the script file.

1 Answer 1

2

You need to store the Binding and re-use the same one. If you call binding repeatedly—even in the same scope—you will get a new binding. So, for the demo function, we can do this:

class Foo
  def initialize; @b = binding; end
  def bar; 42; end
  def run(code)
    @b.eval( code, '(yourcode)' )
  end
end

f = Foo.new
f.run "x=bar ; p x"  #=> 42
f.run "p x"          #=> 42
Sign up to request clarification or add additional context in comments.

4 Comments

(@binding ||= binding).eval(code, '(yourcode)') in the method body works for me - just a bit simpler.
@August Interesting! That helps a lot. So calling binding creates a new binding each time; as long as I create a single Binding and store it, there is no reason to return the binding. Thanks!
@August I have edited my answer to incorporate your feedback. If you wanted to post as your own answer I would be happy to revert my change and upvote (and possibly accept) your answer.
You can keep it in your answer :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.