class HTTP::FormData::CompositeIO

Provides IO interface across multiple IO objects.

Public Class Methods

new(ios) click to toggle source

@param [Array<IO>] ios Array of IO objects

# File lib/http/form_data/composite_io.rb, line 10
def initialize(ios)
  @index  = 0
  @buffer = "".b
  @ios    = ios.map do |io|
    if io.is_a?(String)
      StringIO.new(io)
    elsif io.respond_to?(:read)
      io
    else
      raise ArgumentError,
        "#{io.inspect} is neither a String nor an IO object"
    end
  end
end

Public Instance Methods

read(length = nil, outbuf = nil) click to toggle source

Reads and returns partial content acrosss multiple IO objects.

@param [Integer] length Number of bytes to retrieve @param [String] outbuf String to be replaced with retrieved data

@return [String, nil]

# File lib/http/form_data/composite_io.rb, line 31
def read(length = nil, outbuf = nil)
  data   = outbuf.clear.force_encoding(Encoding::BINARY) if outbuf
  data ||= "".b

  read_chunks(length) { |chunk| data << chunk }

  data unless length && data.empty?
end
rewind() click to toggle source

Rewinds all IO objects and set cursor to the first IO object.

# File lib/http/form_data/composite_io.rb, line 46
def rewind
  @ios.each(&:rewind)
  @index = 0
end
size() click to toggle source

Returns sum of all IO sizes.

# File lib/http/form_data/composite_io.rb, line 41
def size
  @size ||= @ios.map(&:size).inject(0, :+)
end

Private Instance Methods

advance_io() click to toggle source

Advances cursor to the next IO object.

# File lib/http/form_data/composite_io.rb, line 83
def advance_io
  @index += 1
end
current_io() click to toggle source

Returns IO object under the cursor.

# File lib/http/form_data/composite_io.rb, line 78
def current_io
  @ios[@index]
end
read_chunks(length = nil) { |force_encoding(BINARY)| ... } click to toggle source

Yields chunks with total length up to `length`.

# File lib/http/form_data/composite_io.rb, line 54
def read_chunks(length = nil)
  while (chunk = readpartial(length))
    yield chunk.force_encoding(Encoding::BINARY)

    next if length.nil?

    length -= chunk.bytesize

    break if length.zero?
  end
end
readpartial(max_length = nil) click to toggle source

Reads chunk from current IO with length up to `max_length`.

# File lib/http/form_data/composite_io.rb, line 67
def readpartial(max_length = nil)
  while current_io
    chunk = current_io.read(max_length, @buffer)

    return chunk if chunk && !chunk.empty?

    advance_io
  end
end