2013-04-07 84 views
2

Ruby的動態參數我有以下一種方法定義的:在動態創建的方法

method_name = :foo 
method_arguments = [:bar, :baz] 
method_mandatory_arguments = {:quux => true} 
method_body = ->{ quux ? bar + baz : bar - baz } 

所以我希望得到一個真正的方法。但是define_method沒有任何動態定義方法參數的可能性。我知道使用class_eval的另一種方式,但我知道比定義方法class_eval要慢得多define_method。 我如何有效地存檔這個?

我做了一些基準測試中軌控制檯:

class Foo; end 
n = 100_000 

Benchmark.bm do |x| 
    x.report('define_method') do 
    n.times { |i| Foo.send(:define_method, "method1#{i}", Proc.new { |a, b, c| a + b + c }) } 
    end 
    x.report('class_eval') do 
    n.times { |i| Foo.class_eval %Q{ def method2#{i}(a, b, c); a + b + c; end } } 
    end 
end 

所以我已經得到了以下結果:

   user  system  total  real 
define_method 0.750000 0.040000 0.790000 ( 0.782988) 
class_eval  9.510000 0.070000 9.580000 ( 9.580577) 
+1

'class_eval'對我來說很有意義。性能真的是一個問題嗎?很難想象它會是什麼用例。 – 2013-04-07 22:21:57

+1

你可以讓你的define_method塊接受可變參數,然後根據你在閉包中捕獲的參數元數據解釋args數組。 – dbenhur 2013-04-07 22:41:15

+0

@dbenhur,好的,但在這種情況下,事實上我有一種方法可以實現乘法行爲,所以我必須通過手工實現基本參數行爲(參數存在,默認參數等)。這是我想要避免的。 – freemanoid 2013-04-08 07:11:34

回答

0

還有就是要實現您正在使用class_eval問什麼沒有簡單的方法或define_method。由於method_body是一個lambda函數,它只能訪問在它之前定義的局部變量。

method_body = ->{ quux ? bar + baz : bar - baz } 
quux = true 
method_body.call # undefined local variable or method ‘quux’ 

quux = true 
method_body = ->{ quux ? bar + baz : bar - baz } 
method_body.call # undefined local variable or method ‘bar’ 

我建議你修改你的要求。如果你的方法體應該是lambda,爲它定義所有參數。那麼這是一個天作之合define_method:

method_body = ->(quux, bar = 0, baz = 0){ quux ? bar + baz : bar - baz } 
define_method(method_name, &method_body) 

如果你的方法體可以是一個字符串,EVAL是唯一的選擇:

method_body = "quux ? bar + baz : bar - baz" 
eval <<RUBY 
def #{method_name} #{arguments} 
    #{method_body} 
end 
RUBY 
+0

從你的觀點來看,我想用我以特定形式存儲的參數集來創建一個proc(或者對我來說不重要的lambda)。所以我有一個數組'''method_arguments = [:bar,:baz]'''我想要像這樣使用它:'''method_body = - >(* method_arguments){quux? bar + baz:bar - baz}'' – freemanoid 2013-04-08 12:34:52

+1

這對procs/lambda來說是不可能的。你可以將你的方法體作爲一個字符串存儲嗎?如果你給出一個更具體的真實世界的例子,這將有所幫助。 – 2013-04-08 12:38:46

+0

似乎唯一的方法是使用class_eval。 – freemanoid 2013-04-08 14:13:28