Gọi một phương thức từ một chuỗi với tên của phương thức trong Ruby


156

Làm thế nào tôi có thể làm những gì họ đang nói ở đây , nhưng trong Ruby?

Làm thế nào bạn sẽ làm chức năng trên một đối tượng? và bạn sẽ làm một chức năng toàn cầu như thế nào (xem câu trả lời của jetxee trên bài đăng được đề cập)?

VÍ DỤ MÃ:

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

CẬP NHẬT: Làm thế nào để bạn có được các phương pháp toàn cầu? hoặc chức năng toàn cầu của tôi?

Tôi đã thử dòng bổ sung này

puts methods

và tải và row_change ở nơi không được liệt kê.

Câu trả lời:


231

Để gọi các hàm trực tiếp trên một đối tượng

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

trả về 3 như mong đợi

hoặc cho một chức năng mô-đun

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

và một phương thức xác định cục bộ

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

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

Tài liệu:


3
+1 Điều đó hoạt động. Đây có thể là một sự theo dõi ngớ ngẩn ... nhưng tại sao tôi không thể tìm thấy từ gửi trong nguồn Ruby tại - C: \ ruby ​​\ lib \ ruby ​​\ 1.8 \ fileutils.rb? Nghĩ rằng tôi sẽ tìm thấy chức năng gửi trong đó.
BuddyJoe

1
Tôi tò mò không biết nó đang làm gì dưới mui xe.
BuddyJoe

Nó được xác định trên đối tượng - ruby-doc.org/core/groupes/Object.html#M000332 Tôi đã chọn một hàm ngẫu nhiên cho giá trị quan tâm.
Grain Gravill

1
Thật thú vị bởi vì trước khi tôi đọc câu trả lời của bạn hai lần và hoàn toàn tìm kiếm nó, tôi đã chạy FileUtils.send ("tải") và nó chạy chức năng của tôi. Vì vậy, nếu tôi hiểu điều này một cách chính xác bằng cách tạo các hàm trong "toàn cầu" thì tôi có thêm các phương thức vào đối tượng gốc không? hay không?
BuddyJoe

12
Tốt cho bạn để tìm kiếm các công cụ trong nguồn! :)
Grain Gravill

34

Ba cách: send/ call/ eval- và Điểm chuẩn của họ

Yêu cầu tiêu biểu (để tham khảo):

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

Sử dụng send

s.send(:length) #=> 6

Sử dụng call

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

Sử dụng eval

eval "s.length" #=> 6

 

Điểm chuẩn

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

... như bạn có thể thấy, khởi tạo một đối tượng phương thức là cách động nhanh nhất để gọi một phương thức, cũng nhận thấy việc sử dụng eval chậm như thế nào.

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

Tín dụng vào bài đăng trên blog này , chi tiết hơn một chút về ba phương thức và cũng chỉ ra cách kiểm tra xem các phương thức có tồn tại hay không.


Tôi chỉ tìm thấy cái này và tôi nhận thấy thứ gì đó không được bảo hiểm. Tôi sẽ làm gì nếu tôi muốn làm gì Class.send("classVariable") = 5? Điều đó ném một lỗi. Có đường nào quanh đó không? Điều tương tự cũng đúng khi sử dụngClass.method("classVariable").call() = 5
thesecretmaster

nếu bạn muốn gửi một số đối số với gửi cuộc gọi, hãy sử dụng một cái gì đó như ClassName.send ("method_name", arg1, arg2)
Aleem

Không phải điểm chuẩn của bạn để callbao gồm việc khởi tạo đối tượng phương thức ( m.test.method(:length)) để thể hiện chính xác thời gian thực của nó? Khi sử dụng, callbạn có thể sẽ khởi tạo đối tượng phương thức mỗi lần.
Joshua Pinter

Blog bài liên kết đã chết, btw.
Joshua Pinter

33

Dùng cái này:

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

Đơn giản phải không?

Đối với toàn cầu , tôi nghĩ rằng cách của Ruby sẽ là tìm kiếm nó bằng methodsphương pháp này.


meth = a.method? Đây không phải là chức năng đã gọi? Điều gì xảy ra nếu phương thức trả về một cái gì đó?
dùng1735921

FYI cho khi phương thức không tồn tại: "my_string".method('blah') #=> NameError: undefined method blah 'cho lớp họcString'
Joshua Pinter

3

Cá nhân tôi sẽ thiết lập một hàm băm để tham chiếu hàm và sau đó sử dụng chuỗi làm chỉ mục cho hàm băm. Sau đó, bạn gọi tham chiếu hàm với các tham số của nó. Điều này có lợi thế là không cho phép chuỗi sai gọi một cái gì đó mà bạn không muốn gọi. Cách khác là về cơ bản evalchuỗi. Đừng làm điều này.

PS đừng lười biếng và thực sự gõ toàn bộ câu hỏi của bạn, thay vì liên kết với một cái gì đó.


Lấy làm tiếc. Tôi sẽ sao chép một số từ ngữ và dịch để làm cho Ruby cụ thể. +1
BuddyJoe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.