Class: Amp::Support::MultiIO

Inherits:
Object
  • Object
show all
Defined in:
lib/amp/support/multi_io.rb

Overview

MultiIO

A MultiIO is a class which joins multiple IO classes together. It responds to #read, and its constituent IOs must respond to #read. Since, currently, it only needs to be able to read (and perhaps rewind), that’s all it does. It allows one to feed, say, 3 separate input IO objects into a GZipWriter, and have it seamlessly traverse all 3 IOs.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*ios) ⇒ MultiIO

Initializes the MultiIO to contain the given IO objects, in the order in which they are specified as arguments.

Parameters:

  • ios (Array<IO>)

    The IO objects we are concatenating



24
25
26
27
# File 'lib/amp/support/multi_io.rb', line 24

def initialize(*ios)
  @ios = ios
  rewind
end

Instance Attribute Details

#current_io_idxObject

Points to the current IO object in the @ios array.



14
15
16
# File 'lib/amp/support/multi_io.rb', line 14

def current_io_idx
  @current_io_idx
end

#current_posObject

Tracks our current index into the “joined” stream. In other words, if they were all lumped into 1 stream, how many bytes in would we be?



17
18
19
# File 'lib/amp/support/multi_io.rb', line 17

def current_pos
  @current_pos
end

#iosObject

These are all the base IO objects we are joining together.



12
13
14
# File 'lib/amp/support/multi_io.rb', line 12

def ios
  @ios
end

Instance Method Details

#read(amt = nil) ⇒ String

Reads from the concatenated IO stream, crossing streams if necessary. (DON’T CROSS THE STREAMS!!!!)

Parameters:

  • amt (Integer) (defaults to: nil)

    (nil) The number of bytes to read from the overall stream. If nil, reads until the end of the stream.

Returns:

  • (String)

    the data read in from the stream



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/amp/support/multi_io.rb', line 50

def read(amt=nil)
  if amt==nil # if nil, read it all
    return @ios[@current_io_idx..-1].map {|io| io.read}.join
  end
  results = [] # result strings
  amount_read = 0 # how much have we read? We need this to match the +amt+ param
  cur_spot = current_io.tell # our current position
  while amount_read < amt # until we've read enough to meet the request
    results << current_io.read(amt - amount_read) # read enough to finish
    amount_read += current_io.tell - cur_spot # but we might not have actually read that much
    @current_pos += current_io.tell - cur_spot # update ivar
    # Do we need to go to the next IO stream?
    if amount_read < amt && @current_io_idx < @ios.size - 1
      # go to the next stream
      @current_io_idx += 1 
      # reset it just in case
      current_io.seek(0)
    # are we at the last stream?
    elsif @current_io_idx >= @ios.size - 1
      break
    end
    # if we need to read from another stream, then remember we're at the start of it
    cur_spot = 0
  end
  # join 'em up
  results.join
end

#rewindObject

Rewinds all the IO objects to position 0.



31
32
33
34
35
# File 'lib/amp/support/multi_io.rb', line 31

def rewind
  @ios.each {|io| io.seek(0) } 
  @current_pos = 0
  @current_io_idx = 0
end

#tellInteger

Gets the current position in the concatenated IO stream.

Returns:

  • (Integer)

    position in the IO stream (if all were 1 big stream, that is)



41
# File 'lib/amp/support/multi_io.rb', line 41

def tell; @current_pos; end