Jak uzyskać nazwę metody wywołującej?

161

czy w Rubim jest sposób, aby znaleźć nazwę metody wywołującej wewnątrz metody?

Na przykład:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end
jrichardlai
źródło
1
możliwy duplikat Pobierz nazwę aktualnie wykonywanej metody w Rubim
Darshan Rivka Whittle
pobierz obiekt wywołujący: stackoverflow.com/questions/2703136/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
To nie jest duplikat „Pobierz nazwę aktualnie wykonywanej metody w Rubim”. To pytanie dotyczy nazwy metody wywołującej, a nie nazwy aktualnej metody.
Wayne Conrad

Odpowiedzi:

210
puts caller[0]

a może ...

puts caller[0][/`.*'/][1..-2]
DigitalRoss
źródło
5
Tak, zobacz Kernel # caller, alias ruby-doc.org/core-1.8.7/classes/Kernel.html#M001073
DigitalRoss,
10
Daje to nazwę metody wywołującej, ale nie daje żadnych wskazówek, do którego modułu lub klasy należy metoda. Czy to jest możliwe?
thomthom
@thomthom Tak, to możliwe, zadzwoń do self.class.name, aby zobaczyć nazwę klasy
Thorin
Doskonałe wykorzystanie wyrażenia regularnego jako indeksu ciągu! Można również użyćcaller[0][/`(.*)'/,1]
aks
1
Wydaje się, że to nie działa w Railsach 5.2.1. W kontrolerze Rails to zwraca "block in make_lambda". Myślę, że to jest tylko dla Ruby.
dcangulo
164

W Ruby 2.0.0 możesz użyć:

caller_locations(1,1)[0].label

Jest znacznie szybszy niż rozwiązanie Ruby 1.8+:

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

Zostanie uwzględniony, backportsgdy otrzymam czas (lub żądanie ściągnięcia!).

Marc-André Lafortune
źródło
Warto zauważyć, że nie jest to dostępne w Rubiniusie.
Maksymalnie
1
jeśli używasz podważania, musisz zignorować ślad stosu podważania, który wydaje się ... nie wydaje się, aby było to domyślne rozwiązanie.
dtc
6
Teraz wydaje się, że jest caller_locations[0].labelna Rubim 2.2.0, w przeciwnym razie zawsze masz send_actionwynik
brcebn
1
jak możemy uzyskać tylko metodę call app i zignorować wywołanie frameworka?
Matrix
31

Użyj caller_locations(1,1)[0].label(dla ruby> = 2,0)

Edycja : Moja odpowiedź mówi, że należy użyć, __method__ale się myliłem, zwraca aktualną nazwę metody.

dorycki
źródło
1
@OswaldoFerreira Thanks, znalazłem to na SO w innej odpowiedzi gdzieś
Dorian
5
To jest niepoprawne, zwraca bieżącą metodę, a nie metodę, która
wywołała
1
działa jak marzenie. Wydaje się również, że jest znacznie szybszy niż metody sprzed 2.0.
Dr Strangelove
21

używam

caller[0][/`([^']*)'/, 1]
Héctor García
źródło
4
Jaka jest przewaga tego w porównaniu z podejściem DigitalRoss?
Andrew Grimm,
2
Czystsze i dokładniejsze. Zamiast wyszukiwać, użyj metody tablicowej, aby podzielić niechciane znaki na podstawie pozycji (co może być nieprawidłowe).
Nowa Aleksandria
2
Dlaczego nie użyć po prostu caller [0] [/ `(. *) '/, 1]? Nie jestem guru w kwestii wyrażeń regularnych, ale wydaje się, że to działa.
collimarco
7
@collimarco O ile String nie zawiera 'poza tym, którego szukasz (i zakładam, że nie może), wynik będzie taki sam, na pewno. Jednak [^']*będzie działać lepiej, ponieważ silnik regex przestanie próbować dopasować tę część do wyrażenia w momencie, gdy osiągnie '(twoja wersja przejdzie do końca, a następnie cofnie się, ponieważ nie znalazła 'na końcu). W tym przypadku różnica jest oczywiście nieistotna, ale dobrym zwyczajem jest unikanie .wyrażeń regularnych, jeśli to możliwe.
Thor84no
4

Co powiesz na

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

Znacznie czystsze imo.

trzykrotnie801
źródło
3

Zamiast tego możesz napisać to jako funkcję biblioteczną i wykonać wywołanie w razie potrzeby. Kod wygląda następująco:

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

Aby uruchomić powyższą metodę modułu, musisz wywołać w ten sposób: caller = CallChain.caller_method

odniesienie do kodu z

amit karsale
źródło
1
Link do potencjalnego rozwiązania jest zawsze mile widziany, ale dodaj kontekst do niego, aby inni użytkownicy mieli pojęcie, co to jest i dlaczego się tam znajduje. Zawsze cytuj najbardziej odpowiednią część ważnego linku, na wypadek gdyby strona docelowa była nieosiągalna lub została trwale wyłączona. Weź pod uwagę, że fakt, że niewiele więcej niż link do strony zewnętrznej jest tylko linkiem do zewnętrznej witryny, jest możliwym powodem, dlaczego i w jaki sposób niektóre odpowiedzi są usuwane? .
Xavi López
@ XaviLópez zaktualizował odpowiedź, plz napraw, jeśli robię źle lub coś pomyłkę ... dzięki za życzliwą sugestię :)
amit karsale
1
Dzięki za poprawienie odpowiedzi. Niestety, nie mam wystarczającej wiedzy o Rubim, aby móc poprawnie skomentować ten post, ale teraz odpowiedź wygląda dobrze. Usunąłem swój głos przeciw. Powodzenia :-)
Xavi López
2

Aby zobaczyć informacje o dzwoniącym i wywoływanym w dowolnym języku, niezależnie od tego, czy jest to ruby, java czy python, zawsze chciałbyś spojrzeć na ślad stosu. W niektórych językach, takich jak Rust i C ++, kompilator ma wbudowane opcje włączania pewnego rodzaju mechanizmu profilowania, który można wyświetlić w czasie wykonywania. Wierzę, że dla Rubiego istnieje jeden o nazwie ruby-prof.

Jak wspomniano powyżej, możesz zajrzeć do stosu wykonywania ruby. Ten stos wykonywania jest tablicą zawierającą obiekty lokalizacji śledzenia wstecznego.

Zasadniczo wszystko, co musisz wiedzieć o tym poleceniu, jest następujące:

caller (start = 1, length = nil) → array lub nil

user3769125
źródło