Reputation: 1169
I've been reading this Ruby book, then there's this example that I haven't well understood :
CONST = "outer"
module Mod
CONST = 1
def Mod.method1
# module method
CONST + 1
end
end
module Mod::Inner
def (Mod::Inner).method2
CONST + " scope"
end
end
Mod::CONST # => 1
Mod.method1 # => 2
Mod::Inner::method2 # => "outer scope"
Would you please explain this to me (a detailed explanation) so I can fully understand how the scope works in Ruby. Thank you.
Upvotes: 1
Views: 230
Reputation: 9762
You would find a good explanation on Ruby Constant lookup here
I would share code snippets with some explanation:
CONST = "outer"
module Mod
CONST = 1
def Mod.method1
# module method
Module.nesting # => [Mod]
CONST + 1
end
end
module Mod::Inner
def (Mod::Inner).method2
Module.nesting # => [Mod::Inner]
CONST + " scope"
end
end
Mod::CONST # => 1
Mod.method1 # => 2
Mod::Inner::method2 # => "outer scope"
Have a look at the evaluation of Module.nesting
above (Mod::Inner).method2
looks in Mod::Inner
as specified in the nesting for CONST
which it does not find before it calls the main Object for CONST
In the example I have below, you would see that Mod::Inner.method2
makes a call to Mod::Inner and then Mod to seek for CONST
which it finds, so no need to call the CONST
in Object
module Mod
CONST = 1
def Mod.method1
Module.nesting # => [Mod]
CONST + 1
end
module Inner
def (Mod::Inner).method2
Module.nesting # => [Mod::Inner, Mod]
CONST.to_s + " scope"
end
end
end
Mod::CONST # => 1
Mod.method1 # => 2
Object::CONST # => "outer"
Mod::Inner::method2 # => "1 scope"
When in doubt use nested class/constant definition over lexical, it would always do the right thing as expected
Upvotes: 2
Reputation: 29409
Constants in Ruby (identifiers beginning with a capital letter) are accessible based on the lexical scope in which they are defined/accessed.
In method1
, the CONST
within the Mod
scope takes precedence over the outermost CONST
. In method2
, the CONST
within the Mod
scope is not visible lexically, so the outermost CONST
is accessed.
As for the method definitions themselves, when the name is qualified with a preceding module constant (e.g. Mod
or Mod::Inner
), the method is defined as a "module method" rather than as an instance method of self.class
(the default).
Names in the module/method hierarchy are separated by ::
or, alternatively in the case of the separator between the module and the module method, a .
.
Update: Note that the reason why Mod
's constants are not visible to method2
is that Mod
was not separately "opened". The definition skipped directly to Mod::Inner
. If the code were changed to:
module Mod
module Inner
def (Mod::Inner).method2
...
Then Mod
's constants would be accessible to method2
and take precedence over any in the outer scope.
Upvotes: 2