Search code examples
rubymethodsaccess-specifier

private and protected methods in Ruby


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.


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 ...