Ruby'de Yöntemin Adıyla Bir Dizeden Yöntem Çağırma


157

Burada bahsettiklerini nasıl yapabilirim , ama Ruby'de?

Bir nesne üzerindeki işlevi nasıl yapardınız? ve küresel bir işlevi nasıl yapardınız ( bahsi geçen yazıdaki jetxee'nin cevabına bakınız )?

ÖRNEK KOD:

event_name = "load"

def load()
  puts "load() function was executed."
end

def row_changed()
  puts "row_changed() function was executed."
end 

#something here to see that event_name = "load" and run load()

GÜNCELLEME: Global yöntemlere nasıl ulaşırsınız? ya da global işlevlerim?

Bu ek satırı denedim

puts methods

ve listelenmeyen yerlerde load ve row_change.

Yanıtlar:


232

İşlevleri doğrudan bir nesne üzerinde çağırmak için

a = [2, 2, 3]
a.send("length")
# or
a.public_send("length")

3 beklendiği gibi döner

veya bir modül işlevi için

FileUtils.send('pwd')
# or
FileUtils.public_send(:pwd)

ve yerel olarak tanımlanmış bir yöntem

def load()
    puts "load() function was executed."
end

send('load')
# or
public_send('load')

Belgeler:


3
+1 Bu işe yarıyor. Bu aptalca bir takip olabilir ... ama neden Ruby kaynağında göndermek kelimesini bulamıyorum - C: \ ruby ​​\ lib \ ruby ​​\ 1.8 \ fileutils.rb? Orada gönderme fonksiyonunu bulacağımı düşündüm.
BuddyJoe

1
Kaputun altında ne yaptığını merak ettim.
BuddyJoe

Nesnede tanımlandı - ruby-doc.org/core/classes/Object.html#M000332 Faiz değeri için rastgele bir işlev seçtim.
Colin Gravill

1
İlginçtir, çünkü cevabınızı iki kez okumadan ve tamamen grok'd etmeden önce FileUtils.send'i ("load") çalıştırdım ve işlevimi çalıştırdı. yani "global" işlevler oluşturarak bunu doğru anlarsam yöntemleri kök nesneye ekler miyim? ya da değil?
BuddyJoe

12
Kaynakta bir şeyler aradığın için sana iyi! :)
Colin Gravill

34

Üç Yol: send/ call/ eval- ve Deneyleri

Tipik çağırma (referans için):

s= "hi man"
s.length #=> 6

kullanma send

s.send(:length) #=> 6

kullanma call

method_object = s.method(:length) 
p method_object.call #=> 6

kullanma eval

eval "s.length" #=> 6

 

Deneyler

require "benchmark" 
test = "hi man" 
m = test.method(:length) 
n = 100000 
Benchmark.bmbm {|x| 
  x.report("call") { n.times { m.call } } 
  x.report("send") { n.times { test.send(:length) } } 
  x.report("eval") { n.times { eval "test.length" } } 
} 

Gördüğünüz gibi, bir yöntem nesnesini örneklendirmek, bir yöntemi çağırmanın en hızlı dinamik yoludur, eval kullanımının ne kadar yavaş olduğunu da fark edin.

#######################################
#####   The results
#######################################
#Rehearsal ----------------------------------------
#call   0.050000   0.020000   0.070000 (  0.077915)
#send   0.080000   0.000000   0.080000 (  0.086071)
#eval   0.360000   0.040000   0.400000 (  0.405647)
#------------------------------- total: 0.550000sec

#          user     system      total        real
#call   0.050000   0.020000   0.070000 (  0.072041)
#send   0.070000   0.000000   0.070000 (  0.077674)
#eval   0.370000   0.020000   0.390000 (  0.399442)

Kredi , üç yöntem üzerinde biraz daha ayrıntılı olan ve yöntemlerin var olup olmadığını nasıl kontrol edeceğinizi gösteren bu blog yayınına gider .


Ben sadece onu buluyordum ve kapsanmayan bir şey fark ettim. Yapmak istersem ne yapardım Class.send("classVariable") = 5? Bu bir hata veriyor. Bunun etrafında bir yol var mı? Aynı şey kullanmak için de geçerlidirClass.method("classVariable").call() = 5
thesecretmaster

gönderme çağrısı ile bazı argümanlar göndermek istiyorsanız, bu ClassName.send ("method_name", arg1, arg2) gibi bir şey kullanın
Aleem

Karşılaştırma ölçütünüz, doğru zamanı temsil etmek calliçin method nesnesini ( m.test.method(:length)) başlatmayı içermemeli midir? Kullanırken callEğer konum olasılıkla yöntem nesne her zaman örneğini olacak.
Joshua Pinter

Blog yazısı bağlantısı öldü, btw.
Joshua Pinter

33

Bunu kullan:

> a = "my_string"
> meth = a.method("size")
> meth.call() # call the size method
=> 9

Basit, değil mi?

Küresel gelince , Ruby yolunun methodsyöntemi kullanarak onu aramak olacağını düşünüyorum .


meth = a.method? bu zaten fonksiyon çağırmıyor mu? yöntem bir şey döndürürse ne olur?
user1735921

Yöntem mevcut olmadığında FYI: "my_string".method('blah') #=> NameError: undefined method sınıf için falanString'
Joshua Pinter

3

Şahsen ben referansları işlev için bir karma kurulum ve daha sonra karma için bir dizin olarak dize kullanın. Daha sonra işlev başvurusunu parametreleriyle çağırırsınız. Bunun avantajı, yanlış dizenin aramak istemediğiniz bir şeyi çağırmasına izin vermemesidir. Diğer yol ise temelde evaldizgidir. Bunu yapma.

PS tembel olmayın ve aslında bir şeye bağlanmak yerine tüm sorunuzu yazın.


Afedersiniz. Bazı ifadeleri kopyalayacağım ve Ruby'yi spesifik hale getirmek için tercüme edeceğim. +1
BuddyJoe
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.