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.

BuddyJoe
sumber

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:

Colin Gravill
sumber
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.

cwd
sumber
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.

Geo
sumber
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.

dlamblin
sumber
Maaf. Saya akan menyalin beberapa kata-kata dan menerjemahkannya untuk membuatnya menjadi Ruby yang spesifik. +1
BuddyJoe