resultsway
resultsway

Reputation: 13300

why doesnt ruby allow accessing a method from within a class unless prefixed with 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 cant Shape access the log method even if it is within the same module?

Upvotes: 3

Views: 50

Answers (2)

bparanj
bparanj

Reputation: 443

Since the value of self is Shape, by default Ruby will look for log method defined in Shape class. You don't have a log method so it will raise an error. Even if the Shape is within the same module, when you use the keyword 'class', Ruby opens a new context, which means all the definitions of methods, variables etc defined within the module Hello goes out of scope within the Shape class. You have to explicity specify which log method you want to call by prefixing it with the class or module name within the Shape class.

Upvotes: 0

Max
Max

Reputation: 22325

Whenever you type a method call without an explicit receiver like

log

That's the same as

self.log

So you're basically doing

class Shape
  def self.test
    self.log
  end
end

self is Shape and Shape doesn't have a log method. That's why you get the error. So to do what you want to do, you need to add Hello's method to Shape. But this is impossible! def self.log adds a method to Hello's singleton class, and when it comes to singleton methods Ruby really doesn't let you move them around. Singleton methods only go with a single instance.

So how can you get around this? The key is to define log as a regular instance method - then you can easily move it around 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

Upvotes: 2

Related Questions