我正在使用包含以下代码的gem,允许用户在Web服务查询返回的每条记录上调用一个块,即使该Web服务查询被分页并需要多个请求:
def each(&block)
yield_from_response &block
while resumable?
@response = @resumption_block.call @response
yield_from_response &block
end
end
private
def yield_from_response(&block)
@response.each do |obj|
block.call(obj)
end
end
def resumable?
@response.resumption_token and not @response.resumption_token.empty?
end
(对于这个问题,细节不是很重要,但对于那些关心的人来说,宝石是ruby-oai,而且有问题的代码在resumable.rb。)
我正在尝试将each()
包装在一个方法中,该方法在响应中的每个对象周围返回Enumerable
个包装器对象。如果我不关心恢复,我可以避免上面的代码,只是直接访问响应(这是一个Enumerable
):
response ? response.map { |obj| MyGem::MyWrapper.new(obj) } : []
现在,我很容易通过该块:
response ? response.full.each { |obj| MyGem::MyWrapper.new(obj) } : []
# full() provides the resumable wrapper with each() and yield_from_response()
但在恢复案例中,由于each
没有返回任何有用的内容,因此无法获得结果。
结果集可能非常大(大于物理RAM大),所以我不只是想明确地或隐式地将所有内容转储到临时数组中。
显然,我需要的是编写自己的each()
替代方案而不是阻止,只返回Enumerable
中objs
嵌入的@responses
}。我觉得在没有编写完整的Enumerable
实现的情况下应该有一个简单的方法来做到这一点,但我对Ruby来说已经足够新了,它还不清楚它是什么。
我能想到的最好的是以下内容,这也是错误的:
def to_enumerable(response)
response.each { |obj| yield MyGem::MyWrapper.new(obj) }
resumption_block = response.resumption_block
if resumption_block
while response.resumption_token && !response.resumption_token.empty?
response = resumption_block.call response
response.each { |obj| yield MyGem::MyWrapper.new(obj) }
end
end
end
这是不正确的,因为当然,Ruby的yield
并没有真正“屈服”,它只是调用一个块,如果我想传入一个块,我可以调用原来的each()
如果我能弄清楚如何将重复的作业转换为response
的{{1}}序列,我可以使用responses
,但我不知道该怎么做。
ETA:在仔细检查时看起来flat_map
不是懒惰的,如果我想避免创建数组(从而耗尽大数据集的内存)我可能实际上想要Enumerable
。如果我理解正确的区别。