2

Rubyで遅延メソッド実行を実装しようとしています。呼び出しの直後に実行されるべきではない2つのメソッドを持つクラスがあるとしましょう

class Foo
  lazy_evaluate :bar, :baz

  def bar(string)
    puts string
  end

  def baz(hash)
    puts hash.inspect
  end
end

f = Foo.new
f.bar('hello world') => nil
f.baz(hello: :world) => nil

f.run_lazy_methods =>
'hello world'
'{:hello=>:world}'

私は私の宝石でこれを使用したくないhttp://pastie.org/5137463

この動作を実装する方法のアイデアを求めています

4

2 に答える 2

3

デリゲート オブジェクトを使用し、呼び出されたメソッドをスタックに記録してから、デリゲートで再生します。

class LazyObject
  def initialize(delegate)
    @invocations = []
    @delegate    = delegate
  end

  def bar(*args, &block)
    @invocations << {
      method: :bar,
      args:   args,
      block:  block
    }
  end

  def baz(*args, &block)
    @invocations << {
      method: :baz,
      args:   args,
      block:  block
    }
  end

  def run_lazy_methods
    @invocations.each do |inv|
      @delegate.send(
        inv[:method],
        *inv[:args],
        &inv[:block]
      )
    end
  end
end

obj = LazyObject.new(RealObject.new)
obj.bar(hello: :world)
obj.baz("Hello World")
obj.run_lazy_methods

を使用して上記をより適切に記述することもできますが、method_missing明確にしたかったのです ;)

于 2012-10-30T13:50:29.910 に答える
0

lazy_evaluate対応するメソッド定義の前に許可できるようにするのは難しいと思いました。私の実装は、対応する定義の後に配置すると機能します。

準備部分は次のとおりです。

class Foo
  def initialize
    @queue = []
  end
  def run_lazy_methods
    @queue.each{|proc| proc.call}
  end
  def self.lazy_evaluate *methods
    methods.each do |method|
      alias :"old_#{method}" :"#{method}"
      define_method method do |*args, &pr|
        @queue.push(->{send(:"old_#{method}", *args, &pr)})
      end
    end
  end
end

次に、メソッドを定義して を呼び出すと、メソッドはlazy_evaluate遅延します。

class Foo
  def bar(string)
    puts string
  end
  def baz(hash)
    puts hash.inspect
  end

  lazy_evaluate :bar, :baz
end

そして、期待どおりの結果が得られます。

f = Foo.new
f.bar('hello world')
f.baz(hello: :world)
f.run_lazy_methods
于 2012-10-30T14:09:22.110 に答える