La mayoría de los métodos de instancia utilizados en Ruby son métodos globales. Eso significa que están disponibles en todas las instancias de la clase en la que se definieron. Por el contrario, un método singleton se implementa en un solo objeto.
Existe una aparente contradicción. Ruby almacena métodos en clases y todos los métodos deben estar asociados con una clase. El objeto sobre el que se define un método singleton no es una clase (es una instancia de una clase). Si solo las clases pueden almacenar métodos, ¿cómo puede un objeto almacenar un método singleton? Cuando se crea un método singleton, Ruby crea automáticamente una clase anónima para almacenar ese método. Estas clases anónimas se llaman metaclases, también conocidas como clases únicas o clases propias. El método singleton está asociado con la metaclase que, a su vez, está asociada con el objeto sobre el que se definió el método singleton.
Si se definen varios métodos únicos dentro de un único objeto, todos se almacenan en la misma metaclase.
class Zen
end
z1 = Zen.new
z2 = Zen.new
def z1.say_hello # Notice that the method name is prefixed with the object name
puts "Hello!"
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
En el ejemplo anterior, se definió el método say_hello dentro de la instancia z1 de la clase Zen pero no la instancia z2.
El siguiente ejemplo muestra una forma diferente de definir un método singleton, con el mismo resultado.
class Zen
end
z1 = Zen.new
z2 = Zen.new
class << z1
def say_hello
puts "Hello!"
end
end
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
En el ejemplo anterior, la clase < < z1 cambia el auto actual para apuntar a la metaclase del objeto z1; luego, define el método say_hello dentro de la metaclase.
Ambos ejemplos anteriores sirven para ilustrar cómo funcionan los métodos únicos. Sin embargo, existe una manera más fácil de definir un método singleton: usar un método integrado llamado definir_singleton_method.
class Zen
end
z1 = Zen.new
z2 = Zen.new
z1.define_singleton_method(:say_hello) { puts "Hello!" }
z1.say_hello # Output: Hello!
z2.say_hello # Output: NoMethodError: undefined method `say_hello'…
Aprendimos anteriormente que las clases también son objetos (instancias de la clase incorporada llamada Clase). También aprendimos sobre métodos de clase. Los métodos de clase no son más que métodos únicos asociados con un objeto de clase.
Un ejemplo más:
class Zabuton
class << self
def stuff
puts "Stuffing zabuton…"
end
end
end
Todos los objetos pueden tener metaclases. Eso significa que las clases también pueden tener metaclases. En el ejemplo anterior, la clase < < se auto modifica por lo que apunta a la metaclase de la clase Zabuton. Cuando se define un método sin un receptor explícito (la clase/objeto sobre el que se definirá el método), se define implícitamente dentro del alcance actual, es decir, el valor actual de uno mismo. Por lo tanto, el método de cosas se define dentro de la metaclase de la clase Zabuton. El ejemplo anterior es solo otra forma de definir un método de clase.
Obtenga más información en this post about Ruby Classes.
Esta es una respuesta realmente brillante en singletons –