Why does Ruby not allow access to a method from a class unless prefixed with the module name
module Hello
def self.log()
p "log called"
end
class Shape
def self.test
log
end
end
def self.test1
log
end
end
Hello::Shape.test # undefined local variable or method `log'
Hello.test1 # prints "log called"
I know the first statement will work if I prefix log with Hello like: Hello.log
But why can't Shape access the log method even though it's in the same module?
source to share
Whenever you enter a method call without an explicit receiver like
log
Same as
self.log
So you basically do
class Shape
def self.test
self.log
end
end
self
Shape
and Shape
has no method log
. This is why you are getting the error. To do what you want to do, you need to add a method Hello
to Shape
. But this is impossible ! def self.log
adds a method to the Hello
singleton class, and when it comes to singleton methods, Ruby really doesn't let you move them around. Singleton methods only work on one instance.
So how can you get around this? The key is to define log
as a normal instance method - then you can easily move it to other classes and modules.
module Hello
# add all instance methods as class methods
extend self
def log
p "log called"
end
class Shape
# Module.nesting.last is just a clever way of referring to Hello
extend Module.nesting.last
def self.test
log
end
end
def test1
log
end
end
source to share
Since self is Shape, Ruby will by default look for the log method defined in the Shape class. You don't have a log method, so it throws an error. Even if Shape is in the same module, when you use the "class" keyword, Ruby opens a new context, which means that all definitions of methods, variables, etc. defined in the Hello module go outside the scope of the Shape class. You must explain which log method you want to call by prefixing it with the class or module name in the Shape class.
source to share