The problem you are seeing can be summarized in this snippet:

    module M
    end

    class M::A
      A
    end

If you run that code with plain Ruby you'll get

    uninitialized constant M::A::A (NameError)

Let's see why that's that way in Ruby first, then we will go with
dependencies.rb.

Ruby looks for constants in the nesting, then ancestors, then in Object if
the container module is a module, and fallbacks to const_missing if
present. That's the resolution algorithm quickly described.

OK, the nesting at the point where we evaluate A is [M::A]. The class and
module keywords push to the nesting the module object they are creating or
reopening. That is one module object regardless of the constant or constant
path that yielded it. If the constant path is composed of 15 constants, in
the end it evaluates to one single class or module object, that's the one
pushed to the nesting.

In particular, M does not belong to the nesting.

So Ruby goes like this: A does not belong to M::A (nesting scan done), A
does not belong to any of [Object, Kernel, BasicObject] (ancestors scan
done). Since the containing M::A is a class we do not do the extra Object
check. And finally const_missing is not present. Therefore: NameError.

The key point here is that A belongs to M, and M is not in the nesting.

Now, Active Support is not able to discern whether M belongs or does not
belong to the nesting because Ruby does not tell you in const_missing. AS
assumes the nesting matches the name of the class or module const_missing
was triggered in. In the example about that would be, [M::A, M].

But, when const_missing is triggered dependencies.rb manually checks if the
constant is present in one of those "parent" modules. So, what happens in
Rails is that const_missing is triggered, and dependencies.rb is able to
see that A is defined in M, therefore a posteriori M must not belong to the
nesting because otherwise const_missing had not been triggered in the first
place, and is able to raise a NameError, which is the correct answer.

Constant autoloading in Rails does *not* emulate the constant name
resolution algorithm. But in this case it behaves as Ruby.

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-core?hl=en.

Reply via email to