Private Methods
To define a private method, we use the private keyword, which is actually a built-in method implemented in a class called Module. A private method can only be called by another method within the class on which it was defined (or one of its subclasses).
class Koan
def call_say_koan
say_koan
end
private
def say_koan
puts "What is the sound of one hand clapping?"
end
end
k = Koan.new
k.say_koan # Output: NoMethodError: private method `say_koan' called for #<Koan:0x000000021e7380>
k.call_say_koan # Output: What is the sound of one hand clapping?
In the above example, we could not call the say_koan private method directly (from outside the class), but we could call the call_say_koan public method which, in turn, called say_koan.
Also in the above example, the built-in private method was used with no arguments. Hence, all methods defined below it were made private.
The private method can also be used with previously defined method names (passed as symbols) as arguments.
class Foo
def some_method
end
private :some_method
end
In order to make a class method private, use the private_class_method keyword/method instead of private.
Private methods can't be called with a receiver, such as self. Trying to call the say_koan method with self as a receiver (self.say_koan) within call_say_koan would result in the following exception:
NoMethodError: private method `say_koan' called for #<Koan:0x000000021eb548>
As of Ruby 2.0, the respond_to? method will return false when given a private method as an argument.
k.respond_to? :say_koan # Output: => false
To list all private instance methods in a class, use the private_instance_methods built-in method. For private class methods, use private_methods.
Koan.private_instance_methods(false) # Output => [:say_koan]
Protected Methods
To define a protected method, we use the protected keyword (which is actually a method). Like private methods, protected methods can also be called by other methods within the class on which it was defined (or one of its subclasses). The difference is, protected methods can also be called from within other instances of the same class.
There is no such thing as a protected a class method, Ruby only supports protected instance methods.
Let's suppose we need to select a few meditators to participate in a study. To find the most experienced meditators, we need to compare their total hours of meditation. However, we don't want the number of hours to be visible.
class Meditator
def initialize(hours)
@hours = hours
end
def more_experienced?(other_person)
hours > other_person.hours
end
protected
attr_reader :hours # We have made the accessor protected
end
m1 = Meditator.new 3000
m2 = Meditator.new 5000
m2.more_experienced? m1 # Output: => true
m1.more_experienced? m2 # Output: => false
Similar code could be used to protect any kind of sensitive data from outside access (outside the class and its instances), although protected methods are not commonly employed in Ruby.
When called with no arguments (as in the above example), the protected method turns all methods defined below it into protected methods. It can also be used to protect previously defined methods, as in the following example.
class Foo
def some_method
end
protected :some_method
end
To list all protected instance methods in a class, use the protected_instance_methods built-in method. For protected class methods, use protected_methods.
Meditator.protected_instance_methods(false) # Output: => [:hours]