我反复使用这种模式:
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 调用注入(inject)到 Progress_cache block 内的 block (map、group_by 等)中?
编辑:重新表述问题
最佳答案
有几种方法可以实现这一点,并在表达能力方面进行各种权衡:
将进度条作为 block 参数发送
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
创建一个新的 map 函数,自动增加进度条(您可以直接覆盖 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。
关于ruby - 将 ruby 代码注入(inject)嵌套block,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11858799/