clase << idioma propio en Ruby


873

¿Qué hace class << selfen Ruby ?


35
Hay un muy buen artículo sobre este tema escrito por Yehuda Katz: yehudakatz.com/2009/11/15/… y Yugui
Andrei

3
Otro artículo súper agradable aquí: integralist.co.uk/posts/eigenclass.html
Saman Mohamadi

2
Estoy viendo esto dentro de un módulo, ¿eso lo hace diferente? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken

@FullDecent No hace la diferencia ya que todo en Ruby es un objeto, incluidos los módulos y las clases.
Aaron

Respuestas:


912

Primero, la class << foosintaxis abre foola clase singleton (clase propia). Esto le permite especializar el comportamiento de los métodos invocados en ese objeto específico.

a = 'foo'
class << a
  def inspect
    '"bar"'
  end
end
a.inspect   # => "bar"

a = 'foo'   # new object, new singleton class
a.inspect   # => "foo"

Ahora, para responder a la pregunta: class << selfabre selfla clase singleton de modo que los métodos se puedan redefinir para el selfobjeto actual (que dentro de una clase o cuerpo del módulo es la clase o el módulo en ). Por lo general, esto se utiliza para definir métodos de clase / módulo ("estático"):

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"

Esto también se puede escribir como una taquigrafía:

class String
  def self.value_of obj
    obj.to_s
  end
end

O incluso más corto:

def String.value_of obj
  obj.to_s
end

Cuando está dentro de una definición de función, se selfrefiere al objeto con el que se llama a la función. En este caso, class << selfabre la clase singleton para ese objeto; un uso de eso es implementar la máquina de estado de un hombre pobre:

class StateMachineExample
  def process obj
    process_hook obj
  end

private
  def process_state_1 obj
    # ...
    class << self
      alias process_hook process_state_2
    end
  end

  def process_state_2 obj
    # ...
    class << self
      alias process_hook process_state_1
    end
  end

  # Set up initial state
  alias process_hook process_state_1
end

Entonces, en el ejemplo anterior, cada instancia de se StateMachineExampleha process_hookaliasado process_state_1, pero tenga en cuenta cómo en la última, puede redefinir process_hook( selfsolo, sin afectar otras StateMachineExampleinstancias) a process_state_2. Por lo tanto, cada vez que una persona que llama llama al processmétodo (que llama redefinible process_hook), el comportamiento cambia según el estado en el que se encuentre.


22
@ Jörg: +1 para editar (deseo que SO proporcione la posibilidad de votar a ediciones; bueno, bueno). De hecho, ese es el uso más común de class << self, para crear métodos de clase / módulo. Probablemente ampliaré ese uso class << self, ya que es un uso mucho más idiomático.
Chris Jester-Young

44
gsub! ("eigenclass", "singleton class"), vea el próximo método redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune

44
Es realmente confuso referirse a a's singleton_classya que ala clase (después de cambiar inspect) es una variante única de la Stringclase. Si estuviera cambiando la Stringclase singleton , afectaría a todas las demás Stringinstancias. Lo que es más raro aún es que si más adelante vuelve a abrir Stringpara redefinir inspectentonces aseguirá siendo recoger a los nuevos cambios.
Old Pro

1
@OldPro Todavía prefiero el nombre eigenclass, como (creo) Matz también lo hace. Pero, no puedo complacer a todos, supongo.
Chris Jester-Young

55
Me parece vaga la expresión "abre la clase singleton de un objeto", que he leído muchas veces antes. Que yo sepa, en ninguna parte de los documentos de Ruby se "abre" una clase definida, a pesar de que todos tenemos una idea de lo que significa. ¿ class << selfSignifica algo más que el valor de selfse establece igual a la clase singleton dentro del alcance del bloque?
Cary Swoveland

34

He encontrado una explicación simple súper sobre class << self, Eigenclassy diferentes tipos de métodos.

En Ruby, hay tres tipos de métodos que se pueden aplicar a una clase:

  1. Métodos de instancia
  2. Métodos Singleton
  3. Métodos de clase

Los métodos de instancia y los métodos de clase son casi similares a sus homónimos en otros lenguajes de programación.

class Foo  
  def an_instance_method  
    puts "I am an instance method"  
  end  
  def self.a_class_method  
    puts "I am a class method"  
  end  
end

foo = Foo.new

def foo.a_singleton_method
  puts "I am a singletone method"
end

Otra forma de acceder a un Eigenclass(que incluye métodos singleton) es con la siguiente sintaxis ( class <<):

foo = Foo.new

class << foo
  def a_singleton_method
    puts "I am a singleton method"
  end
end

ahora puede definir un método singleton para el selfcual es la clase Foomisma en este contexto:

