Frage

Wir hatten vor kurzem ein Problem, wo, nach einer Reihe von Commits stattgefunden hatte, ein Back-End-Prozess ausgeführt fehlgeschlagen. Nun, wir waren gute kleine Jungen und Mädchen und lief rake test nach jedem Check-in, aber aufgrund einiger Merkwürdigkeiten in Rails' Bibliothek Laden, es trat nur, wenn wir es lief direkt von Mongrel im Produktionsmodus.

raupen ich den Fehler und es war aufgrund einer neuen Rails gem eine Methode in der String-Klasse in einer Art und Weise zu überschreiben, die eine schmale Verwendung in der Runtime-Rails-Code brach.

Wie auch immer, lange Geschichte kurz, gibt es eine Möglichkeit, zur Laufzeit, zu fragen, Rubin, wo eine Methode definiert wurde? So etwas wie whereami( :foo ) die /path/to/some/file.rb line #45 zurückkehrt? In diesem Fall sagt mir, dass es in der Klasse String definiert wurde wäre nicht hilfreich, weil es durch eine Bibliothek überlastet war.

Ich kann nicht garantieren, dass die Quelle lebt in meinem Projekt wird so greppen für 'def foo' nicht unbedingt mir geben, was ich brauche, nicht zu erwähnen, wenn ich viele def foo ist, manchmal weiß ich nicht, bis Laufzeit, welche ich kann mit Hilfe sein.

War es hilfreich?

Lösung

Das ist wirklich zu spät, aber hier ist, wie Sie feststellen können, wo eine Methode definiert ist:

http://gist.github.com/76951

# How to find out where a method comes from.
# Learned this from Dave Thomas while teaching Advanced Ruby Studio
# Makes the case for separating method definitions into
# modules, especially when enhancing built-in classes.
module Perpetrator
  def crime
  end
end

class Fixnum
  include Perpetrator
end

p 2.method(:crime) # The "2" here is an instance of Fixnum.
#<Method: Fixnum(Perpetrator)#crime>

Wenn Sie Ruby 1.9+ sind, können Sie a href verwenden <= "http://www.ruby-doc.org/core-1.9.3/Method.html#method-i-source_location" rel = "noreferrer"> source_location

require 'csv'

p CSV.new('string').method(:flock)
# => #<Method: CSV#flock>

CSV.new('string').method(:flock).source_location
# => ["/path/to/ruby/1.9.2-p290/lib/ruby/1.9.1/forwardable.rb", 180]

Beachten Sie, dass dies nicht alles funktioniert, wie native kompilierten Code. Die Methode Klasse hat einige nette Funktionen, auch, wie Methode # Besitzer , die die Datei zurückgibt, wo die Methode definiert ist.

EDIT: Auch die __file__ und __line__ und Hinweise für REE in der anderen Antwort sehen, sie sind auch nützlich. - wg

Andere Tipps

Sie können tatsächlich ein wenig weiter als die Lösung oben gehen. Für Ruby 1.8 Enterprise Edition, gibt es die __file__ und __line__ Methoden auf Method Instanzen:

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

Für Ruby 1.9 und darüber hinaus gibt es source_location (dank 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]

Ich komme spät auf diesen Thread und bin überrascht, dass niemand Method#owner erwähnt.

class A; def hello; puts "hello"; end end
class B < A; end
b = B.new
b.method(:hello).owner
=> A

Kopieren meiner Antwort von einer neueren ähnlicher Frage , die neuen Informationen ergänzt dieses Problem.

Rubin 1.9 hat Methode namens Quellpfad :

  

Gibt die Ruby-Quelldateinamen und die Zeilennummer diese Methode oder gleich Null enthalten, wenn diese Methode nicht in Ruby (das heißt nativ) definiert wurde

Dies wurde zurück portiert auf 1.8.7 dieses Juwel:

Sie können also für das Verfahren anfordern:

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

Und dann fragen Sie nach dem source_location dieser Methode:

m.source_location

Dies wird ein Array mit Dateinamen und die Zeilennummer zurück. Z. B für ActiveRecord::Base#validates dies zurück:

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]

Für die Klassen und Module, ist Rubin nicht eingebaute Unterstützung bieten, aber es ist ein ausgezeichnetes Gist aus, dass es auf source_location baut Datei für eine bestimmte Methode oder die ersten Datei für eine Klasse zurück, wenn keine Methode angegeben wurde:

In Aktion:

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]

Auf Macs mit Textmate installiert, das auch den Editor an der angegebenen Stelle erscheint.

Dies kann helfen, aber sie würde es selbst codieren. Geklebte aus dem Blog:

  

Rubin bietet eine method_added ()   Rückruf, der jedes Mal, wenn ein aufgerufen wird   Verfahren hinzugefügt wird oder in einem neu definiert   Klasse. Es ist ein Teil der Modulklasse,   und jede Klasse ist ein Modul. Es gibt   auch zwei verwandte Rückrufe genannt   method_removed () und   (Method_undefined).

http://scie.nti.st / 2008/9/17 / Making-Methoden-unveränderlich-in-ruby

Wenn Sie die Methode zum Absturz bringen können, erhalten Sie eine Rückverfolgung erhalten, die Ihnen genau sagen, wo es ist.

Leider, wenn Sie es nicht zum Absturz bringen können, dann können Sie nicht herausfinden, wo es definiert wurde. Wenn Sie mit dem Verfahren zum Affen versuchen, indem sie sie überschreiben oder überschreiben sie, dann wird jeder Absturz kommt aus Ihrer überschrieben oder überschriebene Methode, und es wird keine Verwendung sein.

Praktische Wege, Methoden Absturz:

  1. Pass nil wo sie es verbietet, -. Eine Menge Zeit die Methode eine ArgumentError erhöhen wird oder die allgegenwärtige NoMethodError auf einer Null-Klasse
  2. Wenn Sie in Kenntnis des Verfahrens haben, und Sie wissen, dass das Verfahren wiederum eine andere Methode aufruft, dann können Sie die andere Methode overrwrite, und im Inneren, dass erhöhen.

Vielleicht kann der #source_location zu finden, in denen das Verfahren kommen.

ex:

ModelName.method(:has_one).source_location

Zurück

[project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/associations.rb", line_number_of_where_method_is]

oder

ModelName.new.method(:valid?).source_location

Zurück

[project_path/vendor/ruby/version_number/gems/activerecord-number/lib/active_record/validations.rb", line_number_of_where_method_is]

Sehr spät Antwort :) Aber früher Antworten haben mir nicht helfen

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

Sie könnten in der Lage sein, so etwas zu tun:

foo_finder.rb:

 class String
   def String.method_added(name)
     if (name==:foo)
        puts "defining #{name} in:\n\t"
        puts caller.join("\n\t")
     end
   end
 end

Dann gewährleisten foo_finder zuerst geladen wird mit so etwas wie

ruby -r foo_finder.rb railsapp

(Ich habe nur mit Schienen durcheinander, so dass ich weiß nicht genau, aber ich glaube, es gibt einen Weg, es zu starten Art wie diese.)

Dies zeigt Ihnen alle Re-Definitionen von String # foo. Mit einer wenig Meta-Programmierung, können Sie es für verallgemeinern, was auch immer gewünschte Funktion. Aber es braucht, bevor die Datei geladen werden, die tatsächlich funktioniert die Neudefinition.

Sie können immer einen Backtrace von wo Sie sind von caller() verwendet wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top