Como obter o nome do método de chamada?

161

existe uma maneira no Ruby encontrar o nome do método de chamada dentro de um método?

Por exemplo:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end
jrichardlai
fonte
1
possível duplicata Obter o nome do método atualmente em execução em Ruby
Darshan Rivka Whittle
obter objeto de chamada: stackoverflow.com/questions/2703136/…
Ciro Santilli (
Não é uma duplicata de "Obter o nome do método atualmente executado no Ruby". Esta pergunta pede o nome do método de chamada, não o nome do método atual.
Wayne Conrad

Respostas:

210
puts caller[0]

ou talvez...

puts caller[0][/`.*'/][1..-2]
DigitalRoss
fonte
5
Sim, consulte Kernel # caller, também conhecido como ruby-doc.org/core-1.8.7/classes/Kernel.html#M001073
DigitalRoss
10
Isso fornece o nome do método de chamada, mas não fornece nenhuma indicação a qual módulo ou classe o método pertence. Isso é possível?
Thomthom 10/11/12
@thomthom Sim, isso é possível, você pode chamar self.class.name para ver o nome da classe
Thorin
Excelente uso de regex como um índice de string! Também pode usarcaller[0][/`(.*)'/,1]
aks
1
Isso não parece funcionar no Rails 5.2.1. No controlador Rails, isso retorna "block in make_lambda". Eu acho que isso é apenas para Ruby.
dcangulo
164

No Ruby 2.0.0, você pode usar:

caller_locations(1,1)[0].label

É muito mais rápido que a solução Ruby 1.8+:

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

Será incluído backportsquando receber a hora (ou uma solicitação de recebimento!).

Marc-André Lafortune
fonte
Vale a pena notar que isso não está disponível no Rubinius.
Max
1
se você estiver usando o alavanca, você deve ignorar o rastreamento da alavanca que parece ... não parece haver uma solução padrão para isso.
dtc
6
Agora parece que está caller_locations[0].labelno Ruby 2.2.0, caso contrário, você sempre terá send_actionresultado.
brcebn
1
como podemos obter apenas o método de aplicativo de chamada e ignorar a chamada de estruturas?
Matrix
31

Use caller_locations(1,1)[0].label(para ruby> = 2.0)

Edit : Minha resposta estava dizendo para usar, __method__mas eu estava errado, ele retorna o nome do método atual.

Dorian
fonte
1
@OswaldoFerreira Obrigado, encontrei no SO em outra resposta em algum lugar #
Dorian
5
Isso é incorreto, ele retorna método atual, não o método que chamou o método atual ...
thrice801
1
Funciona como um encanto. Também parece ser muito mais rápido que os métodos anteriores à 2.0.
precisa saber é o seguinte
21

eu uso

caller[0][/`([^']*)'/, 1]
Héctor García
fonte
4
Qual é a vantagem disso em relação à abordagem da DigitalRoss?
Andrew Grimm
2
Mais limpo e preciso. Em vez de fazer a pesquisa, use um método de matriz para dividir caracteres indesejados com base na posição (que pode estar incorreta).
New Alexandria
2
Por que não usar simplesmente o chamador [0] [/ `(. *) '/, 1]? Eu não sou um guru sobre expressões regulares, mas parece funcionar.
Collimarco
7
@ collimarco Contanto que a String não contenha uma 'além da que você está procurando (e presumo que não possa), o resultado será o mesmo, com certeza. No entanto, [^']*terá um desempenho melhor, pois o mecanismo regex deixará de tentar corresponder a essa parte a expressão no momento em que atingir uma '(sua versão será finalizada e, em seguida, retornará porque não encontrou uma 'no final). A diferença é bastante insignificante nesse caso, é claro, mas é um bom hábito evitar .em regexes sempre que possível.
Thor84no
4

E se

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

Muito mais limpo.

thrice801
fonte
3

Em vez disso, você pode escrevê-lo como função de biblioteca e fazer uma chamada sempre que necessário. O código é o seguinte:

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

Para acionar o método do módulo acima, você precisa chamar assim: caller = CallChain.caller_method

referência de código de

amit karsale
fonte
1
Um link para uma solução em potencial é sempre bem-vindo, mas adicione contexto ao link para que seus colegas usuários tenham uma idéia do que é e por que está lá. Sempre cite a parte mais relevante de um link importante, caso o site de destino esteja inacessível ou fique permanentemente offline. Leve em conta que ser pouco mais que um link para um site externo é uma possível razão para Por que e como algumas respostas são excluídas? .
Xavi López
@ XaviLópez ter atualizado a resposta, plz corrigir se estou fazendo de errado ou somthing enganado ... thnx para o tipo sugestão :)
Amit karsale
1
Obrigado por melhorar sua resposta. Infelizmente, não tenho conhecimento suficiente sobre Ruby para poder comentar adequadamente sobre este post, mas a resposta parece boa agora. Eu removi meu voto negativo. Boa sorte :-)
Xavi López
2

Para ver as informações do chamador e do destinatário em qualquer idioma, seja ruby, java ou python, você sempre desejaria examinar o rastreamento da pilha. Em algumas linguagens, como Rust e C ++, há opções integradas no compilador para ativar algum tipo de mecanismo de criação de perfil que você pode exibir durante o tempo de execução. Eu acredito que existe um para Ruby chamado ruby-prof.

E, como mencionado acima, você pode procurar na pilha de execução por ruby. Essa pilha de execução é uma matriz que contém objetos de localização de backtrace.

Basicamente, tudo o que você precisa saber sobre este comando é o seguinte:

chamador (início = 1, comprimento = nulo) → matriz ou nulo

user3769125
fonte