class Foo
  class << self
    def a_singleton_and_class_method
      puts "I am a singleton method for self and a class method for Foo"
    end
  end
end

44
En realidad, los métodos Singleton y los métodos Class son los mismos, ambos existentes en la clase Singleton. puedes usar foo.singleton_class.instance_methods(false)para verificar.
Damon Yuan

22

Por lo general, los métodos de instancia 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, se implementa un método singleton en un solo objeto.

Ruby almacena métodos en clases y todos los métodos deben estar asociados con una clase. El objeto en 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 denominan metaclases, también conocidas como clases singleton o clases propias. El método singleton está asociado con la metaclase que, a su vez, está asociada con el objeto en el que se definió el método singleton.

Si se definen múltiples métodos singleton dentro de un solo objeto, todos se almacenan en la misma metaclase.

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 self actual para apuntar a la metaclase del objeto z1; luego, define el método say_hello dentro de la metaclase.

Las clases también son objetos (instancias de la clase incorporada llamada Clase). Los métodos de clase no son más que métodos singleton asociados con un objeto de clase.

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 << self modifica self para que apunte a la metaclase de la clase Zabuton. Cuando un método se define sin un receptor explícito (la clase / objeto en 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 relleno se define dentro de la metaclase de la clase Zabuton. El ejemplo anterior es solo otra forma de definir un método de clase. En mi humilde opinión, es mejor usar la sintaxis def self.my_new_clas_method para definir métodos de clase, ya que hace que el código sea más fácil de entender. El ejemplo anterior se incluyó para que comprendamos qué sucede cuando nos encontramos con la clase << sintaxis propia.

Se puede encontrar información adicional en esta publicación sobre Ruby Classes .


15

¿Qué clase << cosa hace:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end

[lo hace self == thing.singleton_class en el contexto de su bloque] .


¿Qué es thing.singleton_class?

hi = String.new
def hi.a
end

hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true

hiobjeto hereda su #methodsde su #singleton_class.instance_methodsy luego de su #class.instance_methods.
Aquí le dimos hiel método de instancia de clase singleton:a . Podría haberse hecho con la clase << hola en su lugar.
hi's #singleton_classtiene todos los métodos de instancia hi' s #classtiene, y posiblemente algunos más ( :aaquí).

[métodos de instancia de cosa #class y #singleton_class pueden aplicarse directamente a cosa. cuando ruby ​​ve thing.a, primero busca: una definición de método en thing.singleton_class.instance_methods y luego en thing.class.instance_methods]


Por cierto, llaman a la clase singleton del objeto == metaclass == eigenclass .


3

El método singleton es un método que se define solo para un solo objeto.

Ejemplo:

class SomeClass
  class << self
    def test
    end
  end
end

test_obj = SomeClass.new

def test_obj.test_2
end

class << test_obj
  def test_3
  end
end

puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods

Los métodos de Singleton de SomeClass

prueba


Los métodos de singleton de test_obj

prueba_2

prueba_3


1

De hecho, si escribe extensiones C para sus proyectos de Ruby, en realidad solo hay una forma de definir un método de Módulo.

rb_define_singleton_method

Sé que este negocio propio simplemente abre todo tipo de otras preguntas para que pueda mejorar buscando cada parte.

Objetos primero.

foo = Object.new

¿Puedo hacer un método para foo?

Por supuesto

def foo.hello
 'hello'
end

¿Que hago con esto?

foo.hello
 ==>"hello"

Solo otro objeto.

foo.methods

Obtiene todos los métodos Object más el nuevo.

def foo.self
 self
end

foo.self

Solo el foo Object.

Intenta ver qué sucede si haces foo de otros objetos como Class y Module. Es agradable jugar con los ejemplos de todas las respuestas, pero debe trabajar con diferentes ideas o conceptos para comprender realmente lo que sucede con la forma en que se escribe el código. Así que ahora tienes muchos términos para ver.

Singleton, Class, Module, self, Object y Eigenclass se mencionaron, pero Ruby no nombra los modelos de objetos de esa manera. Es más como Metaclass. Richard o __ por qué te muestra la idea aquí. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html Y si te sorprende, intenta buscar el Modelo de objetos Ruby en la búsqueda. Dos videos que conozco en YouTube son Dave Thomas y Peter Cooper. Intentan explicar ese concepto también. Dave tardó mucho en conseguirlo, así que no te preocupes. Todavía estoy trabajando en eso también. ¿Por qué más estaría aquí? Gracias por tu pregunta También eche un vistazo a la biblioteca estándar. Tiene un Módulo Singleton como un FYI.

Esto es bastante bueno https://www.youtube.com/watch?v=i4uiyWA8eFk

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.