Come ottenere il nome del metodo di chiamata?


161

c'è un modo in Ruby per trovare il nome del metodo chiamante all'interno di un metodo?

Per esempio:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end



Non un duplicato di "Ottieni il nome del metodo attualmente eseguito in Ruby." Questa domanda richiede il nome del metodo chiamante, non il nome del metodo corrente.
Wayne Conrad,

Risposte:


210
puts caller[0]

o forse...

puts caller[0][/`.*'/][1..-2]

5
Sì, vedere Kernel # chiamante, alias ruby-doc.org/core-1.8.7/classes/Kernel.html#M001073
DigitalRoss

10
Ciò fornisce il nome del metodo chiamante, ma non fornisce alcuna indicazione a quale modulo o classe appartiene il metodo. È possibile?
Thom

@thomthom Sì, è possibile, puoi chiamare self.class.name per vedere il nome della classe
Thorin,

Ottimo uso di regex come indice di stringa! Può anche usarecaller[0][/`(.*)'/,1]
aks il

1
Questo non sembra funzionare in Rails 5.2.1. Nel controller Rails questo ritorna "block in make_lambda". Immagino che questo sia solo per Ruby.
dcangulo,

164

In Ruby 2.0.0 è possibile utilizzare:

caller_locations(1,1)[0].label

È molto più veloce della soluzione Ruby 1.8+:

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

Sarà incluso in backportsquando avrò il tempo (o una richiesta pull!).


Vale la pena notare che questo non è disponibile in Rubinius.
Max

1
se stai usando pry, devi ignorare lo stacktrace di pry sembra ... non sembra esserci una soluzione predefinita per quello.
dtc,

6
Ora sembra essere caller_locations[0].labelsu Ruby 2.2.0 altrimenti hai sempre un send_actionrisultato
brcebn

1
come possiamo ottenere solo il metodo di chiamata app e ignorare la chiamata dei framework?
Matrix,

31

Usa caller_locations(1,1)[0].label(per rubino> = 2.0)

Modifica : la mia risposta diceva di usare __method__ma mi sbagliavo, restituiva il nome del metodo corrente.


1
@OswaldoFerreira Grazie, l'ho trovato su SO in un'altra risposta da qualche parte
Dorian

5
Questo non è corretto, restituisce il metodo corrente, non il metodo che ha chiamato il metodo corrente ...
thrice801

1
funziona come un fascino. Inoltre sembra essere molto più veloce dei metodi pre 2.0.
Dr.Strangelove,

21

Io uso

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

4
Qual è il vantaggio di questo rispetto all'approccio di DigitalRoss?
Andrew Grimm,

2
Più pulito e più preciso. Anziché eseguire la ricerca, utilizzare un metodo array per dividere i caratteri indesiderati in base alla posizione (che potrebbe essere errata).
Nuova Alessandria,

2
Perché non usare semplicemente il chiamante [0] [/ `(. *) '/, 1]? Non sono un guru delle espressioni regolari, ma sembra funzionare.
Collimarco,

7
@collimarco Fintanto che la stringa non contiene un valore 'al di là di quello che stai cercando (e presumo che non sia possibile), il risultato sarà lo stesso, certo. Tuttavia, [^']*funzionerà meglio poiché il motore regex smetterà di cercare di abbinare quella parte all'espressione nel momento in cui raggiunge una '(la tua versione andrà alla fine, quindi tornerà indietro perché non ha trovato una 'alla fine). La differenza è piuttosto trascurabile in questo caso ovviamente, ma è una buona abitudine evitare .nelle regex ove possibile.
Thor84no,

4

Che ne dite di

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

Molto più pulito imo.


3

Invece puoi scriverlo come funzione di libreria ed effettuare una chiamata ovunque sia necessario. Il codice è il seguente:

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

Per attivare il metodo del modulo sopra è necessario chiamare in questo modo: caller = CallChain.caller_method

codice di riferimento da


1
Un collegamento a una potenziale soluzione è sempre il benvenuto, ma per favore aggiungi un contesto attorno al collegamento in modo che i tuoi colleghi utenti abbiano qualche idea di cosa sia e perché sia ​​lì. Cita sempre la parte più pertinente di un link importante, nel caso in cui il sito di destinazione non sia raggiungibile o rimanga permanentemente offline. Tieni presente che essere a malapena più di un collegamento a un sito esterno è una possibile ragione del perché e come vengono eliminate alcune risposte? .
Xavi López,

@ XaviLópez ha aggiornato la risposta, per favore rettifica se sto sbagliando o qualcosa di sbagliato ... grazie per il suggerimento gentile :)
Karsale,

1
Grazie per aver migliorato la tua risposta. Sfortunatamente, non ho abbastanza conoscenze su Ruby per essere in grado di commentare correttamente questo post, ma la risposta ora sembra a posto. Ho rimosso il mio voto negativo. Buona fortuna :-)
Xavi López,

2

Per vedere le informazioni sul chiamante e sul chiamante in qualsiasi lingua, che si tratti di ruby, java o python, dovresti sempre guardare la traccia dello stack. In alcune lingue, come Rust e C ++, ci sono opzioni integrate nel compilatore per attivare una sorta di meccanismo di profilazione che è possibile visualizzare durante il runtime. Credo che ne esista uno per Ruby chiamato ruby-prof.

E come accennato in precedenza, potresti cercare nello stack di esecuzione il rubino. Questo stack di esecuzione è un array contenente oggetti di posizione backtrace.

Fondamentalmente tutto ciò che devi sapere su questo comando è il seguente:

chiamante (inizio = 1, lunghezza = zero) → array o zero

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.