2011-06-19 12 views
7

¿Existe alguna manera rápida de rastrear los métodos que se invocan sobre un objeto? A menudo, cuando estoy trabajando con una gema en un nivel justo debajo de su interfaz pública, me encuentro con errores que son difíciles de rastrear. Finalmente, termino rastreando el objeto a través del código fuente y manteniendo todo en mi cabeza.¿Existe una manera sencilla de registrar los métodos que se invocan sobre un objeto en Ruby?

Pero sería bueno poder llamar algo así como #log_method_calls en un objeto para que, por ejemplo, todos los métodos invocados se impriman en stdout o algo así. ¿Hay alguna forma de lograr esto?

+0

Es posible que desee ver en [ruby-debug] (http://bashdb.sourceforge.net/ruby-debug.html). Tiene un poco de curva de aprendizaje, pero probablemente lo compensará con creces con el tiempo ahorrado, dado lo que está haciendo. – coreyward

Respuesta

5

Existen varios métodos para hacerlo, dependiendo de la situación.

Si es posible crear un objeto nuevo en lugar de lo observado, puede escribir fácilmente una clase de observador utilizando method_missing.

class LogProxy 
    def initialize obj 
    @obj = obj 
    end 

    def method_missing(name, *args) 
    puts "#{name} => #{args.to_s}" 
    @desk.send(name, *args) 
    end 
end 

Si no es posible, igual puede utilizar alias_method. Es un poco más complicado, pero usando Module.instance_methods puedes encadenar todos los métodos de cualquier cosa.

Algo así como:

module Logger 

    def self.included(mod) 
    mod.instance_methods.each do |m| 
     next if m =~ /with_logging/ 
     next if m =~ /without_logging/ 

     mod.class_eval do 

     define_method "#{m}_with_logging" do |*args| 
      puts "#{m} called #{args.to_s}" 
      self.send_without_logging "#{m}_without_logging", *args 
     end 

     alias_method "#{m}_without_logging", m 
     alias_method m, "#{m}_with_logging" 
     end 

    end 
    end 

end 

TargetClass.send(:include, Logger) 
+0

Gracias! Dos soluciones muy inteligentes y lógicas. La segunda solución también inspira la idea de ampliar la clase 'Object' con un método como' # log_method_calls' que crea una nueva clase con la mezcla 'Logger' sobre la marcha para que pueda hacerlo en cualquier punto de la aplicación. –

Cuestiones relacionadas