[ruby-on-rails] Comment trouver où une méthode est définie lors de l'exécution?


4 Answers

Vous pouvez aller un peu plus loin que la solution ci-dessus. Pour Ruby 1.8 Enterprise Edition, il existe les méthodes __file__ et __line__ sur les instances de Method :

require 'rubygems'
require 'activesupport'

m = 2.days.method(:ago)
# => #<Method: Fixnum(ActiveSupport::CoreExtensions::Numeric::Time)#ago>

m.__file__
# => "/Users/james/.rvm/gems/ree-1.8.7-2010.01/gems/activesupport-2.3.8/lib/active_support/core_ext/numeric/time.rb"
m.__line__
# => 64

Pour Ruby 1.9 et au-delà, il y a source_location (merci Jonathan!):

require 'active_support/all'
m = 2.days.method(:ago)
# => #<Method: Fixnum(Numeric)#ago>    # comes from the Numeric module

m.source_location   # show file and line
# => ["/var/lib/gems/1.9.1/gems/activesupport-3.0.6/.../numeric/time.rb", 63]
Question

Nous avons récemment eu un problème où, après une série de validations, un processus dorsal n'a pas fonctionné. Maintenant, nous étions de bons petits garçons et filles et nous faisions des rake test après chaque check-in mais, à cause de certaines bizarreries dans le chargement de la bibliothèque de Rails, cela n'arrivait que lorsque nous l'utilisions directement en Mongolie.

J'ai dépisté le bug et c'était dû à un nouveau gem Rails qui écrasait une méthode dans la classe String d'une manière qui cassait une utilisation étroite dans le code Rails d'exécution.

Quoi qu'il en soit, en bref, y a-t-il un moyen, au moment de l'exécution, de demander à Ruby où une méthode a été définie? Quelque chose comme whereami( :foo ) qui retourne /path/to/some/file.rb line #45 ? Dans ce cas, me dire qu'il était défini dans la classe String ne serait pas utile, car il était surchargé par une bibliothèque.

Je ne peux pas garantir que la source soit présente dans mon projet, donc le fait de vouloir 'def foo' ne me donnera pas forcément ce dont j'ai besoin, pas plus si j'ai beaucoup de def foo , parfois je ne sais pas avant peut être utilisé.




Réponse très tard :) Mais les réponses précédentes ne m'a pas aidé

set_trace_func proc{ |event, file, line, id, binding, classname|
  printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
}
# call your method
set_trace_func nil



Vous pouvez toujours obtenir une trace d'où vous êtes en utilisant caller() .




Copier ma réponse à partir d'une question similaire plus récente qui ajoute de nouvelles informations à ce problème.

Ruby 1.9 a une méthode appelée source_location :

Renvoie le nom de fichier source Ruby et le numéro de ligne contenant cette méthode ou nil si cette méthode n'a pas été définie dans Ruby (natif)

Ceci a été rétroporté à 1.8.7 par cette gemme:

Vous pouvez donc demander la méthode:

m = Foo::Bar.method(:create)

Et puis demandez la source_location de cette méthode:

m.source_location

Cela retournera un tableau avec le nom de fichier et le numéro de ligne. Par exemple, pour ActiveRecord::Base#validates ces retours:

ActiveRecord::Base.method(:validates).source_location
# => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]

Pour les classes et les modules, Ruby n'offre pas de support intégré, mais il existe un excellent Gist basé sur source_location pour renvoyer un fichier pour une méthode donnée ou un premier fichier pour une classe si aucune méthode n'a été spécifiée:

En action:

where_is(ActiveRecord::Base, :validates)

# => ["/Users/laas/.rvm/gems/ruby-1.9.2-p0@arveaurik/gems/activemodel-3.2.2/lib/active_model/validations/validates.rb", 81]

Sur les Mac équipés de TextMate, l'éditeur est également affiché à l'emplacement spécifié.




Si vous pouvez planter la méthode, vous obtiendrez une trace qui vous dira exactement où elle se trouve.

Malheureusement, si vous ne pouvez pas le planter, vous ne pouvez pas savoir où il a été défini. Si vous tentez de singe avec la méthode en l'écrasant ou en l'écrasant, alors tout plantage viendra de votre méthode écrasée ou surchargée, et cela ne servira à rien.

Façons utiles de plantage des méthodes:

  1. Passe nil là où il l'interdit - la plupart du temps la méthode soulèvera une ArgumentError ou le toujours NoMethodError sur une classe nulle.
  2. Si vous avez une connaissance approfondie de la méthode, et que vous savez que la méthode appelle à son tour une autre méthode, vous pouvez écraser l'autre méthode et l'augmenter à l'intérieur.



Related