2016-05-13 42 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對象。

A 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? '通過':'失敗'。 Parens很重要。 –