¿Cómo obtener el nombre del método de llamada?

161

¿Hay alguna manera en Ruby para encontrar el nombre del método de llamada dentro de un método?

Por ejemplo:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end
jrichardlai
fuente
obtener objeto de llamada: stackoverflow.com/questions/2703136/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
No es un duplicado de "Obtener el nombre del método ejecutado actualmente en Ruby". Esta pregunta solicita el nombre del método de llamada, no el nombre del método actual.
Wayne Conrad

Respuestas:

210
puts caller[0]

o quizás...

puts caller[0][/`.*'/][1..-2]
DigitalRoss
fuente
55
Sí, vea Kernel # caller, también conocido
DigitalRoss
10
Eso le da el nombre del método de llamada, pero no da ninguna indicación a qué módulo o clase pertenece el método. ¿Es eso posible?
Thom
@thomthom Sí, eso es posible, puedes llamar a self.class.name para ver el nombre de la clase
Thorin el
Excelente uso de expresiones regulares como un índice de cadena! También se puede usarcaller[0][/`(.*)'/,1]
aks el
1
Esto no parece funcionar en Rails 5.2.1. En el controlador Rails, esto vuelve "block in make_lambda". Supongo que esto es solo para Ruby.
dcangulo
164

En Ruby 2.0.0, puedes usar:

caller_locations(1,1)[0].label

Es mucho más rápido que la solución Ruby 1.8+:

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

Se incluirá backportscuando tenga el tiempo (o una solicitud de extracción).

Marc-André Lafortune
fuente
Vale la pena señalar que esto no está disponible en Rubinius.
Max
1
si estás usando palanca, tienes que ignorar el rastro de pila de palanca que parece ... no parece haber una solución predeterminada para eso.
dtc
66
Ahora parece estar caller_locations[0].labelen Ruby 2.2.0, de lo contrario, siempre tendrá send_actionresultados
brcebn
1
¿Cómo podemos obtener solo el método de aplicación de llamada e ignorar la llamada de frameworks?
Matrix
31

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

Editar : mi respuesta decía usar __method__pero estaba equivocado, devuelve el nombre del método actual.

dorio
fuente
1
@OswaldoFerreira Gracias, lo encontré en SO en otra respuesta en alguna parte
Dorian
55
Esto es incorrecto, devuelve el método actual, no el método que llamó al método actual ...
thrice801
1
Funciona de maravilla. También parece ser mucho más rápido que los métodos pre 2.0.
Dr.Strangelove
21

yo suelo

caller[0][/`([^']*)'/, 1]
Héctor García
fuente
44
¿Cuál es la ventaja de esto sobre el enfoque de DigitalRoss?
Andrew Grimm
2
Más limpio y más preciso. En lugar de hacer la búsqueda, utilice un método de matriz para dividir los caracteres no deseados en función de la posición (lo que podría ser incorrecto).
Nueva Alejandría
2
¿Por qué no usar simplemente la persona que llama [0] [/ `(. *) '/, 1]? No soy un gurú de las expresiones regulares, pero parece funcionar.
collimarco
77
@collimarco Mientras la Cadena no contenga 'más allá de la que está buscando (y supongo que no puede), el resultado será el mismo, claro. Sin embargo, [^']*funcionará mejor ya que el motor de expresiones regulares dejará de intentar igualar esa parte con la expresión en el momento en que llegue a '(su versión irá al final, luego retrocederá porque no encontró un 'al final). La diferencia es bastante insignificante en este caso, por supuesto, pero es un buen hábito evitar .en expresiones regulares siempre que sea posible.
Thor84no
4

Qué tal si

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

Mucho más limpio imo.

thrice801
fuente
3

En su lugar, puede escribirlo como función de biblioteca y hacer una llamada donde sea necesario. El código es el siguiente:

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 activar el método del módulo anterior, debe llamar así: caller = CallChain.caller_method

código de referencia de

amit karsale
fuente
1
Siempre es bienvenido un enlace a una solución potencial, pero agregue contexto alrededor del enlace para que sus usuarios tengan una idea de qué es y por qué está allí. Siempre cite la parte más relevante de un enlace importante, en caso de que no se pueda acceder al sitio de destino o se desconecte permanentemente. Tenga en cuenta que ser apenas más que un enlace a un sitio externo es una posible razón de por qué y cómo se eliminan algunas respuestas. .
Xavi López
@ XaviLópez han actualizado la respuesta, PLZ rectificar si estoy haciendo mal o Somthing equivocada ... thnx para la sugerencia buena :)
Amit karsale
1
Gracias por mejorar tu respuesta. Desafortunadamente, no tengo suficiente conocimiento sobre Ruby para poder comentar adecuadamente sobre esta publicación, pero la respuesta parece correcta ahora. He eliminado mi voto negativo. Mejor suerte :-)
Xavi López
2

Para ver la información de la persona que llama y de la persona que llama en cualquier idioma, ya sea ruby, java o python, siempre querrá ver el seguimiento de la pila. En algunos lenguajes, como Rust y C ++, hay opciones integradas en el compilador para activar algún tipo de mecanismo de creación de perfiles que puede ver durante el tiempo de ejecución. Creo que existe uno para Ruby llamado ruby-prof.

Y como se mencionó anteriormente, puede buscar rubí en la pila de ejecución. Esta pila de ejecución es una matriz que contiene objetos de ubicación de rastreo.

Esencialmente, todo lo que necesita saber sobre este comando es el siguiente:

llamador (inicio = 1, longitud = nulo) → matriz o nulo

usuario3769125
fuente