Ruby 常量查找并不是简单的从继承链继承,总的来说,常量查找根据以下三个规则来:
- 
    查找当前环境的 Module.nesting, 这会是一个模块(类也是模块)的数组。
- 
    如果 #1 找不到,且 Module.nesting.first是一个类,那么查找Module.nesting.first.ancestors
- 
    如果 #1 和 #2 都找不到, 那么查找 Object.ancestors[Object, Kernel, BasicObject]
虽然规则很简单明了,但是还是有很多需要说的:
- 
    前缀式的模块嵌套,并不会计入 Module.nesting里, 比如:module A; B = 10; end module A::C puts Module.nesting # [A::C] puts B # uninitialized constant A::C::B end如果把换成一下格式就OK了 module A; B = 10; end module A module C puts Module.nesting # [A::C, A] puts B # 10 end end
- 
    关于规则2,一个常见的错误是认为,在ancestors里查找是从self.class开始, 正确的是从 Module.nesting.first.ancestors.first开始:class A def get_c; puts self #b puts self.class #B puts Module.nesting.first.ancestors.first #A puts C; #uninitialized constant A::C end end class B < A C = 10 end b = B.new b.get_c这个例子说明 puts C是查找的A::C(Module.nesting.first.ancestors.first) 而不是B::C(self.class)
- 
    在顶层 Module.nesting 为空,顶层的常量定义和查找是在Object里 
- 
    class_eval, module_eval, instance_eval, define_method不会改变Module.nesting, 也就不会改变常量查找
- 
    在本体类里查找常量,并不会查到这个原类的继承链,因为本体类的继承链是从Class开始的: class A B = 10 end class C < A class << C puts Module.nesting # [#<Class>, C] puts ancestors # 1.9.3 [Class, Module, Object, Kernel, BasicObject] # 2.1.1 [#<Class:C> #<Class:A> #<Class:Object> #<Class:BasicObject> Class Module Object Kernel BasicObject] puts B # uninitialized constant Class::B end end这是一个很常见的错误,以为puts B 应该输出A::B 
其他:
- Module#constants返回module的所有第一层级常量
- Module#constants返回所有顶级常量
参考资料
Everything you ever wanted to know about constant lookup in Ruby
