public, protected and private

private

A public method is the interface: anyone may call it. A private method is behind it: only code inside the same object may call it without a receiver. The rule is about the receiver, not about the file, which is why a private method can still be called with send:

ruby -e 'class A; private def x = 1; end; p A.new.send(:x)'

1

Calling it the normal way raises, and the message names the method and the visibility:

ruby -e 'class A; private def x = 1; end; A.new.x'

-e:1:in '<main>': private method 'x' called for an instance of A (NoMethodError)

private def x is the short form; the older form writes def x; end and then private :x. Both work, and the short form keeps the visibility next to the method.

protected

A protected method may be called with an explicit receiver, as long as the receiver is the same kind of object. That is what an object needs to compare itself with another:

class Score def initialize(points) @points = points end def higher_than?(other) points > other.points end protected def points @points end end

ruby -e 'class A; def initialize(n) = @n = n; protected def n = @n; def bigger?(o) = n > o.n; end; p A.new(2).bigger?(A.new(1))'

true

bigger? calls o.n, and that is allowed because the caller is another A. From outside the class, the same call is refused.

module_function

A module that is used as a namespace rather than mixed in can expose a method as both a module method and a private instance method. module_function does that for one name:

ruby -e 'module M; def self.x = 1; def y = 2; module_function :y; end; p M.x; p M.y'

1
2

The method y is callable as M.y and, inside a class that includes the module, as a private method. That is the usual way to write a helper module with a public entry point and internal steps.

What to watch for

Private is a message to the next reader, not a security boundary. send and instance_variable_get reach everything, and a test that uses them is testing the implementation. Test the public method whose behaviour depends on the private one.

A private method on a class (def self.x under private) is not private in the same way: class methods live on the singleton class, and private_class_method is the one that hides them from callers.

Next: Keyword arguments and forwarding

Article author: Arthur Isaev

Banner image