Buscar..


Sintaxis

  • singleton_class = clase << objeto; auto final

Observaciones

Las clases de Singleton solo tienen una instancia: su objeto correspondiente. Esto se puede verificar consultando el ObjectSpace de Ruby:

instances = ObjectSpace.each_object object.singleton_class

instances.count            # => 1
instances.include? object  # => true

Usando < , también se puede verificar que sean subclases de la clase real del objeto:

object.singleton_class < object.class  # => true

Referencias:

Introducción

Ruby tiene tres tipos de objetos:

  • Clases y módulos que son instancias de clase Clase o clase Módulo.
  • Instancias de las clases.
  • Clases singleton.

Cada objeto tiene una clase que contiene sus métodos:

class Example
end

object = Example.new

object.class  # => Example
Example.class # => Class
Class.class   # => Class

Los objetos en sí mismos no pueden contener métodos, solo su clase puede. Pero con las clases de singleton, es posible agregar métodos a cualquier objeto, incluidas otras clases de singleton.

def object.foo
  :foo
end
object.foo #=> :foo

foo se define en la clase de object singleton. Otros Example casos no pueden responder a foo .

Ruby crea clases de singleton bajo demanda. Acceder a ellos o agregarles métodos obliga a Ruby a crearlos.

Acceso a la clase Singleton

Hay dos formas de obtener la clase singleton de un objeto.

  • método singleton_class
  • Reapertura de la clase singleton de un objeto y regreso del self .
object.singleton_class

singleton_class = class << object
  self
end

Acceso a variables de instancia / clase en clases singleton

Las clases de Singleton comparten sus variables de instancia / clase con su objeto.

class Example
  @@foo = :example
end

def Example.foo
  class_variable_get :@@foo
end

Example.foo #=> :example

class Example
  def initialize
    @foo = 1
  end

  def foo
    @foo
  end
end

e = Example.new

e.instance_eval <<-BLOCK
  def self.increase_foo
    @foo += 1
  end
BLOCK

e.increase_foo
e.foo #=> 2

Los bloques se cierran alrededor de sus variables de instancia / clase de destino. Acceder a las variables de instancia o clase usando un bloque en class_eval o instance_eval no es posible. Pasar una cadena a class_eval o usar class_variable_get el problema.

class Foo
  @@foo = :foo
end

class Example
  @@foo = :example 

  Foo.define_singleton_method :foo do
    @@foo
  end
end

Foo.foo #=> :example

Herencia de la clase Singleton

Subclasificación también Subclases Clase Singleton

class Example
end

Example.singleton_class #=> #<Class:Example>

def Example.foo
  :example
end

class SubExample < Example
end

SubExample.foo #=> :example

SubExample.singleton_class.superclass #=> #<Class:Example>

Extender o incluir un módulo no amplía la clase Singleton

module ExampleModule
end

def ExampleModule.foo
  :foo
end

class Example
  extend ExampleModule
  include ExampleModule
end

Example.foo #=> NoMethodError: undefined method

Propagación de mensajes con Singleton Class

Las instancias nunca contienen un método que solo llevan datos. Sin embargo, podemos definir una clase singleton para cualquier objeto, incluida una instancia de una clase.

Cuando se pasa un mensaje a un objeto (se llama método), Ruby primero verifica si una clase singleton está definida para ese objeto y si puede responder a ese mensaje, de lo contrario Ruby verifica la cadena de ancestros de la clase de la instancia y continúa con eso.

class Example
  def foo
    :example
  end
end

Example.new.foo #=> :example

module PrependedModule
  def foo
    :prepend
  end
end

class Example
  prepend PrependedModule
end

Example.ancestors #=> [Prepended, Example, Object, Kernel, BasicObject]
e = Example.new
e.foo #=> :prepended

def e.foo
  :singleton
end

e.foo #=> :singleton

Reapertura (parches de monos) Clases Singleton

Hay tres formas de reabrir una clase Singleton

  • Usando class_eval en una clase de singleton.
  • Usando la class << bloque.
  • Usando def para definir un método en la clase singleton del objeto directamente
class Example
end

Example.singleton_class.class_eval do
  def foo
    :foo
  end
end

Example.foo #=> :foo

class Example
end

class << Example
  def bar
    :bar
  end
end

Example.bar #=> :bar

class Example
end

def Example.baz
  :baz
end

Example.baz #=> :baz

Cada objeto tiene una clase singleton a la que puedes acceder

class Example
end
ex1 = Example.new
def ex1.foobar
  :foobar
end
ex1.foobar #=> :foobar

ex2 = Example.new
ex2.foobar #=> NoMethodError

Clases singleton

Todos los objetos son instancias de una clase. Sin embargo, esa no es toda la verdad. En Ruby, cada objeto también tiene una clase singleton algo oculta.

Esto es lo que permite definir métodos en objetos individuales. La clase singleton se encuentra entre el objeto en sí y su clase real, por lo que todos los métodos definidos en él están disponibles para ese objeto, y solo ese objeto.

object = Object.new

def object.exclusive_method
  'Only this object will respond to this method'
end

object.exclusive_method
# => "Only this object will respond to this method"

Object.new.exclusive_method rescue $!
# => #<NoMethodError: undefined method `exclusive_method' for #<Object:0xa17b77c>>

El ejemplo anterior podría haberse escrito usando define_singleton_method :

object.define_singleton_method :exclusive_method do
  "The method is actually defined in the object's singleton class"
end

Lo que equivale a definir el método en singleton_class object :

# send is used because define_method is private
object.singleton_class.send :define_method, :exclusive_method do
  "Now we're defining an instance method directly on the singleton class"
end

Antes de la existencia de singleton_class como parte de la API central de Ruby, las clases de singleton se conocían como metaclases y se podía acceder a ellas a través del siguiente idioma:

class << object
  self  # refers to object's singleton_class
end


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow