3

次のようなメソッド定義があります。

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よりもはるかに遅いことを知っています。これを効果的にアーカイブするにはどうすればよいですか?

Railsコンソールでいくつかのベンチマークを行いました:

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

1 に答える 1

1

class_eval または define_method を使用して求めているものを実装する簡単な方法はありません。method_body はラムダであるため、その直前に定義されたローカル変数にのみアクセスできます。

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’

要件を修正することをお勧めします。メソッド本体がラムダである必要がある場合は、そのすべての引数を定義します。次に、これは 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
于 2013-04-08T11:41:32.447 に答える