Use duck typing to detect IO-like objects.
This commit is contained in:
parent
1a028fcbaa
commit
05a9ba3f20
|
@ -176,7 +176,7 @@ module Zip
|
|||
end
|
||||
|
||||
def read_c_dir_entry(io) #:nodoc:all
|
||||
path = if io.is_a?(::IO)
|
||||
path = if io.respond_to?(:path)
|
||||
io.path
|
||||
else
|
||||
io
|
||||
|
@ -548,7 +548,7 @@ module Zip
|
|||
end
|
||||
|
||||
def get_raw_input_stream(&block)
|
||||
if @zipfile.is_a?(::IO) || @zipfile.is_a?(::StringIO)
|
||||
if @zipfile.respond_to?(:seek) && @zipfile.respond_to?(:read)
|
||||
yield @zipfile
|
||||
else
|
||||
::File.open(@zipfile, 'rb', &block)
|
||||
|
|
|
@ -49,6 +49,7 @@ module Zip
|
|||
MAX_SEGMENT_SIZE = 3_221_225_472
|
||||
MIN_SEGMENT_SIZE = 65_536
|
||||
DATA_BUFFER_SIZE = 8192
|
||||
IO_METHODS = [:tell, :seek, :read, :close]
|
||||
|
||||
attr_reader :name
|
||||
|
||||
|
@ -117,13 +118,13 @@ module Zip
|
|||
# (This can be used to extract data from a
|
||||
# downloaded zip archive without first saving it to disk.)
|
||||
def open_buffer(io, options = {})
|
||||
unless io.is_a?(IO) || io.is_a?(String) || io.is_a?(Tempfile) || io.is_a?(StringIO)
|
||||
raise "Zip::File.open_buffer expects an argument of class String, IO, StringIO, or Tempfile. Found: #{io.class}"
|
||||
unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
|
||||
raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
|
||||
end
|
||||
if io.is_a?(::String)
|
||||
require 'stringio'
|
||||
io = ::StringIO.new(io)
|
||||
elsif io.is_a?(IO)
|
||||
elsif io.respond_to?(:binmode)
|
||||
# https://github.com/rubyzip/rubyzip/issues/119
|
||||
io.binmode
|
||||
end
|
||||
|
|
|
@ -111,8 +111,7 @@ module Zip
|
|||
protected
|
||||
|
||||
def get_io(io_or_file, offset = 0)
|
||||
case io_or_file
|
||||
when IO, StringIO
|
||||
if io_or_file.respond_to?(:seek)
|
||||
io = io_or_file.dup
|
||||
io.seek(offset, ::IO::SEEK_SET)
|
||||
io
|
||||
|
|
|
@ -3,6 +3,16 @@ require 'test_helper'
|
|||
class ZipInputStreamTest < MiniTest::Test
|
||||
include AssertEntry
|
||||
|
||||
class IOLike
|
||||
extend Forwardable
|
||||
|
||||
def initialize(path, mode)
|
||||
@file = File.new(path, mode)
|
||||
end
|
||||
|
||||
delegate ::Zip::File::IO_METHODS => :@file
|
||||
end
|
||||
|
||||
def test_new
|
||||
zis = ::Zip::InputStream.new(TestZipFile::TEST_ZIP2.zip_name)
|
||||
assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
|
||||
|
@ -48,6 +58,13 @@ class ZipInputStreamTest < MiniTest::Test
|
|||
assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
|
||||
end
|
||||
|
||||
def test_open_io_like_with_block
|
||||
::Zip::InputStream.open(IOLike.new(TestZipFile::TEST_ZIP2.zip_name, 'rb')) do |zis|
|
||||
assert_stream_contents(zis, TestZipFile::TEST_ZIP2)
|
||||
assert_equal(true, zis.eof?)
|
||||
end
|
||||
end
|
||||
|
||||
def test_incomplete_reads
|
||||
::Zip::InputStream.open(TestZipFile::TEST_ZIP2.zip_name) do |zis|
|
||||
entry = zis.get_next_entry # longAscii.txt
|
||||
|
|
Loading…
Reference in New Issue