2010-08-16 9 views
24

Cuando se envía un mensaje, un objeto Ruby busca para ver si tiene un método con ese nombre para responder. Su búsqueda de método busca en el siguiente orden y usa el primer método que encuentra.Ruby: determinar el origen del método?

  1. métodos Singleton definidos sobre sí misma (también conocidos como métodos en su "eigenclass")
  2. métodos definidos en su clase
  3. Cualquier módulos mezclan en su clase, en el orden inverso de la inclusión (sólo el primer inclusión de una El módulo dado tiene algún efecto: si la superclase incluye el módulo A, y la subclase lo incluye de nuevo, se ignora en la subclase; si la subclase incluye A, entonces B y A, se ignora la segunda A) (actualización: tenga en cuenta que fue escrito antes de que Module.prepend existiera)
  4. Su clase de padres
  5. Cualquier método de mezclado en la clase padre, el padre del padre, etc.

O, para decirlo más simplemente, lo que parece en sí misma, entonces todo en self.class.ancestors en el orden en que aparecen.

Esta ruta de búsqueda se sigue en el momento en que se llama al método; si crea una instancia de una clase, luego vuelve a abrir la clase y agrega un método o mezcla uno a través de un módulo, la instancia existente obtendrá acceso a ese método.

Si todo esto falla, se ve a ver si tiene un método method_missing, o si lo hace su clase, su clase padre, etc.

Mi pregunta es la siguiente: aparte de examinar el código a mano , o utilizando métodos de ejemplo como puts "I'm on module A!", ¿puede decir de dónde vino un método determinado? ¿Puede, por ejemplo, enumerar los métodos de un objeto y ver "éste está en la clase padre, este está en el módulo A, este está en la clase y anula la clase padre," etc.?

Respuesta

22

Object#method devuelve un objeto Method dando metadatos sobre un método determinado. Por ejemplo:

> [].method(:length).inspect 
=> "#<Method: Array#length>" 
> [].method(:max).inspect 
=> "#<Method: Array(Enumerable)#max>" 

en Ruby 1.8.7 y posteriores, puede utilizar Method#owner para determinar la clase o módulo que define el método.

Para obtener una lista de todos los métodos con el nombre de la clase o módulo en el que se definen se podría hacer algo como lo siguiente:

obj.methods.collect {|m| "#{m} defined by #{obj.method(m).owner}"} 
+0

puede obtener el método #owner en 1.8.6 utilizando la joya de backports. – rogerdpack

+5

Otro poco de genialidad: los objetos 'Method' también tienen un método' source_location'. "Ahora, ¿dónde está ese parche de mono molesto? ..." :) –

+0

No puedo creer que no tenía idea de eso. ¡Tan útil! Muchas gracias. – dimitarvp

9

Obtenga el objeto Método apropiado (o UnboundMethod) y solicite su owner. Entonces podría hacer method(:puts).owner y obtener Kernel.

+0

Su respuesta junto con la respuesta aceptada son luz pura en la oscuridad, hombre. ¡Gracias! – dimitarvp

1

Puede utilizar Object#method. Por ejemplo,

[1, 2, 3].method(:each_cons) # => #<Method: Array(Enumerable)#each_cons> 

indica que el método each_cons de una matriz proviene del módulo Enumerable.

4

para encontrar qué métodos de instancia se definen en A (pero no en superclases):

A.methods(false) 

para encontrar qué métodos de instancia se define en A y sus superclases:

A.methods 

para encontrar clase (o módulo) un método dado se define en:

method(:my_method).owner 

Para encontrar qué objeto es el receptor para un método dado:

+0

Para obtener tipos de métodos específicos: someobject.private_methods, someobject.public_methods, someobject.protected_methods, someobject.singleton_methods, SomeClass.instance_methods, SomeClass.private_instance_methods, SomeClass.protected_instance_methods, SomeClass.public_instance_methods (que es lo mismo que just .instance_methods). –

+0

'A.methods' debe leer' A.instance_methods' – Kelvin