Method Visibility
Every method you define in Ruby has a visibility: public, private, or protected. Visibility determines who is allowed to call a method and how. By default, every instance method you write is public, meaning any object holding a reference to your object can call it directly with an explicit receiver. Ruby lets you tighten this default using the private and protected keywords, which is essential for encapsulation — hiding implementation details so that a class's internal helper methods can change freely without breaking code that depends on the class.
Cricket analogy: Method visibility is like a team's information tiers: public stats anyone can see on the scoreboard, private dressing-room strategy only the team can access, and protected data like fitness reports shared only within the squad's own management.
Public methods
Public methods form a class's external interface. They can be called with an explicit receiver, some_object.public_method, from anywhere in the program. Unless stated otherwise, initialize is a special case: it is always private, because Ruby only ever wants new to invoke it internally. Every other method you define is public unless you say otherwise.
Cricket analogy: Public methods forming the external interface, callable from anywhere, are like a player's public stats accessible to any fan, while initialize being always private is like the selection meeting that picks the player, only the selectors (new) ever run it internally.
Private methods
A private method cannot be called with an explicit receiver — not even self.method_name in most cases (Ruby 2.7+ makes an exception for attribute writers like self.name =). Private methods exist to hide implementation details that are only meaningful inside the object itself, such as a helper that formats data for a public method to use. Marking methods private communicates intent to other developers: 'this is not part of the contract; do not depend on it.'
Cricket analogy: A private method not callable with an explicit receiver is like a bowler's personal grip adjustment technique, useful only to that bowler internally, never something a teammate can invoke by name from the boundary.
class BankAccount
def initialize(balance)
@balance = balance
end
def withdraw(amount)
raise ArgumentError, 'insufficient funds' unless sufficient_funds?(amount)
@balance -= amount
end
private
# Cannot be called as account.sufficient_funds?(50) from outside
def sufficient_funds?(amount)
amount <= @balance
end
end
account = BankAccount.new(100)
account.withdraw(30) #=> 70
account.sufficient_funds?(10) #=> NoMethodError: private method calledProtected methods
Protected methods sit between public and private: they can be called with an explicit receiver, but only from within an instance method of the same class (or a subclass). This is the idiomatic choice when one object needs to compare itself against another object of the same type using an internal value that should not be exposed publicly.
Cricket analogy: A protected method callable with an explicit receiver only from within the same class is like two batters from the same team comparing their internal strike rates mid-innings, something an opposing player could never do since they're not part of that team's class.
class Money
def initialize(cents)
@cents = cents
end
def >(other)
cents > other.cents # calling other.cents requires 'protected', not 'private'
end
protected
attr_reader :cents
end
Money.new(500) > Money.new(300) #=> true
Money.new(500).cents #=> NoMethodError: protected method calledIn Python, all attributes are technically accessible; underscore prefixes like _name or __name are conventions, not enforcement. Ruby's private and protected are enforced by the interpreter itself — calling a private method externally raises NoMethodError, giving Ruby stronger encapsulation guarantees than Python's convention-based approach.
A common mistake is assuming private hides a method from subclasses — it does not. Private methods are inherited and remain callable (without an explicit receiver) inside subclass instance methods. private restricts the calling syntax, not which classes can see the method.
- Public methods can be called with an explicit receiver from anywhere; this is the default visibility.
- Private methods cannot be called with an explicit receiver (with a narrow exception for
self.attr=setters since Ruby 2.7). - Protected methods can be called with an explicit receiver, but only from within another instance method of the same class or its subclasses.
initializeis always private so that onlynewcan invoke it.- Visibility is enforced by the interpreter, unlike Python's convention-based underscore naming.
- Use
protectedwhen objects of the same class need to compare or interact using internal state.
Practice what you learned
1. What happens when you call a private method with an explicit receiver like `obj.private_method`?
2. Why must comparison methods like `>` between two objects of the same class often use `protected` instead of `private`?
3. What is the default visibility of a newly defined instance method in Ruby?
4. Is `initialize` public or private by default?
5. Do subclasses inherit private methods from their superclass?
Was this page helpful?
You May Also Like
Classes and Objects in Ruby
Learn how Ruby defines classes as blueprints for objects, covering the `class` keyword, `initialize`, instance methods, and how everything in Ruby is an object.
attr_accessor and Instance Variables
Learn how instance variables hold per-object state in Ruby, and how attr_accessor, attr_reader, and attr_writer generate boilerplate getter and setter methods.
Inheritance in Ruby
See how Ruby classes extend one another with single inheritance, how `super` calls parent implementations, and how method resolution order determines which method runs.
Operator Overloading
Learn how Ruby implements operators as ordinary methods, letting you define custom `+`, `==`, `<<`, and other operators on your own classes for expressive, idiomatic APIs.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics