diff --git a/lib/xlsxtream/io/rubyzip.rb b/lib/xlsxtream/io/rubyzip.rb index f706366..f60ef4f 100644 --- a/lib/xlsxtream/io/rubyzip.rb +++ b/lib/xlsxtream/io/rubyzip.rb @@ -1,12 +1,16 @@ require "zip" +require "xlsxtream/errors" module Xlsxtream module IO class RubyZip - def initialize(path_or_io) - @stream = path_or_io.respond_to? :reopen - path_or_io.binmode if path_or_io.respond_to? :binmode - @zos = Zip::OutputStream.new(path_or_io, @stream) + def initialize(io) + unless io.respond_to? :pos and io.respond_to? :pos= + raise Error, 'IO is not seekable' + end + io.binmode if io.respond_to? :binmode + stream = true + @zos = Zip::OutputStream.new(io, stream) end def <<(data) @@ -20,7 +24,6 @@ def add_file(path) def close os = @zos.close_buffer os.flush if os.respond_to? :flush - os.close if !@stream and os.respond_to? :close end end end diff --git a/lib/xlsxtream/workbook.rb b/lib/xlsxtream/workbook.rb index 0c6cd31..d948a5b 100644 --- a/lib/xlsxtream/workbook.rb +++ b/lib/xlsxtream/workbook.rb @@ -1,12 +1,9 @@ # encoding: utf-8 -require "stringio" require "xlsxtream/errors" require "xlsxtream/xml" require "xlsxtream/shared_string_table" require "xlsxtream/workbook" require "xlsxtream/io/rubyzip" -require "xlsxtream/io/directory" -require "xlsxtream/io/stream" module Xlsxtream class Workbook @@ -22,8 +19,8 @@ class Workbook class << self - def open(data = nil, options = {}) - workbook = new(data, options) + def open(output = nil, options = {}) + workbook = new(output, options) if block_given? begin yield workbook @@ -37,10 +34,16 @@ def open(data = nil, options = {}) end - def initialize(data = nil, options = {}) + def initialize(output = nil, options = {}) + output ||= StringIO.new @options = options io_wrapper = options[:io_wrapper] || IO::RubyZip - @io = io_wrapper.new(data || StringIO.new) + if output.is_a?(String) || !output.respond_to?(:<<) + @file = File.open(output, 'wb') + @io = io_wrapper.new(@file) + else + @io = io_wrapper.new(output) + end @sst = SharedStringTable.new @worksheets = Hash.new { |hash, name| hash[name] = hash.size + 1 } end @@ -74,6 +77,7 @@ def close write_root_rels write_content_types @io.close + @file.close if @file nil end diff --git a/test/xlsxtream/io/directory_test.rb b/test/xlsxtream/io/directory_test.rb new file mode 100644 index 0000000..6c96c2e --- /dev/null +++ b/test/xlsxtream/io/directory_test.rb @@ -0,0 +1,32 @@ +require 'test_helper' +require 'xlsxtream/io/directory' +require 'pathname' + +module Xlsxtream + module IO + class DirectoryTest < Minitest::Test + + def test_writes_of_multiple_files + Dir.mktmpdir do |dir| + io = Xlsxtream::IO::Directory.new(dir) + io.add_file("book1.xml") + io << '' + io.add_file("book2.xml") + io << '' + io << '' + io.add_file("empty.txt") + io.add_file("another.xml") + io << '' + io.close + + dir = Pathname(dir) + assert_equal '', dir.join('empty.txt').read + assert_equal '', dir.join('book1.xml').read + assert_equal '', dir.join('book2.xml').read + assert_equal '', dir.join('another.xml').read + end + + end + end + end +end diff --git a/test/xlsxtream/io/hash_test.rb b/test/xlsxtream/io/hash_test.rb new file mode 100644 index 0000000..efbd17d --- /dev/null +++ b/test/xlsxtream/io/hash_test.rb @@ -0,0 +1,30 @@ +require 'test_helper' +require 'xlsxtream/io/hash' + +module Xlsxtream + module IO + class HashTest < Minitest::Test + + def test_writes_of_multiple_files + buffer = StringIO.new + + io = Xlsxtream::IO::Hash.new(buffer) + io.add_file("book1.xml") + io << '' + io.add_file("book2.xml") + io << '' + io << '' + io.add_file("empty.txt") + io.add_file("another.xml") + io << '' + io.close + + file_contents = io.to_h + assert_equal '', file_contents['empty.txt'] + assert_equal '', file_contents['book1.xml'] + assert_equal '', file_contents['book2.xml'] + assert_equal '', file_contents['another.xml'] + end + end + end +end diff --git a/test/xlsxtream/io/rubyzip_test.rb b/test/xlsxtream/io/rubyzip_test.rb new file mode 100644 index 0000000..be8666c --- /dev/null +++ b/test/xlsxtream/io/rubyzip_test.rb @@ -0,0 +1,40 @@ +require 'test_helper' +require 'xlsxtream/io/rubyzip' +require 'zip' + +module Xlsxtream + module IO + class RubyZipTest < Minitest::Test + + def test_writes_of_multiple_files + zip_buf = Tempfile.new('ztio-test') + + io = Xlsxtream::IO::RubyZip.new(zip_buf) + io.add_file("book1.xml") + io << '' + io.add_file("book2.xml") + io << '' + io << '' + io.add_file("empty.txt") + io.add_file("another.xml") + io << '' + io.close + + zip_buf.rewind + + file_contents = {} + ::Zip::File.open(zip_buf) do |zip_file| + zip_file.each do |entry| + file_contents[entry.name] = entry.get_input_stream.read + end + end + assert_equal '', file_contents['empty.txt'] + assert_equal '', file_contents['book1.xml'] + assert_equal '', file_contents['book2.xml'] + assert_equal '', file_contents['another.xml'] + ensure + zip_buf.close! if zip_buf + end + end + end +end diff --git a/test/xlsxtream/io/stream_test.rb b/test/xlsxtream/io/stream_test.rb new file mode 100644 index 0000000..aa756ed --- /dev/null +++ b/test/xlsxtream/io/stream_test.rb @@ -0,0 +1,36 @@ +require 'test_helper' +require 'xlsxtream/io/stream' + +module Xlsxtream + module IO + class StreamTest < Minitest::Test + + def test_writes_of_multiple_files + buffer = StringIO.new + + io = Xlsxtream::IO::Stream.new(buffer) + io.add_file("book1.xml") + io << '' + io.add_file("book2.xml") + io << '' + io << '' + io.add_file("empty.txt") + io.add_file("another.xml") + io << '' + io.close + + file_contents = buffer.string + assert_equal <<-EOF, file_contents +book1.xml + +book2.xml + +empty.txt + +another.xml + +EOF + end + end + end +end diff --git a/test/xlsxtream/workbook_test.rb b/test/xlsxtream/workbook_test.rb index d5ce02a..460ea98 100644 --- a/test/xlsxtream/workbook_test.rb +++ b/test/xlsxtream/workbook_test.rb @@ -1,10 +1,27 @@ require 'test_helper' +require 'tempfile' require 'xlsxtream/workbook' require 'xlsxtream/io/hash' module Xlsxtream class WorksheetTest < Minitest::Test + def test_workbook_from_path + tempfile = Tempfile.new('xlsxtream') + Workbook.open(tempfile.path) {} + refute_equal 0, tempfile.size + ensure + tempfile.close! if tempfile + end + + def test_workbook_from_io + tempfile = Tempfile.new('xlsxtream') + Workbook.open(tempfile) {} + refute_equal 0, tempfile.size + ensure + tempfile.close! if tempfile + end + def test_empty_workbook iow_spy = io_wrapper_spy Workbook.open(nil, :io_wrapper => iow_spy) {}