2012-10-30 38 views
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}' 

我wan't使用這在我的寶石http://pastie.org/5137463

我要求知道如何實現這一行爲

+1

看看延遲工作,Sidekiq或任何其他異步排隊寶石。 – meagar

+0

伊莫在這種特殊情況下我不能使用延遲工作和其他後臺工作人員。 http://pastie.org/5137463 – Lewy

+0

你可能想看看這個線程:http://stackoverflow.com/questions/9371875/task-future-in-ruby –

回答

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,但我想講清楚;)

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 
+0

將lazy_methods定義放入模塊中。使用['method_added'](http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-method_added)捕獲插入的方法定義。 – d11wtq

+0

@ d11wtq將'lazy_evaluation'移動到'foo'和'baz'定義的前面是爲了嗎? – sawa

+1

sawa沒錯,是的。如果你有一個你想要打包的方法名列表,你可以檢測它們何時被定義,因爲每一個被定義,method_added被調用,所以你可以把它們包裝在這個點上。 – d11wtq

相關問題