Chris911
Chris911

Reputation: 4199

Accessing constant in nested module

I'm having trouble accessing a module constant in a nested module. Here's the code:

outer.rb

require 'inner.rb'

module Outer
  BASE_DIR = "cache/"
end

inner.rb

module Outer
  module Inner
    puts BASE_DIR
  end
end

If I run the code in inner.rb I get the following error:

<module:Inner>': uninitialized constant Outer::Inner::BASE_DIR (NameError)

I thought that since BASE_DIR is declared in the outer module is should also be accessible in the inner module and it does not seem to be the case.

Upvotes: 0

Views: 578

Answers (2)

Patrick Oscity
Patrick Oscity

Reputation: 54684

It is a question of load order. Replacing the require with the actual code required reveals that your code is loaded in this order:

module Outer
  module Inner
    puts BASE_DIR
  end
end

module Outer
  BASE_DIR = "cache/"
end

Now it is pretty easy to see why that cannot work. As the error message suggests, the constant simply is not defined at the time when you try to access it. This happens because every piece of code that is not inside a method definition will be executed immediately. Accessing the constant from a method is however possible:

module Outer
  module Inner
    def self.foo
      puts BASE_DIR
    end
  end
end

module Outer
  BASE_DIR = "cache/"
end

Outer::Inner.foo
# cache/

There are several possible solutions, depending on your needs:

  • eliminate the use of the constant outside methods (may not be an option)
  • change load order (put the require at the end of the file)
  • Delegate the storage of global settings to a dedicated class/module

Upvotes: 2

phoet
phoet

Reputation: 18845

no, ruby does not do that. have a look for the ancestor chain that ruby uses to resolve names.

so you will have to use Outer::BASE_DIR instead.

here is a nice talk about the ruby class system and rails auto loading.

Upvotes: 0

Related Questions