Recientemente tuvimos un problema en el que, después de una serie de confirmaciones, no se pudo ejecutar un proceso de fondo. Ahora, éramos buenos niños y niñas y corríamos rake test
después de cada registro, pero, debido a algunas rarezas en la carga de la biblioteca de Rails, solo ocurría cuando lo ejecutamos directamente desde Mongrel en modo de producción.
Rastreé el error y se debió a una nueva gema de Rails que sobrescribió un método en la clase String de una manera que rompió un uso limitado en el código de Rails en tiempo de ejecución.
De todos modos, para resumir, ¿hay alguna manera, en tiempo de ejecución, de preguntarle a Ruby dónde se ha definido un método? Algo así whereami( :foo )
regresa /path/to/some/file.rb line #45
? En este caso, decirme que se definió en la clase String no sería útil, porque alguna biblioteca lo sobrecargó.
No puedo garantizar que la fuente viva en mi proyecto, por lo que buscarla 'def foo'
no necesariamente me dará lo que necesito, sin mencionar si tengo muchas def foo
, a veces no sé hasta el momento de ejecución cuál puedo estar usando.
fuente
Respuestas:
Esto es realmente tarde, pero así es cómo puedes encontrar dónde se define un método:
http://gist.github.com/76951
Si estás usando Ruby 1.9+, puedes usar
source_location
Tenga en cuenta que esto no funcionará en todo, como el código compilado nativo. La clase Method también tiene algunas funciones ordenadas, como Method # owner, que devuelve el archivo donde se define el método.
EDIT: consulta las
__file__
y los__line__
y las notas para REE en la otra respuesta, que están muy bien también. - wgfuente
owner
Método2.method(:crime)
?Fixnum
method_missing
. Entonces, si tiene un módulo o una clase ancestral con unclass_eval
odefine_method
dentro demethod_missing
, entonces este método no funcionará.De hecho, puede ir un poco más allá de la solución anterior. Para Ruby 1.8 Enterprise Edition, existen los métodos
__file__
y__line__
en lasMethod
instancias:Para Ruby 1.9 y más allá, hay
source_location
(¡gracias Jonathan!):fuente
__file__
y__line__
en cualquierMethod
instancia de clase, por ejemplo:method(:method).__file__
.m.__file__
ym.__line__
han sido reemplazados porm.source_location
.Llego tarde a este hilo y me sorprende que nadie lo haya mencionado
Method#owner
.fuente
Method#parameters
.Copiando mi respuesta de una pregunta similar más reciente que agrega nueva información a este problema.
Ruby 1.9 tiene un método llamado source_location :
Esto ha sido respaldado a respaldado 1.8.7 por esta gema:
Entonces puede solicitar el método:
Y luego pregunta por el
source_location
ese método:Esto devolverá una matriz con nombre de archivo y número de línea. Por ejemplo para
ActiveRecord::Base#validates
esto vuelve:Para las clases y los módulos, Ruby no ofrece soporte integrado, pero existe una excelente esencia que se basa en
source_location
devolver el archivo para un método dado o el primer archivo para una clase si no se especificó ningún método:En acción:
En Macs con TextMate instalado, esto también muestra el editor en la ubicación especificada.
fuente
Esto puede ayudar, pero tendría que codificarlo usted mismo. Pegado del blog:
http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby
fuente
Si puede bloquear el método, obtendrá una traza inversa que le dirá exactamente dónde está.
Desafortunadamente, si no puede bloquearlo, entonces no puede averiguar dónde se ha definido. Si intenta simular el método sobrescribiéndolo o anulándolo, entonces cualquier bloqueo vendrá de su método sobrescrito o anulado, y no servirá de nada.
Formas útiles de métodos de bloqueo:
nil
donde lo prohíba: muchas veces el método generará unaArgumentError
presencia siempre presenteNoMethodError
en una clase nula.fuente
require 'ruby-debug'; debugger
donde desee ingresar.Tal vez el
#source_location
puede ayudar a encontrar de dónde viene el método.ex:
Regreso
O
Regreso
fuente
Respuesta muy tardía :) Pero las respuestas anteriores no me ayudaron
fuente
nil
?nil
.Es posible que pueda hacer algo como esto:
foo_finder.rb:
Luego, asegúrese de que foo_finder se cargue primero con algo como
(Solo me he metido con los rieles, así que no sé exactamente, pero imagino que hay una manera de comenzar así).
Esto le mostrará todas las redefiniciones de String # foo. Con un poco de metaprogramación, puede generalizarlo para cualquier función que desee. Pero debe cargarse ANTES del archivo que realmente realiza la redefinición.
fuente
Siempre puede obtener un seguimiento de dónde está utilizando
caller()
.fuente