Ale*_*xey 7 ruby metaprogramming instance-eval class-eval
除了工作class_eval和instance_eval工作有什么不同def吗?内部class_eval块def定义了类本身的方法(即实例方法),内部instance_eval def定义了类的本征类的方法(即类方法).据我所知其他所有功能在这两种情况下(例如相同的工作define_method,attr_accessor,class << self; end,定义常量).这是真的吗?
答案是:def,undef并且alias有不同的背景class_eval和instance_eval.
Mat*_*ira 13
长话短说:
Object.instance_eval &block 集:
self 至 ObjectObject.singleton_classObject.class_eval &block 集:
self 至 ObjectObject"当前级"被用于def,undef并且alias,以及常数和类变量查找.
现在,我们来看看实现细节.
以下是如何module_eval以及instance_eval用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);
}
Run Code Online (Sandbox Code Playgroud)
这两个电话specific_eval,其中采用下列参数:int argc,VALUE *argv,VALUE klass和VALUE self.
注意:
module_eval传递Module或Class实例作为klass 和 selfinstance_eval穿过对象的单例类如klass如果给出一个块,specific_eval将调用yield_under,它接受以下参数:VALUE under,VALUE self和VALUE values.
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, Qundef);
}
Run Code Online (Sandbox Code Playgroud)
有两条重要的路线yield_under:
block.self = self;
这将self块设置为接收器.
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
的cref是一个链表
,其指定了"当前级",其用于def,undef和alias,以及常数和类变量查找.
该线基本上设置cref为under.
最后:
从中调用时module_eval,under将是Class或Module
实例.
当从所谓的instance_eval,under将是单例类的
self.