延迟枚举,直到块为假

时间:2018-09-21 05:06:37

标签: ruby enumerable

我编写了一个Enumerable类,以无缝地和延迟地获取API请求的所有页面。

class Pager
  include Enumerable

  def initialize(&fetch_next_page)
    @fetch_next_page = fetch_next_page
    reset
  end

  def reset
    @page_number = 0
  end

  private def next_page
    @page_number += 1

    return @fetch_next_page.call(@page_number)
  end

  def each(&block)
    if block_given?
      while resp = next_page
        resp.each(&block)
      end
      reset
    else
      to_enum(:each)
    end
  end
end

这是如何使用它的一个例子。

pager = Pager.new do |page_number|
  response = fetch_page( page: page_number, **some_options )

  response.page <= response.total_pages ? response.stuff : false
end

但是我已经意识到,所有要做的就是执行一个返回Enumerable的块,直到其为false为止,并且将Enumerables展平。

pager = Pager.new { |page_number|
  page_number <= 3 ? 1.upto(page_number) : false
}

# [1, 1, 2, 1, 2, 3]
puts pager.to_a.inspect

有没有更简单的方法来做到这一点?我已经接近枚举器,但是无法进行拼合处理。

def paginate(&fetch_next)
  return Enumerator.new do |yielder|
    page_number = 1
    while ret = fetch_next.call(page_number)
      yielder.yield(*ret)
      page_number += 1
    end
  end
end

pager = paginate { |page_number|
  page_number <= 3 ? 1.upto(page_number) : false
}

# [1, [1, 2], [1, 2, 3]]
puts pager.to_a.inspect

1 个答案:

答案 0 :(得分:3)

枚举器的输出不正确的原因确实与splat运算符有关。

如果您将多个值传递给 yield ,它们将一次全部产生,而您想一次一一产生。既然有障碍:

cose-bilkent

这将产生3个产量。第一个带有参数{ |page_number| page_number <= 3 ? 1.upto(page_number) : false } ,第二个带有参数1,第三个带有参数1, 2。如果要将它们作为单个产量生产,则必须更改以下内容:

1, 2, 3

yielder.yield(*ret)

# should be changed to

ret.each { |e| yielder.yield e }
# or
ret.each { |e| yielder << e }
# depending on your preference