2

我正在尝试在 ruby​​ 中实现惰性方法执行。假设我有一个类有两个方法,调用后不应该立即执行

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}'

我不想在我的 gem 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 回答