diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 22898000..e1e72aa2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ jobs: fail-fast: false matrix: os: [ubuntu] - ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1', jruby, truffleruby] + ruby: ['2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3', jruby, truffleruby] include: - os: macos ruby: '2.4' @@ -31,12 +31,36 @@ jobs: FULL_ZIP64_TEST: 1 run: bundle exec rake + test-frozen-string-literal: + strategy: + fail-fast: false + matrix: + os: [ubuntu] + ruby: ['3.3'] + runs-on: ${{ matrix.os }}-latest + continue-on-error: true + steps: + - name: Checkout rubyzip code + uses: actions/checkout@v2 + + - name: Install and set up ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + + - name: Run the tests + env: + RUBYOPT: --enable-frozen-string-literal + FULL_ZIP64_TEST: 1 + run: bundle exec rake + test-yjit: strategy: fail-fast: false matrix: os: [ubuntu, macos] - ruby: ['3.1', head] + ruby: ['3.1', '3.2', '3.3', head] runs-on: ${{ matrix.os }}-latest continue-on-error: true steps: diff --git a/README.md b/README.md index 9fe2ba68..38cb3cb3 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ If `::Zip::InputStream` finds such entry in the zip archive it will raise an exc Rubyzip supports reading/writing zip files with traditional zip encryption (a.k.a. "ZipCrypto"). AES encryption is not yet supported. It can be used with buffer streams, e.g.: ```ruby -Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |out| +Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |out| out.put_next_entry("my_file.txt") out.write my_data end.string diff --git a/lib/zip/extra_field/zip64.rb b/lib/zip/extra_field/zip64.rb index 9826c6cf..93bf7abd 100644 --- a/lib/zip/extra_field/zip64.rb +++ b/lib/zip/extra_field/zip64.rb @@ -59,7 +59,7 @@ def pack_for_local def pack_for_c_dir # central directory entries contain only fields that didn't fit in the main entry part - packed = ''.force_encoding('BINARY') + packed = ''.b packed << [@original_size].pack('Q<') if @original_size packed << [@compressed_size].pack('Q<') if @compressed_size packed << [@relative_header_offset].pack('Q<') if @relative_header_offset diff --git a/lib/zip/file.rb b/lib/zip/file.rb index fbbf17c9..256f052e 100644 --- a/lib/zip/file.rb +++ b/lib/zip/file.rb @@ -140,7 +140,7 @@ def open(file_name, dep_create = false, create: false, **options) def add_buffer Zip.warn_about_v3_api('Zip::File.add_buffer') - io = ::StringIO.new('') + io = ::StringIO.new zf = ::Zip::File.new(io, true, true) yield zf zf.write_buffer(io) @@ -411,7 +411,7 @@ def commit end # Write buffer write changes to buffer and return - def write_buffer(io = ::StringIO.new('')) + def write_buffer(io = ::StringIO.new) return unless commit_required? ::Zip::OutputStream.write_buffer(io) do |zos| diff --git a/lib/zip/filesystem.rb b/lib/zip/filesystem.rb index d9928d4a..77655c6e 100644 --- a/lib/zip/filesystem.rb +++ b/lib/zip/filesystem.rb @@ -239,7 +239,7 @@ def directory?(filename) end def open(filename, mode = 'r', permissions = 0o644, &block) - mode.delete!('b') # ignore b option + mode = mode.delete('b') # ignore b option case mode when 'r' @mapped_zip.get_input_stream(filename, &block) @@ -619,7 +619,7 @@ def each end def expand_path(path) - expanded = path.start_with?('/') ? path : ::File.join(@pwd, path) + expanded = path.start_with?('/') ? path.dup : ::File.join(@pwd, path) expanded.gsub!(/\/\.(\/|$)/, '') expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '') expanded.empty? ? '/' : expanded diff --git a/lib/zip/inflater.rb b/lib/zip/inflater.rb index 530f98aa..31627ebb 100644 --- a/lib/zip/inflater.rb +++ b/lib/zip/inflater.rb @@ -3,11 +3,11 @@ class Inflater < Decompressor #:nodoc:all def initialize(*args) super - @buffer = +'' + @buffer = ''.b @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS) end - def read(length = nil, outbuf = '') + def read(length = nil, outbuf = ''.b) return (length.nil? || length.zero? ? '' : nil) if eof while length.nil? || (@buffer.bytesize < length) diff --git a/lib/zip/ioextras.rb b/lib/zip/ioextras.rb index 63774d33..6748776d 100644 --- a/lib/zip/ioextras.rb +++ b/lib/zip/ioextras.rb @@ -6,14 +6,14 @@ module IOExtras #:nodoc: class << self def copy_stream(ostream, istream) - ostream.write(istream.read(CHUNK_SIZE, '')) until istream.eof? + ostream.write(istream.read(CHUNK_SIZE, ''.b)) until istream.eof? end def copy_stream_n(ostream, istream, nbytes) toread = nbytes while toread > 0 && !istream.eof? tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread - ostream.write(istream.read(tr, '')) + ostream.write(istream.read(tr, ''.b)) toread -= tr end end diff --git a/lib/zip/ioextras/abstract_input_stream.rb b/lib/zip/ioextras/abstract_input_stream.rb index 8392d240..dc239d67 100644 --- a/lib/zip/ioextras/abstract_input_stream.rb +++ b/lib/zip/ioextras/abstract_input_stream.rb @@ -11,13 +11,13 @@ def initialize super @lineno = 0 @pos = 0 - @output_buffer = '' + @output_buffer = ''.b end attr_accessor :lineno attr_reader :pos - def read(number_of_bytes = nil, buf = '') + def read(number_of_bytes = nil, buf = ''.b) tbuf = if @output_buffer.bytesize > 0 if number_of_bytes <= @output_buffer.bytesize @output_buffer.slice!(0, number_of_bytes) @@ -26,7 +26,7 @@ def read(number_of_bytes = nil, buf = '') rbuf = sysread(number_of_bytes, buf) out = @output_buffer out << rbuf if rbuf - @output_buffer = '' + @output_buffer = ''.b out end else @@ -93,7 +93,7 @@ def ungetc(byte) def flush ret_val = @output_buffer - @output_buffer = '' + @output_buffer = ''.b ret_val end diff --git a/lib/zip/output_stream.rb b/lib/zip/output_stream.rb index 3d1293ab..3dac2a48 100644 --- a/lib/zip/output_stream.rb +++ b/lib/zip/output_stream.rb @@ -62,7 +62,7 @@ def open(file_name, dep_encrypter = nil, encrypter: nil) end # Same as #open but writes to a filestream instead - def write_buffer(io = ::StringIO.new(''), dep_encrypter = nil, encrypter: nil) + def write_buffer(io = ::StringIO.new, dep_encrypter = nil, encrypter: nil) Zip.warn_about_v3_api('Zip::OutputStream.write_buffer') unless dep_encrypter.nil? io.binmode if io.respond_to?(:binmode) diff --git a/lib/zip/pass_thru_decompressor.rb b/lib/zip/pass_thru_decompressor.rb index e638540e..b51e19f1 100644 --- a/lib/zip/pass_thru_decompressor.rb +++ b/lib/zip/pass_thru_decompressor.rb @@ -5,7 +5,7 @@ def initialize(*args) @read_so_far = 0 end - def read(length = nil, outbuf = '') + def read(length = nil, outbuf = ''.b) return (length.nil? || length.zero? ? '' : nil) if eof if length.nil? || (@read_so_far + length) > decompressed_size diff --git a/test/encryption_test.rb b/test/encryption_test.rb index d3ed5ffb..2feba1d9 100644 --- a/test/encryption_test.rb +++ b/test/encryption_test.rb @@ -19,7 +19,7 @@ def test_encrypt @rand = [250, 143, 107, 13, 143, 22, 155, 75, 228, 150, 12] @output = ::Zip::DOSTime.stub(:now, ::Zip::DOSTime.new(2014, 12, 17, 15, 56, 24)) do Random.stub(:rand, ->(_range) { @rand.shift }) do - Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |zos| + Zip::OutputStream.write_buffer(::StringIO.new, Zip::TraditionalEncrypter.new('password')) do |zos| zos.put_next_entry('file1.txt') zos.write ::File.open(INPUT_FILE1).read end.string diff --git a/test/file_test.rb b/test/file_test.rb index ece14860..e596881e 100644 --- a/test/file_test.rb +++ b/test/file_test.rb @@ -503,7 +503,7 @@ def test_write_buffer zf = ::Zip::File.new(TEST_ZIP.zip_name) old_name = zf.entries.first zf.rename(old_name, new_name) - io = ::StringIO.new('') + io = ::StringIO.new buffer = zf.write_buffer(io) File.open(TEST_ZIP.zip_name, 'wb') { |f| f.write buffer.string } zf_read = ::Zip::File.new(TEST_ZIP.zip_name) diff --git a/test/input_stream_test.rb b/test/input_stream_test.rb index bfaf6dff..47ea7e05 100644 --- a/test/input_stream_test.rb +++ b/test/input_stream_test.rb @@ -136,7 +136,7 @@ def test_rewind assert_equal(TestZipFile::TEST_ZIP2.entry_names[0], e.name) # Do a little reading - buf = '' + buf = ''.b buf << zis.read(100) assert_equal(100, zis.pos) buf << (zis.gets || '') @@ -145,7 +145,7 @@ def test_rewind zis.rewind - buf2 = '' + buf2 = ''.b buf2 << zis.read(100) buf2 << (zis.gets || '') buf2 << (zis.gets || '') diff --git a/test/ioextras/abstract_output_stream_test.rb b/test/ioextras/abstract_output_stream_test.rb index 9b02309c..cf5256ff 100644 --- a/test/ioextras/abstract_output_stream_test.rb +++ b/test/ioextras/abstract_output_stream_test.rb @@ -8,7 +8,7 @@ class TestOutputStream attr_accessor :buffer def initialize - @buffer = '' + @buffer = ''.b end def <<(data) @@ -58,12 +58,12 @@ def test_print assert_equal("hello world. You ok out there?\nI sure hope so!\n", @output_stream.buffer) $, = 'X' - @output_stream.buffer = '' + @output_stream.buffer = ''.b @output_stream.print('monkey', 'duck', 'zebra') assert_equal("monkeyXduckXzebra\n", @output_stream.buffer) $\ = nil - @output_stream.buffer = '' + @output_stream.buffer = ''.b @output_stream.print(20) assert_equal('20', @output_stream.buffer) end @@ -87,19 +87,19 @@ def test_puts @output_stream.puts('hello', 'world') assert_equal("\nhello\nworld\n", @output_stream.buffer) - @output_stream.buffer = '' + @output_stream.buffer = ''.b @output_stream.puts("hello\n", "world\n") assert_equal("hello\nworld\n", @output_stream.buffer) - @output_stream.buffer = '' + @output_stream.buffer = ''.b @output_stream.puts(%W[hello\n world\n]) assert_equal("hello\nworld\n", @output_stream.buffer) - @output_stream.buffer = '' + @output_stream.buffer = ''.b @output_stream.puts(%W[hello\n world\n], 'bingo') assert_equal("hello\nworld\nbingo\n", @output_stream.buffer) - @output_stream.buffer = '' + @output_stream.buffer = ''.b @output_stream.puts(16, 20, 50, 'hello') assert_equal("16\n20\n50\nhello\n", @output_stream.buffer) end diff --git a/test/output_stream_test.rb b/test/output_stream_test.rb index b2f64ab9..02e59d64 100644 --- a/test/output_stream_test.rb +++ b/test/output_stream_test.rb @@ -23,7 +23,7 @@ def test_open end def test_write_buffer - io = ::StringIO.new('') + io = ::StringIO.new buffer = ::Zip::OutputStream.write_buffer(io) do |zos| zos.comment = TEST_ZIP.comment write_test_zip(zos) @@ -33,7 +33,7 @@ def test_write_buffer end def test_write_buffer_binmode - io = ::StringIO.new('') + io = ::StringIO.new buffer = ::Zip::OutputStream.write_buffer(io) do |zos| zos.comment = TEST_ZIP.comment write_test_zip(zos) diff --git a/test/test_helper.rb b/test/test_helper.rb index 76d57978..1b446bb5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -145,7 +145,7 @@ class TestOutputStream attr_accessor :buffer def initialize - @buffer = '' + @buffer = ''.b end def <<(data)