Pregunta

Estuve viendo la primera metaprogramación de rubíes grabada por Prag Dave. En algún momento, dijo que ruby ??introduce "clases de fantasmas" cuando agregas un método a una variable de instancia. i.

animal = "cat"
def animal.speak
  puts "hola"
end
animal.speak       # => hola
animal.class       # => String

dog = "dog"

dog.speak          # Undefined method `speak' for "dog":String
String.send :speak # NoMethodError: undefined method `speak' for String:Class
animal.send :speak # hola

¿Dónde está realmente la tienda de métodos de conversación? Si se trata de una clase de proxy invisible, ¿cómo podemos acceder a esa clase de proxy?

¿Fue útil?

Solución

El método speak se almacena en una metaclase (también conocida como eigenclass), lo que usted llama una "clase proxy invisible". En Ruby, las variables de instancia no tienen lugar para almacenar métodos. Solo pueden almacenar variables de instancia y su clase. Entonces, cuando agrega un método a una instancia, se crea una metaclase y se inserta en su cadena de clase. Para una mejor comprensión de los aspectos internos, recomiendo este artículo de Klank Boom Klang.

Para llegar a la meta clase, puedes hacer lo siguiente:

animal = "cat"
def animal.speak
  puts "hola"
end
animal.speak       # => hola
animal.class       # => String

metaclass = class << animal; self; end

metaclass.inspect                        # => #<Class:#<String:0x2c9c460>>
metaclass.instance_methods.index 'speak' # => 102
metaclass.class                          # => Class

Otros consejos

Algunas personas lo llaman " Clase Singleton "

singleton_class = class << animal; self; end

Y, de hecho, esta clase de singleton es el host de los métodos de clase en cualquier clase, verifique este ejemplo, primero definiendo la clase Foo con los métodos de clase 'hi' y 'bye':

class Foo
  def self.hi ; p "hi" ; end
  def self.bye ; p "bye" ; end
end
Foo.singleton_methods #=> ["hi","bye"]

Ahora definamos un método que devuelva la clase singleton para nosotros:

class Object
  def singleton_class 
     class << self
       self
     end
  end
end

Ahora prueba esto:

Foo.singleton_methods #=> ["bye", "hi"]
Foo.singleton_class.instance_methods(false) #=> ["bye", "hi"]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top