Bagaimana cara mendapatkan nama metode panggilan?

161

apakah ada cara di Ruby untuk menemukan nama metode panggilan di dalam metode?

Sebagai contoh:

class Test
  def self.foo
    Fooz.bar
  end
end

class Fooz
  def self.bar
    # get Test.foo or foo
  end
end
jrichardlai
sumber
1
kemungkinan rangkap dari Dapatkan nama metode yang sedang dijalankan di Ruby
Darshan Rivka Whittle
dapatkan objek panggilan: stackoverflow.com/questions/2703136/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功
Bukan duplikat dari "Dapatkan nama metode yang saat ini dieksekusi di Ruby." Pertanyaan ini menanyakan nama metode panggilan, bukan nama metode saat ini.
Wayne Conrad

Jawaban:

210
puts caller[0]

atau mungkin...

puts caller[0][/`.*'/][1..-2]
DigitalRoss
sumber
5
Ya, lihat Kernel # caller, alias ruby-doc.org/core-1.8.7/classes/Kernel.html#M001073
DigitalRoss
10
Itu memberi nama metode panggilan, tetapi itu tidak memberikan indikasi ke mana modul atau kelas metode milik. Apakah itu mungkin?
thomthom
@thomthom Ya itu mungkin Anda dapat memanggil self.class.name untuk melihat nama kelas
Thorin
Sangat baik menggunakan regex sebagai indeks string! Dapat juga menggunakancaller[0][/`(.*)'/,1]
aks
1
Ini sepertinya tidak berfungsi di Rails 5.2.1. Dalam pengendali Rails ini kembali "block in make_lambda". Saya kira ini hanya untuk Ruby.
dcangulo
164

Di Ruby 2.0.0, Anda dapat menggunakan:

caller_locations(1,1)[0].label

Ini jauh lebih cepat daripada solusi Ruby 1.8+:

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

Akan disertakan backportssaat saya mendapatkan waktu (atau permintaan tarik!).

Marc-André Lafortune
sumber
Perlu dicatat bahwa ini tidak tersedia di Rubinius.
Maks
1
jika Anda menggunakan mangsa, Anda harus mengabaikan stacktrace mangsa tampaknya ... sepertinya tidak ada solusi default untuk itu.
dtc
6
Sekarang tampaknya berada caller_locations[0].labeldi Ruby 2.2.0 lagi Anda selalu memiliki send_actionhasil
brcebn
1
bagaimana kita bisa hanya memanggil metode aplikasi dan mengabaikan kerangka kerja panggilan?
Matriks
31

Menggunakan caller_locations(1,1)[0].label (untuk ruby> = 2.0)

Sunting : Jawaban saya mengatakan untuk digunakan __method__tetapi saya salah, ia mengembalikan nama metode saat ini.

Dorian
sumber
1
@OswaldoFerreira Terima kasih, menemukannya di SO di jawaban lain di suatu tempat
Dorian
5
Ini tidak benar, ia mengembalikan metode saat ini, bukan metode yang disebut metode saat ini ...
thrice801
1
bekerja seperti pesona. Tampaknya juga jauh lebih cepat daripada metode pra 2.0.
Dr.Strangelove
21

saya menggunakan

caller[0][/`([^']*)'/, 1]
Héctor García
sumber
4
Apa keuntungan dari pendekatan ini daripada DigitalRoss?
Andrew Grimm
2
Lebih bersih dan lebih presisi. Daripada melakukan pencarian, kemudian menggunakan metode array untuk membagi karakter yang tidak diinginkan berdasarkan posisi (yang bisa salah).
New Alexandria
2
Mengapa tidak menggunakan penelepon [0] [/ `(. *) '/, 1]? Saya bukan guru tentang ekspresi reguler, tetapi sepertinya berhasil.
collimarco
7
@collimarco Selama String tidak mengandung di 'luar yang Anda cari (dan saya anggap tidak bisa), hasilnya akan sama, tentu. Namun, [^']*akan tampil lebih baik karena mesin regex akan berhenti berusaha untuk mencocokkan bagian ekspresi saat itu mencapai '(versi Anda akan pergi ke akhir, lalu mundur karena tidak menemukan 'di akhir). Perbedaannya cukup diabaikan dalam kasus ini tentu saja, tetapi itu kebiasaan yang baik untuk dihindari .di regex jika memungkinkan.
Thor84no
4

Bagaimana tentang

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

Imo jauh lebih bersih.

tiga kali801
sumber
3

Sebagai gantinya, Anda dapat menuliskannya sebagai fungsi perpustakaan dan melakukan panggilan di mana pun diperlukan. Kode tersebut sebagai berikut:

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

Untuk memicu metode modul di atas, Anda perlu memanggil seperti ini: caller = CallChain.caller_method

referensi kode dari

amit karsale
sumber
1
Tautan ke solusi potensial selalu diterima, tetapi harap tambahkan konteks di sekitar tautan sehingga sesama pengguna Anda akan mengetahui apa itu dan mengapa ada di sana. Selalu kutip bagian yang paling relevan dari tautan penting, jika situs target tidak dapat dijangkau atau offline secara permanen. Mempertimbangkan bahwa menjadi lebih dari sekadar tautan ke situs eksternal adalah kemungkinan alasan mengapa dan bagaimana beberapa jawaban dihapus? .
Xavi López
@ XaviLópez telah memperbarui jawabannya, tolong perbaiki jika saya melakukan kesalahan atau sesuatu yang salah ... terima kasih atas saran
baiknya
1
Terima kasih telah meningkatkan jawaban Anda. Sayangnya, saya tidak memiliki cukup pengetahuan tentang Ruby untuk dapat mengomentari posting ini dengan benar, tetapi jawabannya tampak baik-baik saja sekarang. Saya telah menghapus downvote saya. Semoga sukses :-)
Xavi López
2

Untuk melihat penelepon dan meninggalkan informasi dalam bahasa apa pun, apakah itu ruby ​​atau java atau python, Anda selalu ingin melihat jejak stack. Dalam beberapa bahasa, seperti Rust dan C ++, ada opsi yang dibangun ke dalam kompiler untuk menyalakan semacam mekanisme profil yang dapat Anda lihat selama waktu berjalan. Saya percaya satu ada untuk Ruby yang disebut ruby-prof.

Dan seperti yang disebutkan di atas, Anda bisa melihat tumpukan eksekusi untuk ruby. Tumpukan eksekusi ini adalah array yang berisi objek lokasi jejak balik.

Pada dasarnya yang perlu Anda ketahui tentang perintah ini adalah sebagai berikut:

pemanggil (mulai = 1, panjang = nihil) → array atau nihil

pengguna3769125
sumber