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 작동합니다. 이것은 멍청한 후속 조치 일 수 있습니다 ...하지만 루비 소스에서 send라는 단어를 어떻게 찾을 수 없습니다-C : \ ruby ​​\ lib \ ruby ​​\ 1.8 \ fileutils.rb? send 함수를 찾을 것이라고 생각했습니다.
BuddyJoe

1
나는 그것이 후드 아래에서 무엇을하고 있는지 궁금했다.
BuddyJoe

그것은 객체에 정의되어 있습니다 -ruby-doc.org/core/classes/Object.html#M000332 관심 가치에 대한 임의의 함수를 선택했습니다.
Colin Gravill

1
흥미롭게도 대답을 두 번 읽고 완전히 이해하기 전에 FileUtils.send ( "load")를 실행하고 내 함수를 실행했기 때문에 흥미 롭습니다. "전역"에서 함수를 작성하여 이것을 올바르게 이해하면 루트 객체에 메소드를 추가합니까? 또는 아닙니다?
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

send call과 함께 인수를 보내려면 다음 ClassName.send ( "method_name", arg1, arg2)와 같은 것을 사용하십시오.
Aleem

실제 시간을 정확하게 나타 내기 위해 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

간단 하죠?

global에 관해서 는 Ruby 방법이 methods메소드를 사용하여 검색하는 것이라고 생각합니다 .


meth = a.method? 이 함수를 이미 호출하지 않습니까? 메소드가 무언가를 리턴하면 어떻게 되나요?
user1735921

그 방법이 존재하지 않을 때 참고로 : "my_string".method('blah') #=> NameError: undefined method 수업을위한 blahString'
Joshua Pinter

3

개인적으로 함수 참조에 해시를 설정 한 다음 문자열을 해시의 인덱스로 사용합니다. 그런 다음 매개 변수와 함께 함수 참조를 호출하십시오. 이것은 잘못된 문자열이 호출하고 싶지 않은 것을 호출하지 못하게하는 이점이 있습니다. 다른 방법은 기본적으로 eval문자열입니다. 이러지 마십시오.

추신 : 게으르지 않고 실제로 무언가에 연결하는 대신 전체 질문을 입력하십시오.


죄송합니다. 몇 가지 문구를 복사하여 루비에 맞게 번역합니다. +1
버디 조
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.