Wie erhalte ich den Namen der aufrufenden Methode?

161

Gibt es in Ruby eine Möglichkeit, den Namen der aufrufenden Methode innerhalb einer Methode zu finden?

Beispielsweise:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end
jrichardlai
quelle
1
Mögliches Duplikat von Holen Sie sich den Namen der aktuell ausgeführten Methode in Ruby
Darshan Rivka Whittle
Rufen Sie das Objekt auf: stackoverflow.com/questions/2703136/…
Ciro Santilli 10 冠状 病 六四 事件 10
Kein Duplikat von "Ruft den Namen der aktuell ausgeführten Methode in Ruby ab." Diese Frage fragt nach dem Namen der aufrufenden Methode, nicht nach dem Namen der aktuellen Methode.
Wayne Conrad

Antworten:

210
puts caller[0]

oder vielleicht...

puts caller[0][/`.*'/][1..-2]
DigitalRoss
quelle
5
Ja, siehe Kernel # Aufrufer, auch bekannt als ruby-doc.org/core-1.8.7/classes/Kernel.html#M001073
DigitalRoss
10
Das gibt den Namen der aufrufenden Methode an, gibt aber keinen Hinweis darauf, zu welchem ​​Modul oder welcher Klasse die Methode gehört. Ist das möglich?
thomthom
@thomthom Ja, das ist möglich, Sie können self.class.name aufrufen, um den Klassennamen zu sehen
Thorin
Hervorragende Verwendung von Regex als String-Index! Kann auch verwendencaller[0][/`(.*)'/,1]
aks
1
Dies scheint in Rails 5.2.1 nicht zu funktionieren. Im Rails-Controller wird dies zurückgegeben "block in make_lambda". Ich denke, das ist nur für Ruby.
Dcangulo
164

In Ruby 2.0.0 können Sie Folgendes verwenden:

caller_locations(1,1)[0].label

Es ist viel schneller als die Ruby 1.8+ Lösung:

caller[0][/`([^']*)'/, 1]

Wird aufgenommen, backportswenn ich Zeit habe (oder eine Pull-Anfrage!).

Marc-André Lafortune
quelle
Es ist erwähnenswert, dass dies in Rubinius nicht verfügbar ist.
Max
1
Wenn Sie Pry verwenden, müssen Sie den Pry-Stacktrace ignorieren. Es scheint, dass es dafür keine Standardlösung gibt.
dtc
6
Jetzt scheint es caller_locations[0].labelauf Ruby 2.2.0 zu sein, sonst haben Sie immer ein send_actionErgebnis
brcebn
1
Wie können wir nur die App-Methode aufrufen und den Framework-Aufruf ignorieren?
Matrix
31

Verwenden Sie caller_locations(1,1)[0].label(für Rubin> = 2,0)

Bearbeiten : Meine Antwort lautete "verwenden", __method__aber ich habe mich geirrt, es wird der aktuelle Methodenname zurückgegeben.

Dorian
quelle
1
@OswaldoFerreira Danke, fand es auf SO in einer anderen Antwort irgendwo
Dorian
5
Dies ist falsch, es gibt die aktuelle Methode zurück, nicht die Methode, die die aktuelle Methode aufgerufen hat ...
dreimal 801
1
klappt wunderbar. Scheint auch viel schneller zu sein als Methoden vor 2.0.
Dr. Strangelove
21

ich benutze

caller[0][/`([^']*)'/, 1]
Héctor García
quelle
4
Was ist der Vorteil gegenüber dem Ansatz von DigitalRoss?
Andrew Grimm
2
Sauberer und präziser. Anstatt die Suche durchzuführen, verwenden Sie eine Array-Methode, um unerwünschte Zeichen basierend auf der Position aufzuteilen (was falsch sein könnte).
New Alexandria
2
Warum nicht einfach den Anrufer [0] [/ `(. *) '/, 1] verwenden? Ich bin kein Guru für reguläre Ausdrücke, aber es scheint zu funktionieren.
Collimarco
7
@collimarco Solange der String kein 'über das gesuchte hinaus enthält (und ich nehme an, dass dies nicht möglich ist), wird das Ergebnis sicher dasselbe sein. Die [^']*Leistung wird jedoch besser, da die Regex-Engine nicht mehr versucht, diesem Teil den Ausdruck zuzuordnen, sobald er einen erreicht '(Ihre Version wird bis zum Ende gehen und dann zurückverfolgen, weil sie 'am Ende keinen gefunden hat ). Der Unterschied ist in diesem Fall natürlich vernachlässigbar, aber es ist eine gute Angewohnheit, .Regexe nach Möglichkeit zu vermeiden .
Thor84no
4

Wie wäre es mit

caller[0].split("`").pop.gsub("'", "")

Viel sauberer imo.

dreimal801
quelle
3

Stattdessen können Sie es als Bibliotheksfunktion schreiben und bei Bedarf einen Anruf tätigen. Der Code lautet wie folgt:

module CallChain
  def self.caller_method(depth=1)
    parse_caller(caller(depth+1).first).last
  end

  private

  # Copied from ActionMailer
  def self.parse_caller(at)
    if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
      file   = Regexp.last_match[1]
      line   = Regexp.last_match[2].to_i
      method = Regexp.last_match[3]
      [file, line, method]
    end
  end
end

Um die obige Modulmethode auszulösen, müssen Sie Folgendes aufrufen: caller = CallChain.caller_method

Code-Referenz von

amit karsale
quelle
1
Ein Link zu einer möglichen Lösung ist immer willkommen. Fügen Sie jedoch einen Kontext um den Link hinzu, damit Ihre Mitbenutzer eine Vorstellung davon haben, was es ist und warum es dort ist. Zitieren Sie immer den relevantesten Teil eines wichtigen Links, falls die Zielwebsite nicht erreichbar ist oder dauerhaft offline geht. Berücksichtigen Sie, dass kaum mehr als ein Link zu einer externen Website ein möglicher Grund dafür ist, warum und wie einige Antworten gelöscht werden. .
Xavi López
@ XaviLópez haben die Antwort aktualisiert, bitte korrigieren, wenn ich etwas falsch mache oder etwas falsch mache ... Danke für den freundlichen Vorschlag :)
amit karsale
1
Vielen Dank für die Verbesserung Ihrer Antwort. Leider habe ich nicht genug Wissen über Ruby, um diesen Beitrag richtig kommentieren zu können, aber die Antwort sieht jetzt in Ordnung aus. Ich habe meine Ablehnung entfernt. Viel Glück :-)
Xavi López
2

Um die Anrufer- und Angerufeneninformationen in einer beliebigen Sprache anzuzeigen, sei es Ruby, Java oder Python, sollten Sie sich immer die Stapelverfolgung ansehen. In einigen Sprachen wie Rust und C ++ sind im Compiler Optionen integriert, mit denen Sie einen Profilierungsmechanismus aktivieren können, den Sie zur Laufzeit anzeigen können. Ich glaube, es gibt eine für Ruby namens Ruby-Prof.

Und wie oben erwähnt, können Sie im Ausführungsstapel nach Ruby suchen. Dieser Ausführungsstapel ist ein Array, das Backtrace-Standortobjekte enthält.

Im Wesentlichen müssen Sie über diesen Befehl nur Folgendes wissen:

Aufrufer (Start = 1, Länge = Null) → Array oder Null

user3769125
quelle