2010-01-26 15 views
6

En Ruby, podríamos usar super dentro del método singleton para llamar al método singleton de la superclase correspondiente, como se muestra en el siguiente código.¿Cuál es la relación entre la metaclase de clase Base y Derivada en Ruby?

class Base 
    def self.class_method 
    puts "Base class method" 
    end 
end 

class Derived < Base 
    def self.class_method 
    puts "Derived class method" 
    super 
    end 
end 

Derived.class_method 
# Derived class method 
# Base class method 

Sin embargo, no me parece del todo cómo conseguir esa llamada a super dentro Derived.class_method podría llegar a Base.class_method. Supongo que class_method se define en su metaclase, ¿eso significa que su metaclase tiene una relación padre/hijo? (Yo no puedo confirmar que los experimentos)

actualización: estoy haciendo esta pregunta, ya que recordaba haber visto en alguna parte que hay algún tipo de relación bettwen base y clase derivada metaclase (pero no puedo encontrarlo más). Además de saber cómo realmente funciona el super, también me gustaría confirmar si las dos metaclases están totalmente separadas o no.

Respuesta

11

Hay cuatro objetos de clase en juego aquí:

<Class>---class---><Class> 
Base    #Base 
^    ^
    |     | 
    |     | 
super    super 
    |     | 
    |     | 
<Class>   <Class> 
Derived---class--->#Derived 

Nomenclatura:

  • < ...> es la clase de cada objeto.
  • El nombre de la clase está en la segunda línea.
  • Si el nombre comienza con #, es la clase propia (también conocida como clase singleton).
  • super puntos a una clase de la superclase
  • clase apunta a la clase de la clase.

Cuando se llama a Derived.class_method, Ruby sigue el "uno a la derecha y luego hacia arriba" regla: Primero vaya a la clase del objeto, a continuación, siga la cadena de superclase arriba, parando cuando se encuentra el método:

  • El receptor de la llamada "class_method" es Derivado. Siga la cadena hasta el objeto de clase Derived, que es su clase propia (#Derived).
  • Derived no define el método, por lo que Ruby sigue la cadena hasta la superclase # Derived, que es #Base.

  • El método se encuentra allí, así Rubí envía el mensaje a # Base.class_method

¿No cree que sabía todo esto de la parte superior de mi cabeza, ¿verdad? Aquí es donde mi cerebro obtuvo todo este metajuju: Metaprogramming Ruby.

Parte 2. Cómo hacer un "eigenclass" (también conocido como "clase singleton") salir de su escondite

class Object 
    def eigenclass 
    class << self 
     self 
    end 
    end 
end 

Este método devolverá los eigenclass de cualquier objeto. Ahora, ¿qué hay de las clases? Esos son objetos, también.

p Derived.eigenclass    # => #<Class:Derived> 
p Derived.eigenclass.superclass # => #<Class:Base> 
p Base.eigenclass     # => #<Class:Base> 

Nota: Above es de Ruby1.9. Cuando se ejecuta bajo Ruby 1.8, se obtiene una sorpresa:

p Derived.eigenclass.superclass # => #<Class:Class> 
+0

¿Hay una manera de 'ver' la relación entre #Base y #Derived? por ejemplo, como la '.superclass' normal. – bryantsai

+0

Agregué el truco que hace que una clase electrónica salga de su escondite. Pero el diagrama no es consistente con lo que muestra el truco :( –

+0

bueno ... # no es # , ese es mi problema ... ¿Dose el enlace de #Derived a #Base realmente existe? – bryantsai

3

Este diagrama explica la relación: http://banisterfiend.wordpress.com/2008/11/25/a-complete-ruby-class-diagram/

nuevo, aquí hay algunos otros mensajes que explican más las complejidades de eigenclasses: http://www.klankboomklang.com/2007/10/05/the-metaclass/

http://www.klankboomklang.com/2007/09/21/the-singleton-class/

Y aquí hay uno bastante difícil que explica más de lo que probablemente le gustaría saber: http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/

+1

Finalmente logré leer su publicación dura. ¡Buena cosa! –

4

clarificar y corregir lo que escribí en los comentarios relativos a la forma en Rubí esconde/expone eigenclasses, aquí está la situación:

Rubí 1.8:

(1) El método Object#class siempre devuelve la primera verdadera (no eigenclass o iclass) superclase de la clase real de un objeto. por ejemplo

o = Object.new 
class << o; end 
o.class #=> returns Object, even though the _actual_ class is the eigenclass of o 

En otras palabras, el método Object#class nunca se devolverá un eigenclass, pasa por encima de ellos y en su lugar devuelve la primera clase 'real' que encuentra en la jerarquía de herencia.

(2) El método Class#superclass tiene dos casos. Si el receptor no es una clase propia, simplemente devuelve la superclase. Sin embargo, si el receptor es eigenclass, este método devuelve la clase real (es decir, no necesariamente real) del receptor.

# case where receiver is a normal class (i.e not an eigenclass) 
Module.superclass #=> Object (behaves as expected) 

# case where receiver is an eigenclass 
class << Module; superclass; end #=> returns Class, this is NOT the superclass 

Desde arriba, Class#superclass comporta como se esperaba en el caso de una clase normal, pero para el ejemplo eigenclass que establece la superclase de los eigenclass de módulo es de clase que no es cierto. De este diagrama http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/ sabemos que la superclase de la clase de módulo es en realidad la clase de objeto. No estoy seguro de por qué Ruby 1.8 tiene este extraño comportamiento.

Ruby 1.9:

(1) El método Object#class comporta de forma idéntica a la versión 1.8.

(2) El método Class#superclass ya no tiene dos casos, se trata ahora eigenclasses de la misma manera en que trata a clases normales y devuelve la superclase real como se esperaba.

por ejemplo

class << Module; superclass; end #=> #<Class:Object> 
Cuestiones relacionadas