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)
  outbuf = outbuf.to_s.clear
  # buffer in JRuby is sometimes US-ASCII, force to ASCII-8BIT
  outbuf.force_encoding(Encoding::BINARY)

  while current_io
    current_io.read(length, @buffer)
    outbuf << @buffer.force_encoding(Encoding::BINARY)

    if length
      length -= @buffer.bytesize
      break if length.zero?
    end

    advance_io
  end

  outbuf unless length && outbuf.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 57
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 52
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 70
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 65
def current_io
  @ios[@index]
end