Module.autoload not working as expected - Ruby

Viewed 112

I'm trying to practice using the autoload function in a Ruby module. I have two modules A and B. I want to load module B in A's namespace but I'm getting an uninitialized constant error. Both files are in the same folder. Here is my code:

a.rb

module A

end
A.autoload(:B, "./b.rb")
A::B.test #this line causes the error. 

b.rb

module B
    def self.test
        puts "test called"
    end
end

Error:

Traceback (most recent call last):
a.rb:7:in `<main>': uninitialized constant A::B (NameError)
Did you mean?  A::B
               B
1 Answers

It's because you need to namespace the module B inside module A:

# b.rb
module A
  module B
    def self.test
      puts "test called"
    end
  end
end

With this code, ruby a.rb will work as expected.

Oddly, your currently code actually does load the B file, but only after raising an error for trying to access the nonexistent A::B. Let me explain:

  1. You register the A.autoload(:B, "./b.rb")
  2. You call A::B - this performs the autoload to obtain B (at the toplevel) but then afterwards tries to evaluate A::B, which fails because of the way you've defined B.

For example, see what happens if you keep b.rb as what you originally had, and change a.rb to the following (which I don't recommend, I'm just explaining the behavior):

module A
end

A.autoload(:B, "./b.rb")

begin
  A::B.test # This errors, but still performs the autoload
rescue NameError
end

B.test # this works because of the autoload
Related