Reputation: 2213
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
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 :
class B
module F;end
end
class A < B
include F
end
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