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?
Solution
Why does
self::NAMEwork?A::NAMEwould be the easiest, hard-coded version.B::NAMEwould also work, becauseBincludesAeigen_scope,selfisB, soself::NAMEworks as wellself::NAMEwould also work inself.class_scopeself::NAMEwouldn't work ininstance_scope: aBinstance is not a class/module.Why doesn't
NAMEwork?Here's a very good explanation.
selfis the same inclass_scopeandeigen_scope.Module.nestingis different though :[B]forclass_scope[#<Class:B>, B]foreigen_scopeSo
Module.nesting.first.ancestorsis :[B, A, Object, Kernel, BasicObject]forclass_scope[#<Class:B>, A::ClassMethods, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]foreigen_scopeAisn't searched, butA::ClassMethods!So you could define :