Question

The following code works:

class MyClass
  def method_a
    method_b
  end

  private
  def method_b
    puts "Hello!"
  end
end

m = MyClass.new
m.method_a

Changing the call to method_b to self.method_b however does not work:

def method_a
  self.method_b
end

I get a NoMethodError. I'm under the impression that self just resolves to the instance of the class when inside an instance method. Why does self.method_b cause problems?

Note: self.method_b works when private is changed to protected.

Note: if the above methods are changed to class methods then calling self.method_b from method_a doesn't throw the NoMethodError.

Was it helpful?

Solution

This is how private methods work in Ruby. They cannot be called with an explicit receiver (unless it is a setter method; see below).

Read more in the section on Access Control from the Pickaxe.

Private methods whose names end with an = may be invoked using self.method_name = ... as this is necessary to differentiate them from setting a local variable:

class Foo
  def try
    set_foo(1)            # Invokes private method
    self.set_foo(2)       # ERROR: private method `set_foo' called for ...
    self.send(:set_foo,3) # Invokes private method

    bar = 1               # Sets local variable
    self.bar = 2          # Invokes private method
    self.send(:bar=,3)    # Invokes private method
  end

  private
    def set_foo(v)
      @foo = v
    end
    def bar=(v)
      @bar = v
    end
end

Foo.new.bar = 42          # ERROR: private method `bar=' called for ...

OTHER TIPS

That's just how Ruby works: when you provide an explicit object reference, NoMethodError is raised to show the code is breaking intent. You could do a self.send and it would work.

Without the explicit reference, Ruby doesn't do the same visibility check; see this and/or this for a bit more detail.

Nutshell is that private methods can't be called with an explicit receiver, even if it's self.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top