Extract `FileSystem::Dir` from the main filesystem file.

This commit is contained in:
Robert Haines 2021-06-02 17:22:58 +01:00
parent 239baef845
commit a1c9b63e61
5 changed files with 93 additions and 92 deletions

View File

@ -77,6 +77,7 @@ Style/IfUnlessModifier:
- 'lib/zip/entry.rb' - 'lib/zip/entry.rb'
- 'lib/zip/file.rb' - 'lib/zip/file.rb'
- 'lib/zip/filesystem.rb' - 'lib/zip/filesystem.rb'
- 'lib/zip/filesystem/dir.rb'
- 'lib/zip/pass_thru_decompressor.rb' - 'lib/zip/pass_thru_decompressor.rb'
- 'lib/zip/streamable_stream.rb' - 'lib/zip/streamable_stream.rb'

View File

@ -3,6 +3,7 @@
require 'zip' require 'zip'
require_relative 'filesystem/zip_file_name_mapper' require_relative 'filesystem/zip_file_name_mapper'
require_relative 'filesystem/directory_iterator' require_relative 'filesystem/directory_iterator'
require_relative 'filesystem/dir'
module Zip module Zip
# The ZipFileSystem API provides an API for accessing entries in # The ZipFileSystem API provides an API for accessing entries in
@ -40,13 +41,13 @@ module Zip
module FileSystem module FileSystem
def initialize # :nodoc: def initialize # :nodoc:
mapped_zip = ZipFileNameMapper.new(self) mapped_zip = ZipFileNameMapper.new(self)
@zip_fs_dir = ZipFsDir.new(mapped_zip) @zip_fs_dir = Dir.new(mapped_zip)
@zip_fs_file = ZipFsFile.new(mapped_zip) @zip_fs_file = ZipFsFile.new(mapped_zip)
@zip_fs_dir.file = @zip_fs_file @zip_fs_dir.file = @zip_fs_file
@zip_fs_file.dir = @zip_fs_dir @zip_fs_file.dir = @zip_fs_dir
end end
# Returns a ZipFsDir which is much like ruby's builtin Dir (class) # Returns a FileSystem::Dir which is much like ruby's builtin Dir (class)
# object, except it works on the Zip::File on which this method is # object, except it works on the Zip::File on which this method is
# invoked # invoked
def dir def dir
@ -428,93 +429,6 @@ module Zip
@mapped_zip.expand_path(path) @mapped_zip.expand_path(path)
end end
end end
# Instances of this class are normally accessed via the accessor
# ZipFile::dir. An instance of ZipFsDir behaves like ruby's
# builtin Dir (class) object, except it works on ZipFile entries.
#
# The individual methods are not documented due to their
# similarity with the methods in Dir
class ZipFsDir
def initialize(mapped_zip)
@mapped_zip = mapped_zip
end
attr_writer :file
def new(directory_name)
DirectoryIterator.new(entries(directory_name))
end
def open(directory_name)
dir_iter = new(directory_name)
if block_given?
begin
yield(dir_iter)
return nil
ensure
dir_iter.close
end
end
dir_iter
end
def pwd
@mapped_zip.pwd
end
alias getwd pwd
def chdir(directory_name)
unless @file.stat(directory_name).directory?
raise Errno::EINVAL, "Invalid argument - #{directory_name}"
end
@mapped_zip.pwd = @file.expand_path(directory_name)
end
def entries(directory_name)
entries = []
foreach(directory_name) { |e| entries << e }
entries
end
def glob(*args, &block)
@mapped_zip.glob(*args, &block)
end
def foreach(directory_name)
unless @file.stat(directory_name).directory?
raise Errno::ENOTDIR, directory_name
end
path = @file.expand_path(directory_name)
path << '/' unless path.end_with?('/')
path = Regexp.escape(path)
subdir_entry_regex = Regexp.new("^#{path}([^/]+)$")
@mapped_zip.each do |filename|
match = subdir_entry_regex.match(filename)
yield(match[1]) unless match.nil?
end
end
def delete(entry_name)
unless @file.stat(entry_name).directory?
raise Errno::EINVAL, "Invalid argument - #{entry_name}"
end
@mapped_zip.remove(entry_name)
end
alias rmdir delete
alias unlink delete
def mkdir(entry_name, permissions = 0o755)
@mapped_zip.mkdir(entry_name, permissions)
end
def chroot(*_args)
raise NotImplementedError, 'The chroot() function is not implemented'
end
end
end end
class File class File

86
lib/zip/filesystem/dir.rb Normal file
View File

@ -0,0 +1,86 @@
# frozen_string_literal: true
module Zip
module FileSystem
class Dir # :nodoc:all
def initialize(mapped_zip)
@mapped_zip = mapped_zip
end
attr_writer :file
def new(directory_name)
DirectoryIterator.new(entries(directory_name))
end
def open(directory_name)
dir_iter = new(directory_name)
if block_given?
begin
yield(dir_iter)
return nil
ensure
dir_iter.close
end
end
dir_iter
end
def pwd
@mapped_zip.pwd
end
alias getwd pwd
def chdir(directory_name)
unless @file.stat(directory_name).directory?
raise Errno::EINVAL, "Invalid argument - #{directory_name}"
end
@mapped_zip.pwd = @file.expand_path(directory_name)
end
def entries(directory_name)
entries = []
foreach(directory_name) { |e| entries << e }
entries
end
def glob(*args, &block)
@mapped_zip.glob(*args, &block)
end
def foreach(directory_name)
unless @file.stat(directory_name).directory?
raise Errno::ENOTDIR, directory_name
end
path = @file.expand_path(directory_name)
path << '/' unless path.end_with?('/')
path = Regexp.escape(path)
subdir_entry_regex = Regexp.new("^#{path}([^/]+)$")
@mapped_zip.each do |filename|
match = subdir_entry_regex.match(filename)
yield(match[1]) unless match.nil?
end
end
def delete(entry_name)
unless @file.stat(entry_name).directory?
raise Errno::EINVAL, "Invalid argument - #{entry_name}"
end
@mapped_zip.remove(entry_name)
end
alias rmdir delete
alias unlink delete
def mkdir(entry_name, permissions = 0o755)
@mapped_zip.mkdir(entry_name, permissions)
end
def chroot(*_args)
raise NotImplementedError, 'The chroot() function is not implemented'
end
end
end
end

View File

@ -2,8 +2,8 @@
module Zip module Zip
module FileSystem module FileSystem
# All access to Zip::File from ZipFsFile and ZipFsDir goes through a # All access to Zip::File from ZipFsFile and FileSystem::Dir goes through
# ZipFileNameMapper, which has one responsibility: ensure # a ZipFileNameMapper, which has one responsibility: ensure
class ZipFileNameMapper # :nodoc:all class ZipFileNameMapper # :nodoc:all
include Enumerable include Enumerable

View File

@ -3,7 +3,7 @@
require 'test_helper' require 'test_helper'
require 'zip/filesystem' require 'zip/filesystem'
class ZipFsDirectoryTest < MiniTest::Test class DirectoryTest < MiniTest::Test
TEST_ZIP = 'test/data/generated/zipWithDirs_copy.zip' TEST_ZIP = 'test/data/generated/zipWithDirs_copy.zip'
GLOB_TEST_ZIP = 'test/data/globTest.zip' GLOB_TEST_ZIP = 'test/data/globTest.zip'