2012-08-08 50 views
2

我反覆使用這個模式:注入Ruby代碼到塊中塊

pb= ProgressBar.new("blah_map", wtf.count) 
newresult= cache("blah_map") do 
    result.map{ |r| pb.inc; { blah: r[:x] } } 
end 
pb.finish 

pb= ProgressBar.new("blah_group", wtf.count) 
newresult= cache("blah_group") do 
    result.group_by{ |r| pb.inc; "#{r[:x]}&#{r[:y]}" } 
end 
pb.finish 

所以很自然,我想能夠做到

def progress_cache(name, count, &block) 
    pb= ProgressBar.new(name, count) 
    inject_pb_inc(block) # how?? 
    # do some caching with yield if cache doesn't exist, don't mind this 
    pb.finish 
end 

而且使用它如此:

newresult= progress_cache("lol", result.count) do 
    result.map do |r| 
    # progress_cache magically inserted a pb.inc here for pretty animation! 
    r[:omg] 
    end 
end 

問題是,如何將pb.inc調用注入progress_cache塊內的塊(map,group_by等)?

編輯:改寫的問題

+0

你需要閱讀https://github.com/bbatsov/ruby-style-guide – megas 2012-08-08 06:40:08

+0

@megas因爲我用了四個空格嗎?當然 – nurettin 2012-08-08 06:42:02

回答

2

有幾個方法可以做到這一點,各種權衡在表現力方面:

  1. 發送進度條爲塊PARAM

    def progress_cache(name, count &block) 
        pb = ProgressBar.new(name, count) 
        result = block.call(pb) 
        pb.finish 
        result 
    end 
    

    並使用它像

    newresult = progress_cache("lol", result.count) do |pb| 
        result.map{|r| pb.inc; r[:omg]} 
    end 
    
  2. 創建一個新的地圖功能,可自動遞增進度條(可以覆蓋result.map直接,或提供result.map_with_progress,但我會離開,給你)

    def map_with_progress(container, name, &block) 
        pb = ProgressBar.new(name, container.count) 
        result = container.map{|obj| block.call(obj)} 
        pb.finish 
        result 
    end 
    

    ,然後用它像

    newresult = map_with_progress(result, "lol") { |r| r[:omg] } 
    

    當然,因爲你同時使用了地圖和GROUP_BY,你必須在這裏有兩個輔助方法,這可能會開始變得凌亂。

  3. 使用高階函數

    def function_with_progress(obj, func_name, name, count, &block) 
        pb = ProgressBar.new(name, count) 
        result = obj.__send__(func_name) do |param| 
        pb.inc 
        block.call(param) 
        end 
        pb.finish 
        result 
    end 
    

    ,然後使用它像

    newresult = function_with_progress(result, "map", "lol", result.count) do |r| 
        r[:omg] 
    end 
    

    ,但因爲它過於抽象,我不會推薦這種方法。它可以像JavaScript或clojure這樣的函數式語言工作,但我認爲它不適合使用ruby。

+0

',因爲你正在做兩個地圖和GROUP_BY,你必須在這裏有兩個輔助方法,這可能會開始越來越messy.' 沒錯,這就是爲什麼我想注入任何塊不只是map和group_by – nurettin 2012-08-08 07:03:26

+0

將pb作爲塊調用參數插入是一個好的開始,謝謝我會接受它,直到我看到更好的答案。 – nurettin 2012-08-08 07:05:07

+0

好吧,我添加了另一個例子(這可能有一些語法錯誤),顯示如何通過傳遞方法的名稱來做到這一點。你也可以繞過lambda表達式,但由於功能不是一階原始的紅寶石,它很快就會變得混亂。 – 2012-08-08 07:11:57