2016-05-13 41 views
-2

私はいくつかの引数で呼びたいメソッドのシンボル名のリストを持っています。これは、私が構築しようとしている単純な比較テストのためのものです。ここではテストのために不可欠なコードは次のとおりです。Ruby - シンボル変数で指定されたメソッドを呼び出す

data = [ 
    ["value", true], 
    ["any value here", true], 
    ["Value", true], 
] 

def test_value_1(string) 
    string == "value" 
end 

def test_value_2(string) 
    string.gsub(/.*?value.*?/, "\\1") 
end 

def test_value_3(string) 
    string.downcase == "value" 
end 

#tests 
[:test_value_1, :test_value_2, :test_value_3].each do |method| 
    data.each do |test| 
    value = test[0] 
    expected_result = test[1] 
    puts "#{method}: #{method.to_proc.call(value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'" 
    end 
end 

重要なビットが#testsコメント以下、エンドブロックです。 datatest_value_*メソッドは、テストブロックの使用方法の単なる例であり、本質的な意味を持たないため、それらを掘り起こす必要はありません。

私が本当にやろうとしているが、このコードスニペットに沸く:

method.to_proc.call(value) 

そして、この場合には、valueは直接グローバル名前空間内のメソッドのシンボル名(ない方法でありますオブジェクト)。

これは私が取得エラー出力です:私は困惑

>$ ruby symbol_methods.rb 
symbol_methods.rb:33:in `call': private method `test_value_1' called for "value":String (NoMethodError) 
    from symbol_methods.rb:33:in `block (2 levels) in <main>' 
    from symbol_methods.rb:30:in `each' 
    from symbol_methods.rb:30:in `block in <main>' 
    from symbol_methods.rb:29:in `each' 
    from symbol_methods.rb:29:in `<main>' 

。私はpublic_send(method, value)method.to_proc.call(value)を試しましたが、どちらもprivate methodというエラーになります。

この場合、シンボルと呼ばれるメソッドを呼び出す正しい方法は何でしょうか?私は説明と構文的に正しい答えの両方を探しています。

答えて

0

、私は予期せぬ機能の利点を有している、Object#sendよりも代替の答えを見つけました。解決策は、Object#methodを使用してシンボル名のMethodオブジェクトを返すことです。

MethodオブジェクトはProcのような呼び出し可能なオブジェクトなので、請求書にうまく収まる#callインターフェイスを実装しています。 Objectには、そのような有用なヘルパーが多くのインタフェースで定義されています。元の質問の文脈では

、これはそれがどのように動作するかです:

#tests 
[:test_value_1, :test_value_2, :test_value_3].each do |method| 
    data.each do |test| 
    value = test[0] 
    expected_result = test[1] 
    puts "#{method}: #{self.method(method).call(value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'" 
    end 
end 

重要なビットは、次のとおりです。

self.method(method).call(value) 

これはMethodオブジェクトにシンボル名を変換し、次に起動しますこのメソッドはパラメータとしてvalueを指定しています。これは、機能的には、とほぼ同等にからsend method solutionまで機能します。ただし、いくつかの違いがあります。

sendは、Methodへの変換にオーバーヘッドがないので、いくらか効率が上がります。 Method#callsendは異なる内部呼び出しメカニズムを使用しており、sendも呼び出しオーバーヘッドが少ないようです。

Object#methodを用いる予期しない特徴Methodオブジェクトが容易(Method#to_procを使用して)Procオブジェクトに変換されることです。このように、ファーストクラスのオブジェクトとして格納して渡すことができます。つまり、ブロックの代わりに提供することも、コールバックとして提供することもでき、柔軟なディスパッチソリューションの実装に役立ちます。

4

sendを代わりに使用してください。検索のかなりの量の後

puts "#{method}: #{send(method, value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'" 
+1

@mudasobwaここでのポイントは、プライベートメソッドを呼び出すことです。 'public_send'は正確に動作しないものです。 – sawa

+0

@sawaああ、本当に、すみません。 – mudasobwa

+0

@deltaこれはsend(method、value == expected_result? 'Pass': 'Fail') 'と同じです。' send(method、value)== expected_result? 「合格」:「失敗」。敬虔は問題です。 –

関連する問題