Private & Protected in Ruby
source link: https://www.tuicool.com/articles/hit/EVBbia3
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
My Ruby newsletter is available here . Feel free to subscribe :-)
Private & Protected in Ruby
As a Ruby method is — behind the scene — a message handler
associated with a block of instructions that returns an object, the private
and protected
policies are strongly correlated with the Ruby message
concept.
So, in order to understand private
and protected
policies, let’s have a quick recall on the Ruby message
concept.
Message, Receiver and Message Handler
A message is composed of a name (commonly a symbol
) and an optional payload (the arguments list).
A message requires a receiver
(an object) which responds to this message via a message handler (a method).
The message sender is always the calling object context.This can be the main object if the message is called from outside of a class context.
We can explicitly send
a message to a receiver by using the Kernel#send
method
receiver name payload | | | __________ ______ ______ "a-string".send(:split, '-', 3)
In the above example, the message is composed of:
- a receiver:
"a-string"
- a message name:
:split
- a payload:
'-', 3
- and a sender which is the
main
object
So "a-string"
responds to the message named :split
via the message handler String#split
.
However, you should be more familiar with the dot syntax
receiver name payload | | | __________ _____ ______ "a-string".split('-', 3)
So here, the message split
is implicitly sent to the receiver "a-string"
with the payload ('-', 3)
.
Now that we’ve a better overview of what’s a message in Ruby, let’s detail the notion of private
and protected
methods.
Private methods
In Ruby, a private method (or private message handler) can only respond to a message with an implicit receiver ( self
). It also cannot respond to a message called from outside of the private message handler context (the object)
class Receiver def public_message private_message end
def self_public_message self.private_message end
private
def private_message
puts "This is a private message"
end
end
irb> Receiver.new.public_message
This is a private message
=> nil
irb> Receiver.new.self_public_message
NoMethodError: private method `private_message' called for #<Receiver:0x007b>
irb> Receiver.new.private_message
NoMethodError: private method `private_message' called for #<Receiver:0x007b>
In Receiver#public_message
, the Receiver
instance implicitly send the private_message
's message to the receiver self
. So as we’re in a Receiver
context and the message receiver is implicit then the Receiver#private_message
can respond to the message.
Receiver#self_public_message
explicitly calls the private method for the receiver self
. As a private message handler cannot respond to a message with a receiver, then a NoMethodError
is raised.
An explicit call to Receiver.new.private_message
will raise a NoMethodError
because the message is sent from outside of the private_message
context (which should be an instance of Receiver
).
Protected methods
In Ruby, a protected method (or protected message handler) can only respond to a message with an implicit/explicit receiver (object) of the same family. It also cannot respond to a message sent from outside of the protected message handler context.
class Receiver def public_message protected_message end
def self_public_message self.protected_message end
protected
def protected_message
puts "This is a protected message"
end
end
class Mailbox < Receiver def mb_public_message ::Mailbox.new.protected_message end end
irb> Receiver.new.public_message
This is a protected message
=> nil
irb> Receiver.new.self_public_message
This is a protected message
=> nil
irb> Mailbox.new.mb_public_message
This is a protected message
=> nil
irb> Receiver.new.protected_message
NoMethodError: protected method `protected_message' called for #<Receiver:0x007fbed691bdf0>
In Receiver#public_message
, protected
and private
methods share the same policy.
Receiver#self_public_message
explicitly call the protected method for the receiver self
. The protected message handler Receiver#protected_message
can respond to the message because it contains:
Receiver
Mailbox.new.mb_public_method
also works fine for the same reasons as enumerated above.
Receiver.new.protected_message
raises a NoMethodError
because the message is sent from outside of the Receiver
object.
Kernel#send: the anarchist
The Kernel#send
method has a specificity that can be useful in some cases (testing, etc..).
In effect, when a message is sent by using this method, the private
and protected
policies are bypassed
class Receiver def public_message protected_message end
def self_public_message self.protected_message end
protected
def protected_message
puts "This is a protected message"
end
private
def private_message
puts "this is a private message"
end
end
irb> Receiver.new.send(:private_message)
this is a private message
=> nil
irb> Receiver.new.send(:protected_message)
This is a protected message
=> nil
Voilà !
Thank you for taking the time to read this post :-)
Feel free to :clap: and share this Medium post if it has been useful for you.
Here is a link to my last medium post: RVM Gemsets
.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK