Ruby provides a method, eval that accepts a string and evaluates it as Ruby code, returning the result. Since all Ruby code is evaluated in the context of an object, what is self for eval? ...

Ruby provides a method, eval that accepts a string and evaluates it as Ruby code, returning the result. Since all Ruby code is evaluated in the context of an object, what is self for eval?


  irb(main):001:0> class A; def eval_self; eval("self"); end; end 
  => nil
  irb(main):002:0> A.new.eval_self 
  => #<A:0x8a0e8>

This experiment shows that self is the current object—the one at the point where eval is called. Usually this is all you need to know, but there are a couple of reasons this could change. For one, eval provides for an optional binding parameter that determines the context in which the code is evaluated.


  irb(main):001:0> class A; def eval_self(binding); eval("self", binding); end; end
  => nil
  irb(main):003:0> A.new.eval_self(binding)
  => main

Here calling eval from within the instance of A returns “main” because the binding object (created by calling the binding method on the second line) was created for irb’s main object. Evaling “self” in this context returns that main object. But what if one object asks another to eval(“self”) directly rather by invoking a method that does so? Normally you wouldn’t encounter this situation because the eval method is private and so can’t be called from another object. Ruby gives us… ways… to get around this though.


  irb(main):001:0> class A; end
  => nil
  irb(main):002:0> A.new.send(:eval, "self")
  => #<A:0x8cec4>

So when I said earlier that self within eval is based on the current object, I was being deliberately vague. A more precise way of stating it would be that self within the context of an eval is the receiver of the eval method. At first I was surprised when I discovered this, but if you think about invoking methods using ”.” to specified a receiver as changing self before the method is called (which is an accurate way to think about it in my experience), then eval behaves just as it should. First the self is set to the receiver of eval, then eval is called and uses the current self as the context for the eval. The fact that the mental model explains the behavior of eval when called on another object makes me happy. :)

Sorry, comments are closed for this article.