Skip to content

Instantly share code, notes, and snippets.

@julik
Created February 24, 2009 10:33
Show Gist options
  • Save julik/69504 to your computer and use it in GitHub Desktop.
Save julik/69504 to your computer and use it in GitHub Desktop.
# Stream wrapper that read's IOs in succession. Can be fed to Net::HTTP. We use it to send a mixture of StringIOs
# and File handles to Net::HTTP which will be used when sending the request, not when composing it. Will skip over
# depleted IOs. Can be also used to roll across files like so:
#
# tape = TapeIO.new(File.open(__FILE__), File.open('/etc/passwd'))
class TapeIO
attr_accessor :substreams
attr_accessor :release_after_use
def initialize(*any_ios)
@pending = *any_ios.flatten
end
def read(buffer_size = 1024)
# Read off the first element in the stack
current_io = @pending.shift
return false if !current_io
buf = current_io.read(buffer_size)
if !buf && @pending.empty? # End of streams
release_handle(current_io)
false
elsif !buf # This IO is depleted, but next one is available
release_handle(current_io)
read(buffer_size)
elsif buf.length < buffer_size # This IO is depleted, but there might be more
release_handle(current_io)
buf + (read(buffer_size - buf.length) || '') # and recurse
else # just return the buffer
@pending.unshift(current_io) # put the current back
buf
end
end
private
def release_handle(io)
return unless @release_after_use
io.close if io.respond_to?(:close)
end
end
require 'stringio'
string_ios = ["this", "", " is", " very", "", "", " interesting"].map{|e| StringIO.new(e) }
stream = TapeIO.new(string_ios, File.open(__FILE__, 'r'))
puts stream.read(256898)
puts stream.read(256898)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment