Çağıran yöntemin adı nasıl alınır?


161

Ruby'de bir yöntemin içinde çağıran yöntem adını bulmak için bir yolu var mı?

Örneğin:

class Test
  def self.foo
    Fooz.bar
  end
end

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



"Ruby'de şu anda yürütülen yöntemin adını al" ın kopyası değil. Bu soru, geçerli yöntemin adını değil, çağıran yöntemin adını sorar.
Wayne Conrad

Yanıtlar:


210
puts caller[0]

ya da belki...

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


10
Bu, çağıran yöntemin adını verir, ancak yöntemin ait olduğu modüle veya sınıfa herhangi bir gösterge vermez. Mümkün mü?
thomthom

@thomthom Evet, sınıf adını görmek için self.class.name adresini arayabilirsiniz
Thorin

Regex'in bir string dizini olarak mükemmel kullanımı! Ayrıca kullanabilirsinizcaller[0][/`(.*)'/,1]
AKS

1
Bu, Rails 5.2.1'de işe yaramıyor gibi görünüyor. Rails kontrol cihazında bu geri döner "block in make_lambda". Sanırım bu sadece Ruby için.
dcangulo

164

Ruby 2.0.0'da şunları kullanabilirsiniz:

caller_locations(1,1)[0].label

Bu var çok daha hızlı Ruby 1.8+ çözümü daha:

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

Dahil olur backportsZamanım aldığımda (veya bir çekme isteği!).


Bunun Rubinius'ta mevcut olmadığını belirtmek gerekir.
Max

1
Eğer gözetleme kullanarak ur, görünüyor gözetlemek stacktrace göz ardı gerekir ... bunun için varsayılan bir çözüm gibi görünmüyor.
dtc

6
Şimdi caller_locations[0].labelRuby 2.2.0 üzerinde gibi görünüyor, her zaman send_actionsonuç var
brcebn

1
nasıl yalnızca çağrı uygulama yöntemini alabilir ve çerçeve çağrısını yoksayabiliriz?
Matris

31

Kullanım caller_locations(1,1)[0].label(yakut için> = 2.0)

Düzenleme : Cevabım kullanmak söylüyordu __method__ama yanılmışım, geçerli yöntem adını döndürür.


1
@OswaldoFerreira Teşekkürler, bir yerde başka bir cevapta SO'da buldum
Dorian

5
Bu yanlış, geçerli yöntemi
çağırır

1
tıkır tıkır çalışıyor. Ayrıca 2.0 öncesi yöntemlerden çok daha hızlı görünüyor.
Dr.Strangelove

21

kullanırım

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

4
Bunun DigitalRoss'un yaklaşımına göre avantajı nedir?
Andrew Grimm

2
Daha temiz ve daha hassas. Arama yapmak yerine, istenmeyen karakterleri konuma göre bölmek için bir dizi yöntemi kullanmak (yanlış olabilir).
Yeni İskenderiye

2
Neden sadece arayan [0] [/ `(. *) '/, 1] kullanmıyorsunuz? Ben düzenli ifadeler hakkında bir guru değilim, ama işe yarıyor gibi görünüyor.
collimarco

7
@collimarco Dize 'aradığınızdan başka bir şey içermediği sürece (ve yapamayacağımı varsayıyorum), sonuç aynı olacaktır, elbette. Bununla birlikte, [^']*regex motoru, bir bölüme ulaştığı andaki ifadeyi eşleştirmeye çalışacağından daha iyi performans gösterecektir '(sürümünüz sonuna kadar, ardından sonunda bir bulamadığı için geri izleme '). Bu durumda elbette fark göz ardı edilebilir, ancak mümkün olduğunda normal .ifadelerden kaçınmak iyi bir alışkanlıktır .
Thor84no

4

Peki ya

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

Çok daha temiz imo.


3

Bunun yerine kitaplık işlevi olarak yazabilir ve gerektiğinde çağrı yapabilirsiniz. Kod aşağıdaki gibi gider:

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

Yukarıdaki modül yöntemini tetiklemek için şu şekilde aramanız gerekir: caller = CallChain.caller_method

kod referansı


1
Potansiyel bir çözümün bağlantısı her zaman açığız, ancak lütfen bağlantınızın çevresine bağlam ekleyin, böylece diğer kullanıcılarınız bunun ne olduğunu ve neden orada olduğunu bilmeleri gerekir. Hedef siteye erişilemiyorsa veya kalıcı olarak çevrimdışı olursa, her zaman önemli bir bağlantının en alakalı kısmını belirtin. Harici bir siteye bağlantıdan çok daha fazla olmanın Neden ve nasıl bazı cevapların silinmesinin olası bir nedeni olduğunu dikkate alın. .
Xavi López

@ XaviLópez cevabı güncelledi, plz yanlış mı yoksa yanlış bir şey yapıyorsam
düzeltin

1
Cevabınızı geliştirdiğiniz için teşekkürler. Ne yazık ki, Ruby hakkında bu yazı hakkında doğru yorum yapabilmek için yeterli bilgim yok, ancak cevap şimdi iyi görünüyor. Aşağı oyumu kaldırdım. En iyi şanslar :-)
Xavi López

2

İster yakut, ister java veya python olsun, arayan ve arayan bilgileri herhangi bir dilde görmek için, her zaman yığın izlemesine bakmak istersiniz. Rust ve C ++ gibi bazı dillerde, derleyicide çalışma sırasında görüntüleyebileceğiniz bir tür profil oluşturma mekanizmasını açmak için seçenekler bulunur. Ruby için ruby-prof adlı birinin var olduğuna inanıyorum.

Ve yukarıda belirtildiği gibi, yakut için yürütme yığınına bakabilirsiniz. Bu yürütme yığını, geri izleme konum nesneleri içeren bir dizidir.

Bu komut hakkında bilmeniz gereken tek şey şu:

arayan (başlangıç ​​= 1, uzunluk = nil) → dizi veya nil

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.