I created a module that contains a constant NAME
and a method hello
. If a class includes the module, both definitions should be visible in different scope.
module A
NAME = 'Otto'
def self.included(base)
base.extend(ClassMethods)
end
def hello(name = 'world')
self.class.hello(name)
end
module ClassMethods
def hello(name = 'world')
"Hello #{name}!"
end
end
end
class B
include A
def instance_scope
p [__method__, hello(NAME)]
end
def self.class_scope
p [__method__, hello(NAME)]
end
class << self
def eigen_scope
p [__method__, hello(NAME)]
end
end
end
B.new.instance_scope
B.class_scope
B.eigen_scope
#=> script.rb:34:in `eigen_scope': uninitialized constant Class::NAME (NameError)
from script.rb:41
But the the constant isn't visible in the instance method scope of the eigenclass, class << self
.
Is there a way to make the module more robust and provide the constants also in the errorneous scope above?
class << self
def eigen_scope
p [__method__, hello(self::NAME)]
#=> [:eigen_scope, "Hello Otto!"]
end
end
self::NAME
work?A::NAME
would be the easiest, hard-coded version.B::NAME
would also work, because B
includes A
eigen_scope
, self
is B
, so self::NAME
works as wellself::NAME
would also work in self.class_scope
self::NAME
wouldn't work in instance_scope
: a B
instance is not a class/module.NAME
work?Here's a very good explanation.
constant lookup searches for constants that are defined in
Module.nesting
,Module.nesting.first.ancestors
, andObject.ancestors
ifModule.nesting.first
is nil or a module
self
is the same in class_scope
and eigen_scope
.
Module.nesting
is different though :
[B]
for class_scope
[#<Class:B>, B]
for eigen_scope
So Module.nesting.first.ancestors
is :
[B, A, Object, Kernel, BasicObject]
for class_scope
[#<Class:B>, A::ClassMethods, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
for eigen_scope
A
isn't searched, but A::ClassMethods
!
So you could define :
module A
module ClassMethods
NAME = 'Bob'
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With