The problem, in my opinion, is the difference in the level of class inheritance and the number class ( ascii image ). In fact, an object of a class is inherited from object objects. which are viewed.
module A; end p A.ancestors
This means that if the search algorithm algorithm in module A , it cannot exit.
So, in the case of module Post the Post::User search algorithm is something like
- find const
Post (found module Post ) - find const
User in module Post (not found, go to Post ancestors) - dead-end - error
and in case of class Post
- find const
Post (found class Post ) - find const
User in class Post (not found, go to Post ancestors) - find const
User (found class User with warning)
That's why you can bind classes at the same level of the namespace, and ruby ββwill still find them. If you try
class User def self.foo "foo" end end class A1; end class A2; end class Foo p Foo::A1::A2::User.foo end
still good. AND
class User def self.foo "foo1" end end class A1; end module A2; end class Foo p Foo::A1::A2::User.foo end
because the steps of the search algorithm in the module were trapped.
TL DR
class User def self.foo "foo" end end class Post1 Post1.tap{|s| p s.ancestors}::User.foo #=> [Post1, Object, Kernel, BasicObject] end # ok module Post2 Post2.tap{|s| p s.ancestors}::User.foo #=> [Post2] end # error
Update
In this situation, the place when calling Post :: User.foo does not play a big role. It can also be outside the class / module, and the behavior will be the same.
module ModuleA; end class ClassB; end class ClassC; end class E; ModuleA::ClassC; end
And as you indicated
Of course, the ancestors for a module or class are different, but in the case of a module, an additional constant search in Object.ancestors is added.
this happens only at the time of the "initial" search. This means that in the case of
module Post; Post::User.foo; end
const Post will be considered first (here I can make a mistake) Post.ancestors and because there is no Post::Post , continue to find in Object.ancestors (then it will go with the algorithm that I described above).
To summarize , the context in what you called const is relevant only for the first (leftmost) constant search. And then only the object that is being considered remains.
A::B::C A # consider context ::B # consider only A ::C # consider only B