mvgijssel
mvgijssel

Reputation: 33

Autoloading classes using class << self in Rails

I have the following 3 files:

test.rb

# doesn't work, raises error: NameError: uninitialized constant Baz
Foo::Bar.do_stuff_1

# does work
Foo::Bar.do_stuff_2

# does work
Foo::Bar.new.do_stuff_3

bar.rb

module Foo   
  class Bar    
    class << self    
      def do_stuff_1

        puts "class level: #{Baz.new.class}"

      end    
    end

    def self.do_stuff_2

      puts "class level: #{Baz.new.class}"

    end

    def do_stuff_3

      puts "Instance level: #{Baz.new.class}"

    end    
  end    
end

baz.rb

module Foo    
  class Baz   
    def initialize

    end    
  end    
end

The do_stuff_1 method raises an exception, NameError: uninitialized constant Baz, while the other methods are executing normally. I think it has something to do with class << self ... end adjusting the metaclass and def self.method ... end adjusting the class itself.

I would like to know if there is way to make class << self ... end autoload the Baz class appropriately like def self.method ... end.

I'm using Rails 4.0.2, Ruby 2.0.0 and I'm autoloading the classes using application.rb.

Upvotes: 3

Views: 322

Answers (1)

Peter Alfvin
Peter Alfvin

Reputation: 29419

This isn't an autoload problem per se, but rather a matter of namescopes. In the case of the first method, you're in the singleton class of Bar, so you need to reference Baz as Foo::Baz.

If you wanted to reference Foo::Baz from that context without using the name Foo, you use any expression that evaluates to Foo in that context, such as Module.nesting[2], as in:

puts "class level: #{Module.nesting[2]::Baz.new.class}"}

Upvotes: 1

Related Questions