Class: ZipTricks::RemoteIO

Inherits:
Object
  • Object
show all
Defined in:
lib/zip_tricks/remote_io.rb

Overview

An object that fakes just-enough of an IO to be dangerous

  • or, more precisely, to be useful as a source for the FileReader central directory parser. Effectively we substitute an IO object for an object that fetches parts of the remote file over HTTP using Range: headers. The RemoteIO acts as an adapter between an object that performs the actual fetches over HTTP and an object that expects a handful of IO methods to be available.

Instance Method Summary collapse

Constructor Details

#initialize(fetcher = :NOT_SET) ⇒ RemoteIO

Returns a new instance of RemoteIO.

Parameters:

  • fetcher (#request_object_size, #request_range) (defaults to: :NOT_SET)

    an object that perform fetches



12
13
14
15
16
# File 'lib/zip_tricks/remote_io.rb', line 12

def initialize(fetcher = :NOT_SET)
  @pos = 0
  @fetcher = fetcher
  @remote_size = false
end

Instance Method Details

#read(n_bytes = nil) ⇒ String

Emulates IO#read, but requires the number of bytes to read The read will be limited to the size of the remote resource relative to the current offset in the IO, so if you are at offset 0 in the IO of size 10, doing a read(20) will only return you 10 bytes of result, and not raise any exceptions.

Parameters:

  • n_bytes (Fixnum, nil) (defaults to: nil)

    how many bytes to read, or nil to read all the way to the end

Returns:

  • (String)

    the read bytes

Raises:

  • (ArgumentError)


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/zip_tricks/remote_io.rb', line 41

def read(n_bytes = nil)
  @remote_size ||= request_object_size

  # If the resource is empty there is nothing to read
  return if @remote_size.zero?

  maximum_avaialable = @remote_size - @pos
  n_bytes ||= maximum_avaialable # nil == read to the end of file
  return '' if n_bytes.zero?
  raise ArgumentError, "No negative reads(#{n_bytes})" if n_bytes < 0

  n_bytes = clamp(0, n_bytes, maximum_avaialable)

  read_n_bytes_from_remote(@pos, n_bytes).tap do |data|
    raise "Remote read returned #{data.bytesize} bytes instead of #{n_bytes} as requested" if data.bytesize != n_bytes
    @pos = clamp(0, @pos + data.bytesize, @remote_size)
  end
end

#seek(offset, mode = IO::SEEK_SET) ⇒ Object

Emulates IO#seek



19
20
21
22
23
24
# File 'lib/zip_tricks/remote_io.rb', line 19

def seek(offset, mode = IO::SEEK_SET)
  raise "Unsupported read mode #{mode}" unless mode == IO::SEEK_SET
  @remote_size ||= request_object_size
  @pos = clamp(0, offset, @remote_size)
  0 # always return 0!
end

#sizeFixnum

Emulates IO#size.

Returns:

  • (Fixnum)

    the size of the remote resource



29
30
31
# File 'lib/zip_tricks/remote_io.rb', line 29

def size
  @remote_size ||= request_object_size
end

#tellFixnum

Returns the current pointer position within the IO

Returns:

  • (Fixnum)


63
64
65
# File 'lib/zip_tricks/remote_io.rb', line 63

def tell
  @pos
end