我反复使用这种模式:
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 :(得分:2)
有几种方法可以实现这一目标,在表达方面有各种权衡:
将进度条作为块参数发送
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
创建一个新的地图功能,自动增加进度条(你可以直接覆盖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,你必须在这里有两个辅助方法,这可能会开始变得混乱。
使用高阶函数
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。