我正在尝试在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}'
我不会在我的宝石http://pastie.org/5137463
中使用它我想知道如何实现这种行为
答案 0 :(得分: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
更好地编写上述内容,但我想说清楚;)
答案 1 :(得分: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