2

我反复使用这种模式:

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 等)中?

编辑:改写问题

4

1 回答 1

2

有几种方法可以实现这一点,并在表现力方面进行各种权衡:

  1. 将进度条作为块参数发送

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

    当然,由于您同时使用 map 和 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​​。

于 2012-08-08T07:00:34.657 回答