Long story short:
Object.instance_eval &block sets:
Object.class_eval &block sets:
self to Object
- The "current class" to
Object
The "current class" is used for def, undef and alias, as well as constant and class variable lookups.
Now, let's have a look at the implementation details.
Here's how module_eval and instance_eval are implemented in C:
VALUE rb_mod_module_eval(int argc, VALUE *argv, VALUE mod) {
return specific_eval(argc, argv, mod, mod);
}
VALUE rb_obj_instance_eval(int argc, VALUE *argv, VALUE self) {
VALUE klass;
if (SPECIAL_CONST_P(self)) { klass = Qnil; }
else { klass = rb_singleton_class(self); }
return specific_eval(argc, argv, klass, self);
}
Both call specific_eval, which takes the following arguments: int argc, VALUE *argv, VALUE klass and VALUE self.
Note that:
module_eval passes the Module or Class instance as both klass and self
instance_eval passes the object's singleton class as klass
If given a block, specific_eval will call yield_under, which takes the following arguments: VALUE under, VALUE self and VALUE values.
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, Qundef);
}
There are two important lines in yield_under:
block.self = self;
This sets the self of the block to the receiver.
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
The cref is a linked list
which specifies the "current class", which is used for def, undef and alias, as well
as constant and class variable lookups.
That line basically sets the cref to under.
Finally:
When called from module_eval, under will be the Class or Module
instance.
When called from instance_eval, under will be the singleton class of
self.