Shinigami
Shinigami

Reputation: 2213

Namespace Confusion in Ruby

I'm playing with Ruby modules.

This works just fine:

module Mod1
  def hello
    "Hello from mod 1"
  end
end

module Mod2
  def hello
    "Hello from mod 2"
  end
end

class Foo
  include Mod1
  include Mod2
end

f = Foo.new
puts f.hello
# output: "Hello from mod 2"

This doesn't work:

module Mod1
  def hello
    "Hello from mod 1"
  end
end

module Mod2
  def hello
    "Hello from mod 2"
  end
end

class Foo < BasicObject
  include Mod1
  include Mod2
end

f = Foo.new
puts f.hello
# output: in `<class:Foo>': uninitialized constant Foo::Mod1 (NameError)

This works:

module Mod1
  def hello
    "Hello from mod 1"
  end
end

module Mod2
  def hello
    "Hello from mod 2"
  end
end

class Foo < BasicObject
  include ::Mod1
  include ::Mod2
end

f = Foo.new
puts f.hello

Can you please explain why?

Upvotes: 2

Views: 105

Answers (1)

Arup Rakshit
Arup Rakshit

Reputation: 118299

In Ruby's Object model, Object is defined underneath the BasicObject. So whatever you will be defining in Object wouldn't be accessible from BasicObject by default.

 Object.superclass # => BasicObject

Now your class Foo is an subclass of BasicObject, so it goes top of the Object class. Thus those modules are not visible to the Foo class. as the modules Mod1 and Mod2 are defined inside the Object class. Anything you will be defining in the top level will go the scope of Object class, that is how Ruby's top level has been defined.

Your last part of code is working as you explicitly has given the constant path as include ::Mod1 and include ::Mod2. ::Mod2 means you are saying the module is defined in Object class, bring it for me here in the class.

But which is not the case for the second part of your code, so Foo is unable to find out the modules, as you didn't give it the path, like the above part.

First part is working, as modules are defined in Object scope and class Foo is a subclass of Object, so only include Mod1 and `include Mod2 does work as expected.

Here is similar use-cases, which might give you some light on this :

no error here

class B 
    module F;end
end

class A < B
    include F
end

error here

class B
  include F
end

class A < B
  module F;end
end
# ~> -:2:in `<class:B>': uninitialized constant B::F (NameError)
# ~>  from -:1:in `<main>'

Upvotes: 4

Related Questions