Если вы в порядке с использованием потоков (возможно, безопасным только в МРТ), я использовал это с некоторым успехом:
# create an writable IO to write the response to
# and a readable IO to return / yield to the caller
read_io, write_io = IO.pipe
write_io.binmode
read_io.binmode
# in a separate thread, continue adding chunks to the writable IO,
# which is connected to the readable IO we return
Thread.new do
begin
# pipe chunks to the write stream
# response is the Net::HTTPSuccess object
response.read_body { |chunk| write_io << chunk }
ensure
write_io.close
Thread.current.exit
end
end
# yield a readable stream while the thread feeds the writable
yield read_io
Мы создаем IO чтения и IO записи, которые связаны с IO.pipe
. Поскольку read_body
является блокирующей операцией, которая будет уступать блоку, который мы передаем ему, пока не будет выполнено все тело (весь контент в памяти), нам нужно read_body
в отдельном потоке. Когда куски получены, они пересылаются на наш write_io
. write_io
по сути является прокси, но мы можем читать из read_io
лениво, не дожидаясь загрузки всего тела ответа. Это полезно для потоковых парсеров и, возможно, для вашего варианта использования. CSV принимает IO и может быть лениво проанализирован с помощью этого метода следующим образом:
CSV.new(io).to_enum
Что даст вам ленивое перечисление строк CSV.