6

I have the following files:

file.rb

require_relative 'foo/bar'
baz = Foo::Stuff::Baz.new
# do stuff

foo/bar.rb

require_relative 'stuff/baz'
module Foo
    class Bar
        def initialize
            # do stuff
        end
    end
end

foo/stuff/baz.rb

module Foo
    module Stuff
        class Baz < Bar
        end
    end
end

I get the following error:

`': uninitialized constant Foo::Stuff::Bar (NameError)

Is there something I'm doing wrong here? Is this even possible in Ruby? In case it matters, I'm only doing this because I need to inherit the initialize method specifically.

sluther
  • 1,694
  • 20
  • 29

4 Answers4

3

Your foo/stuff/baz.rb does not contain any require statement and you tell nothing about a main programm. So I think you just don't load the code.

Ruby has no automatic loading depending on folder path, you must explicitly load the source code. In your case you need a require_relative '../bar' in the file foo/stuff/baz.rb. Then the class Foo::Bar is known:

require_relative '../bar'

module Foo
    module Stuff
        class Baz < Bar
        end
    end
  end

  p Foo::Stuff::Baz.new
  p Foo::Stuff::Baz.ancestors

The result:

#<Foo::Stuff::Baz:0x00000002ff3c30>
[Foo::Stuff::Baz, Foo::Bar, Object, Kernel, BasicObject]

The initialize-method of Foo::Bar is executed.


A more realistic architecture would be the usage of a main file where you load all code files, e.g.:

foo.rb
foo/bar.rb
foo/stuff/baz.rb

and foo.rb would contain:

require_relative 'foo/bar'
require_relative 'foo/stuff/baz'
knut
  • 27,320
  • 6
  • 84
  • 112
  • I do have the require_relative statements in there, actually. I should have included them in my post. – sluther Jan 06 '17 at 02:59
  • So, if I'm not mistaken, I should have the require_relatives for everything in the main file. I'll give that a shot instead. – sluther Jan 06 '17 at 03:08
  • Thanks, I figured it out. I realized that the problem is the require statement in my foo/bar.rb file. – sluther Jan 06 '17 at 03:15
3

It works just fine when you put them in the same script :

module Foo
  class Bar
    def initialize
      # do stuff
    end
  end
end

module Foo
  module Stuff
    class Baz < Bar
    end
  end
end

p Foo::Stuff::Baz.ancestors
#=> [Foo::Stuff::Baz, Foo::Bar, Object, Kernel, BasicObject]

So it must be a problem with the way or order in which you require your files.

Also, if you just need just one specific method from Foo::Bar in Foo::Stuff::Baz, you could put this method in a module, and include this module in both classes.

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • Yep, you were right. The problem was that I require foo/stuff/baz.rb in foo/bar.rb. I'm marking your answer as the correct one. – sluther Jan 06 '17 at 03:16
1

Foo::Bar is defined. You can also access ::Foo::Bar ("root" module) when there are issues finding the right namespace.

Eric Platon
  • 9,819
  • 6
  • 41
  • 48
0

It does not work because in baz.rb namespace there is no any reference to the Bar class; should simply enter:

class Bar; end

So the baz.rb structure becomes simply have: (foo/stuff/baz.rb)

module Foo
  class Bar; end
  module Stuff
    class Baz < Bar
    end
  end
end
MVP
  • 1,061
  • 10
  • 8