matz 的设计就是要隐藏单键类,这是一种设计原则。但对于要了解元编程的人来说,又必须要透彻了解隐藏类的全部体系关系。我写了一段测试代码(https://github.com/homeway/fulll_ancestors/blob/master/ancestors.rb)
#encoding: utf-8
class Object
def full_ancestors
instance_ancestors << "\n" << eigein_ancestors
end
def instance_ancestors
return "我只是一个对象,不能派生实例,也就没有实例的祖先链。" unless respond_to? :ancestors
return "作为类,若派生实例将产生的祖先链是:[#{ancestors.join(',')}]"
end
def eigein_ancestors
eigeinclass = class << self;self;end
ancestors = [eigeinclass]
modules = eigeinclass.included_modules
x = eigeinclass
while x.superclass do
x = x.superclass
ancestors << x
deleted = []
modules.each do |m|
if x.include? m
unless x.superclass and x.superclass.include? m
ancestors << m
deleted << m
end
end
end
deleted.each do |m|
modules.delete m
end
end
"作为对象,我的实际祖先链是:[#{ancestors.join(',')}]"
end
end
module M; end
class A; end
class B < A; end
A.extend M
puts ''
puts A.full_ancestors
puts B.full_ancestors
那么输出结果大致如下:
作为类,若派生实例将产生的祖先链是:
[A,Object,Kernel,BasicObject]
作为对象,我的实际祖先链是:
[#<Class:A>,#<Class:Object>,#<Class:BasicObject>,Class,Module,Object,Kernel,BasicObject]
作为类,若派生实例将产生的祖先链是:
[B,A,Object,Kernel,BasicObject]
作为对象,我的实际祖先链是:
[#<Class:B>,#<Class:A>,M,#<Class:Object>,#<Class:BasicObject>,Class,Module,Object,Kernel,BasicObject]
Matz 的实现只是过滤掉了#部分的隐藏类,而实际上对象和类在查找方法时,仍将按照上面所输出的实际祖先链顺序来查找。