Memanggil Metode Dari String Dengan Nama Metode di Ruby


157

Bagaimana saya bisa melakukan apa yang mereka bicarakan di sini , tetapi di Ruby?

Bagaimana Anda melakukan fungsi pada suatu objek? dan bagaimana Anda melakukan fungsi global (lihat jawaban jetxee pada posting yang disebutkan)?

CONTOH KODE:

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()

PEMBARUAN: Bagaimana Anda bisa sampai ke metode global? atau fungsi global saya?

Saya mencoba baris tambahan ini

puts methods

dan memuat dan row_change di mana tidak terdaftar.

Jawaban:


232

Untuk memanggil fungsi secara langsung pada suatu objek

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

yang mengembalikan 3 seperti yang diharapkan

atau untuk fungsi modul

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

dan metode yang ditentukan secara lokal

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

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

Dokumentasi:


3
+1 Itu bekerja. Ini mungkin tindak lanjut bodoh ... tapi kenapa saya tidak dapat menemukan kata kirim di sumber Ruby di - C: \ ruby ​​\ lib \ ruby ​​\ 1.8 \ fileutils.rb? Kupikir aku akan menemukan fungsi kirim di sana.
BuddyJoe

1
Saya ingin tahu apa yang dilakukannya di bawah tenda.
BuddyJoe

Itu didefinisikan pada objek - ruby-doc.org/core/classes/Object.html#M000332 Saya memilih fungsi acak untuk nilai bunga.
Colin Gravill

1
Menarik karena sebelum saya membaca jawaban Anda dua kali, dan sepenuhnya mengatasinya saya menjalankan FileUtils.send ("memuat") dan itu menjalankan fungsi saya. jadi jika saya memahami ini dengan benar dengan membuat fungsi dalam "global" apakah saya menambahkan metode ke objek root? atau tidak?
BuddyJoe

12
Bagus untuk Anda karena mencari hal-hal di sumber! :)
Colin Gravill

34

Tiga Cara: send/ call/ eval- dan Tolok Ukurnya

Doa yang khas (untuk referensi):

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

Menggunakan send

s.send(:length) #=> 6

Menggunakan call

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

Menggunakan eval

eval "s.length" #=> 6

 

Tolak ukur

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" } } 
} 

... seperti yang Anda lihat, instantiasi objek metode adalah cara dinamis tercepat dalam memanggil metode, juga perhatikan seberapa lambat menggunakan eval.

#######################################
#####   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)

Penghargaan diberikan pada posting blog ini yang menjelaskan lebih banyak tentang tiga metode dan juga menunjukkan cara memeriksa apakah metode tersebut ada.


Saya baru saja menemukan ini, dan saya perhatikan sesuatu yang tidak tertutup. Apa yang akan saya lakukan jika saya ingin melakukannya Class.send("classVariable") = 5? Itu melempar kesalahan. Apakah ada jalan keluarnya? Hal yang sama berlaku untuk menggunakanClass.method("classVariable").call() = 5
kepala sekolah

jika Anda ingin mengirim beberapa argumen dengan kirim panggilan, gunakan sesuatu seperti ClassName.send ini ("method_name", arg1, arg2)
Aleem

Tidakkah seharusnya tolok ukur Anda untuk callmemasukkan instantiating objek metode ( m.test.method(:length)) untuk secara akurat mewakili waktu sebenarnya? Saat menggunakan callAnda kemungkinan akan instantiate objek metode setiap kali.
Joshua Pinter

Tautan posting blog sudah mati, btw.
Joshua Pinter

33

Gunakan ini:

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

Sederhana bukan?

Sedangkan untuk global , saya pikir cara Ruby adalah mencarinya menggunakan methodsmetode.


meth = a.method? Bukankah ini sudah memanggil fungsi? bagaimana jika metode mengembalikan sesuatu?
user1735921

FYI untuk saat metode tidak ada: "my_string".method('blah') #=> NameError: undefined method bla 'untuk kelasString'
Joshua Pinter

3

Secara pribadi saya akan mengatur referensi hash untuk berfungsi dan kemudian menggunakan string sebagai indeks untuk hash. Anda kemudian memanggil referensi fungsi dengan parameternya. Ini memiliki keuntungan karena tidak membiarkan string yang salah memanggil sesuatu yang tidak ingin Anda panggil. Cara lain pada dasarnya evaladalah string. Jangan lakukan ini.

PS jangan malas dan benar-benar mengetikkan seluruh pertanyaan Anda, alih-alih menautkan sesuatu.


Maaf. Saya akan menyalin beberapa kata-kata dan menerjemahkannya untuk membuatnya menjadi Ruby yang spesifik. +1
BuddyJoe
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.