การเรียกใช้เมธอดจากสตริงด้วยชื่อของเมธอดใน Ruby


157

ฉันจะทำสิ่งที่พวกเขากำลังพูดถึงที่นี่แต่ในทับทิมได้อย่างไร

คุณจะทำฟังก์ชั่นบนวัตถุได้อย่างไร? และวิธีการที่คุณจะทำฟังก์ชั่นระดับโลก (ดูคำตอบของ jetxee ในโพสต์ดังกล่าว)

รหัสตัวอย่าง:

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

ปรับปรุง: คุณจะได้รับวิธีการทั่วโลกได้อย่างไร หรือฟังก์ชั่นระดับโลกของฉัน?

ฉันลองบรรทัดเพิ่มเติมนี้

puts methods

และ load และ row_change โดยไม่แสดงรายการ

คำตอบ:


232

เพื่อเรียกฟังก์ชั่นโดยตรงบนวัตถุ

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

ซึ่งผลตอบแทน 3 ตามที่คาดไว้

หรือสำหรับฟังก์ชั่นโมดูล

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

และวิธีการที่กำหนดไว้ในเครื่อง

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

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

เอกสารอ้างอิง:


3
+1 นั่นใช้ได้ นี่อาจเป็นสิ่งที่ติดตามได้ ... แต่ทำไมฉันถึงไม่พบคำที่ส่งในแหล่งทับทิมที่ - C: \ ruby ​​\ lib \ ruby ​​\ 1.8 \ fileutils.rb? คิดว่าฉันจะหาฟังก์ชั่นส่งที่นั่น
BuddyJoe

1
ฉันอยากรู้ว่ามันทำอะไรอยู่ใต้ฝากระโปรง
BuddyJoe

มันกำหนดไว้ใน object - ruby-doc.org/core/classes/Object.html#M000332ฉันเลือกฟังก์ชั่นแบบสุ่มสำหรับมูลค่าดอกเบี้ย
Colin Gravill

1
ที่น่าสนใจเพราะก่อนที่ฉันจะอ่านคำตอบของคุณสองครั้งและอย่างเต็มที่ฉันก็วิ่ง FileUtils.send ("โหลด") และมันก็วิ่งฟังก์ชั่นของฉัน ดังนั้นถ้าฉันเข้าใจสิ่งนี้อย่างถูกต้องโดยการสร้างฟังก์ชั่นใน "โลก" ฉันจะเพิ่มวิธีการลงในวัตถุรูตหรือไม่ หรือไม่?
BuddyJoe

12
ดีกับคุณสำหรับการค้นหาสิ่งต่าง ๆ ในแหล่งที่มา! :)
Colin Gravill

34

สามวิธี: send/ call/ eval- และมาตรฐานของพวกเขา

การร้องขอทั่วไป (สำหรับการอ้างอิง):

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

การใช้ send

s.send(:length) #=> 6

การใช้ call

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

การใช้ eval

eval "s.length" #=> 6

 

มาตรฐาน

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

... อย่างที่คุณเห็นการสร้างอินสแตนซ์ของวัตถุเป็นวิธีที่เร็วที่สุดในการเรียกใช้เมธอดและสังเกตว่าการใช้ 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)

เครดิตไปที่โพสต์บล็อกนี้ซึ่งให้รายละเอียดเพิ่มเติมเกี่ยวกับสามวิธีและยังแสดงวิธีการตรวจสอบว่ามีวิธีดังกล่าวอยู่หรือไม่


ฉันเพิ่งพบสิ่งนี้และฉันสังเกตเห็นบางสิ่งที่ไม่ได้ครอบคลุม สิ่งที่ฉันจะทำอย่างไรถ้าฉันอยากจะทำClass.send("classVariable") = 5? นั่นทำให้เกิดข้อผิดพลาด มีวิธีใดบ้างไหม? สิ่งเดียวกันนี้เป็นจริงสำหรับการใช้Class.method("classVariable").call() = 5
thesecretmaster

ถ้าคุณต้องการที่จะส่งข้อโต้แย้งบางคนที่มีการใช้งานส่งโทรบางอย่างเช่น ClassName.send นี้ ( "method_name" arg1, arg2)
เอลีม

เกณฑ์มาตรฐานของคุณไม่ควรcallรวมถึงการสร้างอินสแตนซ์ออบเจ็กต์วิธีการ ( m.test.method(:length)) เพื่อให้แม่นยำว่าเป็นเวลาจริงหรือไม่ เมื่อใช้callคุณอาจจะยกตัวอย่างวิธีวัตถุทุกครั้ง
Joshua Pinter

ลิงก์โพสต์บล็อกตายแล้ว btw
Joshua Pinter

33

ใช้สิ่งนี้:

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

ง่ายใช่มั้ย

สำหรับทั่วโลกฉันคิดว่าวิธีทับทิมจะค้นหาโดยใช้methodsวิธีการ


ปรุงยา = a.method? ฟังก์ชั่นนี้ไม่ได้โทรมาแล้วเหรอ? ถ้าวิธีคืนค่าบางอย่าง
user1735921

FYI สำหรับเมื่อไม่มีวิธีการ: "my_string".method('blah') #=> NameError: undefined method blah 'สำหรับชั้นเรียนString'
Joshua Pinter

3

ส่วนตัวฉันจะตั้งค่าแฮเพื่อฟังก์ชั่นการอ้างอิงและจากนั้นใช้สตริงเป็นดัชนีเพื่อแฮช จากนั้นคุณเรียกใช้การอ้างอิงฟังก์ชันด้วยพารามิเตอร์ นี่เป็นข้อดีของการไม่อนุญาตให้มีสายอักขระที่ไม่ถูกต้องในการโทรหาสิ่งที่คุณไม่ต้องการโทร วิธีอื่นคือevalการสตริงโดยทั่วไป อย่าทำอย่างนี้.

PS อย่าขี้เกียจและพิมพ์คำถามทั้งหมดของคุณแทนที่จะเชื่อมโยงกับบางสิ่ง


ขอโทษ ฉันจะคัดลอกข้อความบางส่วนและแปลเพื่อให้เป็นทับทิมโดยเฉพาะ +1
BuddyJoe
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.