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 的实现只是过滤掉了#部分的隐藏类,而实际上对象和类在查找方法时,仍将按照上面所输出的实际祖先链顺序来查找。