36

Private & Protected in Ruby

 6 years ago
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.
neoserver,ios ssh client
eQNRVjR.png!web

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 .


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK