The concept of 'encapsulation' is at the core of Object Oriented programming. Object Oriented programming is grouping related data and methods into a coherent class, as well as providing an interface for that class. The user of these objects and classes use the interface and don't touch the internal state of the object, this is often referred to as 'encapsulation.' Ruby provides both a way to prevent unwanted instance variable accesses, as well as unwanted method invocation by defining three method visibilities.
Public Method Visibility
The default method visibility is public. If a method is public, anyone can call it. It can be called from another instance method as well as from outside of the class. Public methods are methods as everyone knows them, methods without restrictions on how and when they can be called.
Private Method Visibility
There are many reasons you would not want a method to be called from outside of the class. Many classes often have methods that modify the internal state of an object without sufficient integrity checks, and these should be hidden from the user to maintain encapsulation. Further, non-API methods (small utility methods not useful outside of the class, for example) can be made private to communicate to the programmer that that method is uninteresting and to not try to use it.
Private instance methods are only callable from instance methods not only of the same class, but of the same object. To reiterate, private methods are only callable if the self value in both callee and caller will be the same. It isn't enough if the caller is an instance method of the same class, it must be executing in the context of the same object.
In addition, private methods are only callable with implicit receiver. A private method can never be called with the dot notation, it must always be called from an instance method as a "naked" method call. You can't even use self.some_private_method. Even if that should be OK, it won't work.
Private methods are the main way to implement this type of method hiding in Ruby. In order to make any method private, simply call the Module#private method from within a module or class definition. All methods defined after that will be defined as private methods. Alternatively, the private method can take any number of symbol arguments. This variant does not change the default visibility of the defined methods, but it will change the visibility of the methods referred to by the symbol arguments.
class Test def a_public_method # This will succeed a_private_method # This will fail self.a_private_method end private def a_private_method puts "Hello from a private method" end end
Protected methods are similar to private methods, but with some of the restrictions relaxed. Protected methods can be called from anywhere where the self value is the same as the receiver (even using explicit receivers) or from anywhere where the caller's self is of the same type of the callee's self.
class Test def do_test(m) m.spin end protected def spin puts "Wheee!" end end t1 = Test.new t2 = Test.new t2.do_test(t1)
Listing Methods by Visibility
On any class or instance, you can call the methods method to get a list of methods. However, this returns a list of all methods. This is typically done from IRB to see how an object is used, so do we really need to see private methods? In order to see only methods with the desired, use the methods public_methods or public_instance_methods.
Visibility is not Security
It's easy to think of visibility as a type of security. That you can lock the internal state of your objects away and that it can't be accessed because private methods are barring the way. This just isn't true. Private methods exist to separate interface from function. There's nothing really stopping a user from accessing private methods, should they really want to.
One trick to access private methods seems like magic at first, but once you know the criteria for calling public and private methods, it's not magic at all. Say if you have the following class, and you wish to call the update_state method from outside the class. One way to do this is to use the send method.
class Test attr_reader :state def initialize(state) @state = state end private def update_state(s) @state = state end end t = Test.new(:before) # This will raise an exception t.update_state(:after) # This will not t.send(:update_state, :after)
Why did the second method call using send not raise an exception? Any method can be called if the caller and callee's self value are the same. Since you're not actually calling the update_state method from outside the object (it's being called by the send method), it gets around the restriction.
Ruby is a totally open language. There are many tricks to get to the internal state of any object should a programmer so desire. So do your best to separate state from interface and trust the user won't do anything they're not supposed to. Though it's very rarely necessary to monkey around with the internal state of an object to fix a bug or work around a limitation without having to re-engineer anything.