2007年6月12日星期二

搬家~~~~~~~~~~~~`

鉴于blogspot的不稳定性, 决定搬家到javaeye...........

2007年6月5日星期二

Class Object的class方法

运行下面的代码片段,我们可以看到,所有class方法的返回值都是一样的.

puts TT.class.object_id #-605661568
puts Array.class.object_id #-605661568
puts Object.class.object_id #-605661568
class Example
puts self.class.object_id #-605661568
end

由此可以得出一个结论,ruby中所有Class object(top level的main除外)的class方法返回的都是同一个Class Object, 也就是Class。 这和class初始化的过程有些关系,在Ruby里面,一个新的Class的创建过程同常是这样的:

rb_eval/rb_define_class
-> rb_define_class_id
-> rb_class_new
-> rb_class_boot

除了rb_eval在eval.rb,其余方法都在class.rb中。过程看似复杂(4步),其实主要的部分都在最后一步,也就是rb_class_boot中。我们来看一下,它的定义

VALUE
rb_class_boot(super)
VALUE super;
{
NEWOBJ(klass, struct RClass);
OBJSETUP(klass, rb_cClass, T_CLASS);

klass->super = super;
klass->iv_tbl = 0;
klass->m_tbl = 0; /* safe GC */
klass->m_tbl = st_init_numtable();

OBJ_INFECT(klass, super);
return (VALUE)klass;
}

可以看出来,在OBJSETUP中,(所有)新的class object的klass变量被设置为rb_cClass

OBJSETUP(klass, rb_cClass, T_CLASS);

#define OBJSETUP(obj,c,t) do {\
RBASIC(obj)->flags = (t);\
RBASIC(obj)->klass = (c);\
if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\
} while (0)

而rb_cClass正是ruby的三个基本类(Object, Module, Class)之一, 其初始化过程可以在object.c中找到

那么,根据ruby的这个特性,我们可以发现一个有意思的sleight,为所有的类添加类方法:
proc = lambda {|arg| puts "class method for all classes: #{arg}"}
Object.class.send :define_method, "methodA", proc
Array.methodA "test"

output: class method for all classes: test