2012-01-01 19 views
5

Inspirado por este article, estaba jugando con la jerarquía de llamadas al método Ruby y noté algo extraño.Jerarquía de llamadas al método Ruby

Dado:

class B 
    def foo 
    "- Instance method defined by B" 
    end 

    def method_missing(method) 
    puts "- method_missing (#{method}) on b. Redirecting to b.foo\n" 
    foo 
    end 
end 

b = B.new 

def b.foo 
    "- Method defined directly on an instance of B\n" + super 
end 

def b.method_missing(method) 
    "- method_missing (#{method}) on b. Calling super\n" + super 
end 

puts "Calling 'bar' on b of type #{b.class}:" 
puts b.bar 

Correr Da:

Calling 'bar' on b of type B: 
- method_missing (bar) on b. Redeirecting to b.foo 
- method_missing (bar) on b. Calling super 
- Method defined directly on an instance of B 
- instance method defined by B 

Mi pregunta es:

Desde que estoy llamando b.bar (en el objeto), ¿cómo es que la instancia de la clase El método se invoca antes de que se llame al método de instancia del objeto?

lo que habría esperado b.method_missing(method) que se llamará en primer lugar, a continuación, method_missing(method) instancia de la clase (ya que estoy llamando súper? Pero es súper jerarquía de clases ...) lo que la hace la redirección desde bar a foo. Además, ¿cómo es que, después de haber sido redirigido al foo, se llama al método missing_method de la instancia? Nos acaban de decir que estamos siendo redirigidos ...

Creo que no entiendo el concepto de cómo Ruby permite definir un método de instancia en una instancia de una clase (nuevo para mí), en oposición a definiéndolo como un método de instancia de una clase (lenguajes clásicos).

espero que esta pregunta tiene sentido, tal vez mi cabeza todavía está girando desde la noche anterior ...

+1

I eliminó el código irrelevante para hacer que el problema sea más evidente. En general, es una buena idea proporcionar un * ejemplo * mínimo de un problema. –

Respuesta

4

El problema es que su salida no se corresponde con el orden real de ejecución. Vamos a echar un vistazo a la salida:

method_missing (bar) on b. Redeirecting to b.foo 
method_missing (bar) on b. Calling super 

A primera vista, esto da la impresión de que B#method_missing se llama antes de que el método de Singleton b.method_missing que eleva las dos preguntas que usted describe. En realidad, sin embargo, b.method_missing se llama correctamente primero. Esto se pone claro si nos fijamos en cómo se evalúa el estado de puts b.bar:

  1. b tiene ningún método bar, por lo que se llama b.method_missing con la cadena 'bar' como argumento.
  2. b.method_missing a su vez llama al método B#method_missing mediante el uso de la palabra clave super.
  3. B#method_missing utiliza puts a la salida de la primera línea se ha visto anteriormente
  4. el método singleton b.foo se llama
  5. la más exterior puts se lleva a cabo, lo que da salida a la cadena en b.method_missing junto con el valor de retorno de b.foo
+2

+1; golpéame. –

+0

Niklas, gracias por aclarar (y eliminar el código irrelevante). ¡Gracias por su respuesta! – dynex

+0

Ejecutarlo en el depurador, por supuesto, lo aclara. Debería haber hecho eso para empezar, lo siento chicos, y gracias por su paciencia. – dynex

Cuestiones relacionadas