Uno de lo aspectos más importantes del diseño orientado a objetos es la ocultación de datos o encapsulación.
Consiste en ocultar los datos internos de una clase y únicamente hacerlos disponibles a traves de métodos públicos.
De esta forma ocultamos los detalles internos de la implementación de una clase ofreciendo una API limpia y segura, que nos permitirá modificar la implementación de la clase sin preocuparnos por romper partes del software de quienes la utilicen.

En Ruby hay 3 tipos de visibilidades: publicos, privados y protegidos. Explicaré más adelante el comportamiento de estas visibilidades, pero por ahora, decir que por defecto, al definir los metodos en ruby, todos serán públicos, a no ser que se especifique lo contrario.

class Ejemplo
def metodo1; end
end

El metodo "metodo1" es publico.

La visibilidad puede cambiarse con los métodos especiales "public", "private" y "protected".

Cuando se usa uno de estos métodos en la definición de la clase, los métodos siguientes adoptarán dicha visibilidad.

Por ejemplo:

class Ejemplo
def metodo1; end

private

def metodo2; end
end

En el ejemplo, el método "metodo1" seguirá siendo público. Sin embargo el método "metodo2" tiene acceso privado.
Es importante anotar que si declaramos otro método despues de "metodo2" también será privado. En cualquier momento podemos volver a cambiar el tipo de acceso a público usando el metodo "public".

Si uno de estos métodos especiales recibe un parametro, afectarán únicamente a la visibilidad de los métodos indicados.
 
Por ejemplo:

class Ejemplo
def metodo1; end

def metodo2; end

private :metodo2
end

El comportamiento de la visibilidad de los métodos en Ruby es disinta a de lo otros lenguajes como Java o C++, lo cual puede confundir un poco a quienes provengan de estos lenguajes.

Public

Permite acceder a los métodos desde cualquier otra clase, llamado de forma explícita.

Ejemplo:

class Ejemplo
def metodo1
"metodo1"
end
end

>> Ejemplo.new.ejemplo1
=> "metodo1"

Protected

Un método protegido no puede ser invocado desde otra clase que no sea ella misma o de otras clases que hereden de ella. Un método protegido puede ser llamado tanto de forma explícita como de forma implícita.

Ejemplo:

class Ejemplo
def publico_implicito
metodo_protegido
end

def publico_explicito
self.metodo_protegido
end

protected

def metodo_protegido
"metodo1"
end
end

>> Ejemplo.new.publico_implicito
=> "metodo1"
>> Ejemplo.new.publico_explicito
=> "metodo1"
>> Ejemplo.new.metodo_protegido
NoMethodError: protected method 'metodo_protegido' called for #<Ejemplo:0xb793c094>
class Subclase < Ejemplo
def subclase_implicito
metodo_protegido
end

def subclase_explicito
self.metodo_protegido
end
end

>> Subclase.new.subclase_implicito
=> "metodo1"
>> Subclase.new.subclase_explicito
=> "metodo1"

Private

Los métodos privados únicamente pueden ser llamados desde su propia clase o sus subclases y sólo de forma implicita.

class Ejemplo 
def publico_implicito
metodo_privado
end

def publico_explicito
self.metodo_privado
end

private

def metodo_privado
"metodo1"
end
end

>> Ejemplo.new.metodo_privado
NoMethodError: private method 'metodo_privado' called for #<Ejemplo:0xb7930514>
from (irb):51

>> Ejemplo.new.publico_implicito
=> "metodo1"
>> Ejemplo.new.publico_explicito
NoMethodError: private method 'metodo_privado' called for #<Ejemplo:0xb792d0bc>
from (irb):43:in 'publico_explicito'
from (irb):53

Esto es contrario al comportamiento en Java. Por ejemplo:

class Ejemplo{
public equals(otro_ejemplo){
private_method() == otro_ejemplo.private_method();
}
private private_method(){
return 1;
}
}

En Java, un metodo privado no es accesible desde fuera de la misma clase, sin embargo, desde una clase, si que se puede acceder a metodos privados de otros objectos de la misma clase.

En Ruby, el mismo ejemplo sólo funcionaría si el metodo es protected, ya que es necesario llamar al método de forma explicita, lo cual no está permitido en métodos privados.

class Ejemplo
def ==(otro_ejemplo)
protected_method == otro_ejemplo.protected_method
end
protected
def protected_method
1
end
end

>> ejemplo1 = Ejemplo.new
>> ejemplo2 = Ejemplo.new
>> ejemplo1 == ejemplo2
=> true