Class: Omnizip::Zip::File

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/omnizip/zip/file.rb

Overview

Rubyzip-compatible File class Provides drop-in replacement for Zip::File from rubyzip

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_path, create: false, **options) ⇒ File

Initialize a ZIP file

Parameters:

  • file_path (String)

    Path to ZIP file

  • create (Boolean) (defaults to: false)

    Create file if it doesn't exist



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/omnizip/zip/file.rb', line 44

def initialize(file_path, create: false, **options)
  @name = file_path
  @entries = []
  @comment = ""
  @create = create
  @options = options
  @modified = false
  @reader = nil
  @writer = nil
  # Load existing archive if it exists
  if ::File.exist?(file_path) && !create
    load_archive
  elsif create
    # Will create on write/close
    @modified = true
  elsif !::File.exist?(file_path)
    raise Errno::ENOENT, "No such file or directory - #{file_path}"
  end
end

Instance Attribute Details

#commentObject

Get archive comment



175
176
177
# File 'lib/omnizip/zip/file.rb', line 175

def comment
  @comment
end

#entriesObject (readonly)

Returns the value of attribute entries.



12
13
14
# File 'lib/omnizip/zip/file.rb', line 12

def entries
  @entries
end

#nameObject (readonly)

Returns the value of attribute name.



12
13
14
# File 'lib/omnizip/zip/file.rb', line 12

def name
  @name
end

Class Method Details

.create(file_path) {|file| ... } ⇒ Object

Create a new archive from scratch

Parameters:

  • file_path (String)

    Path to ZIP file

Yields:

  • (file)

    Block to execute with the new archive



37
38
39
# File 'lib/omnizip/zip/file.rb', line 37

def self.create(file_path, &block)
  open(file_path, create: true, &block)
end

.open(file_path, create: false, **options) {|file| ... } ⇒ File

Open a ZIP archive

Parameters:

  • file_path (String)

    Path to ZIP file

  • create (Boolean) (defaults to: false)

    Create file if it doesn't exist

  • options (Hash)

    Additional options

Yields:

  • (file)

    Block to execute with the opened archive

Returns:

  • (File)

    The opened archive (if no block given)



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/omnizip/zip/file.rb', line 20

def self.open(file_path, create: false, **options)
  file = new(file_path, create: create, **options)

  if block_given?
    begin
      yield(file)
    ensure
      file.close
    end
  else
    file
  end
end

Instance Method Details

#add(entry_name, src_path = nil) { ... } ⇒ Object

Add a file to the archive

Parameters:

  • entry_name (String)

    Name in the archive

  • src_path (String, nil) (defaults to: nil)

    Source file path (optional if block given)

Yields:

  • Block that returns content to add



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/omnizip/zip/file.rb', line 68

def add(entry_name, src_path = nil)
  # Handle directory entries (ending with /)
  if entry_name.end_with?("/") && !src_path && !block_given?
    add_directory(entry_name)
  elsif block_given?
    data = yield
    add_data(entry_name, data)
  elsif src_path
    add_file_from_path(entry_name, src_path)
  else
    raise ArgumentError, "Either src_path or block must be provided"
  end

  @modified = true
  self
end

#closeObject

Close the archive



294
295
296
297
298
# File 'lib/omnizip/zip/file.rb', line 294

def close
  commit if @modified
  @reader = nil
  @writer = nil
end

#commitObject

Commit changes to disk



287
288
289
290
291
# File 'lib/omnizip/zip/file.rb', line 287

def commit
  write_archive if @modified
  @modified = false
  @reader = nil # Invalidate reader after writing
end

#count_matching(pattern) ⇒ Integer

Count files matching a pattern

Parameters:

  • pattern (String, Regexp, Array)

    Pattern(s) to match

Returns:

  • (Integer)

    Number of matches



260
261
262
# File 'lib/omnizip/zip/file.rb', line 260

def count_matching(pattern)
  Omnizip::Extraction.count_matching(self, pattern)
end

#each {|entry| ... } ⇒ Object

Iterate over all entries rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility

Yields:

  • (entry)

    Block to execute for each entry



117
118
119
# File 'lib/omnizip/zip/file.rb', line 117

def each(&block)
  entries.each(&block)
end

#extract(entry, dest_path, &on_exists_proc) ⇒ Object

Extract an entry to a destination path

Parameters:

  • entry (Entry, String)

    Entry object or name

  • dest_path (String)

    Destination file path

Raises:

  • (Errno::ENOENT)


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/omnizip/zip/file.rb', line 125

def extract(entry, dest_path, &on_exists_proc)
  entry = get_entry(entry) if entry.is_a?(String)
  raise Errno::ENOENT, "Entry not found: #{entry}" unless entry

  # Handle existing file
  if ::File.exist?(dest_path)
    if on_exists_proc
      action = yield(entry, dest_path)
      return if action == false
    else
      raise "Destination file already exists: #{dest_path}"
    end
  end

  extract_entry_to_path(entry, dest_path)
end

#extract_matching(pattern, dest, options = {}) ⇒ Array<String>

Extract files matching a pattern

Parameters:

  • pattern (String, Regexp, Array)

    Pattern(s) to match

  • dest (String)

    Destination directory

  • options (Hash) (defaults to: {})

    Extraction options

Options Hash (options):

  • :preserve_paths (Boolean)

    Keep directory structure

  • :flatten (Boolean)

    Extract all to destination root

  • :overwrite (Boolean)

    Overwrite existing files

Returns:

  • (Array<String>)

    Paths of extracted files



239
240
241
# File 'lib/omnizip/zip/file.rb', line 239

def extract_matching(pattern, dest, options = {})
  Omnizip::Extraction.extract_matching(self, pattern, dest, options)
end

#extract_matching_to_memory(pattern) ⇒ Hash<String, String>

Extract files matching a pattern to memory

Parameters:

  • pattern (String, Regexp, Array)

    Pattern(s) to match

Returns:

  • (Hash<String, String>)

    Hash of filename => content



246
247
248
# File 'lib/omnizip/zip/file.rb', line 246

def extract_matching_to_memory(pattern)
  Omnizip::Extraction.extract_to_memory_matching(self, pattern)
end

#extract_with_filter(filter, dest, options = {}) ⇒ Array<String>

Extract with a filter chain

Parameters:

Returns:

  • (Array<String>)

    Paths of extracted files



269
270
271
# File 'lib/omnizip/zip/file.rb', line 269

def extract_with_filter(filter, dest, options = {})
  Omnizip::Extraction.extract_with_filter(self, filter, dest, options)
end

#get_entry(entry_name) ⇒ Entry? Also known as: find_entry

Get entry by name

Parameters:

  • entry_name (String)

    Name of the entry

Returns:

  • (Entry, nil)

    The entry or nil if not found



88
89
90
# File 'lib/omnizip/zip/file.rb', line 88

def get_entry(entry_name)
  entries.find { |e| e.name == entry_name }
end

#get_input_stream(entry) {|stream| ... } ⇒ String Also known as: read

Get input stream for an entry rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding, Style/BlockDelimiters -- Ruby 3.0 compatibility

Parameters:

  • entry (Entry, String)

    Entry object or name

Yields:

  • (stream)

    Block to read from the stream

Returns:

  • (String)

    Entry content (if no block given)

Raises:

  • (Errno::ENOENT)


98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/omnizip/zip/file.rb', line 98

def get_input_stream(entry, &block)
  entry = get_entry(entry) if entry.is_a?(String)
  raise Errno::ENOENT, "Entry not found: #{entry}" unless entry

  content = read_entry_data(entry)

  if block
    require "stringio"
    StringIO.open(content, "rb", &block)
  else
    content
  end
end

#glob(pattern, &block) ⇒ Array<Entry>

Glob entries by pattern rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding, Style/BlockDelimiters -- Ruby 3.0 compatibility

Parameters:

  • pattern (String)

    Glob pattern

Returns:

  • (Array<Entry>)

    Matching entries



220
221
222
223
224
225
226
227
228
# File 'lib/omnizip/zip/file.rb', line 220

def glob(pattern, &block)
  matching = entries.select { |e| ::File.fnmatch(pattern, e.name) }

  if block
    matching.each(&block)
  else
    matching
  end
end

#include?(entry_name) ⇒ Boolean

Check if archive contains an entry

Parameters:

  • entry_name (String)

    Entry name to check

Returns:

  • (Boolean)

    True if entry exists



206
207
208
# File 'lib/omnizip/zip/file.rb', line 206

def include?(entry_name)
  !get_entry(entry_name).nil?
end

#list_matching(pattern) ⇒ Array<Entry>

List files matching a pattern

Parameters:

  • pattern (String, Regexp, Array)

    Pattern(s) to match

Returns:

  • (Array<Entry>)

    Matching entries



253
254
255
# File 'lib/omnizip/zip/file.rb', line 253

def list_matching(pattern)
  Omnizip::Extraction.list_matching(self, pattern)
end

#metadataOmnizip::Metadata::ArchiveMetadata

Get archive metadata

Returns:



275
276
277
# File 'lib/omnizip/zip/file.rb', line 275

def 
  @metadata ||= Omnizip::Metadata::ArchiveMetadata.new(self)
end

#modified!Object

Mark this archive as having unsaved changes. The next #commit or #close will write the archive to disk.



193
194
195
196
# File 'lib/omnizip/zip/file.rb', line 193

def modified!
  @modified = true
  self
end

#modified?Boolean

True if there are unsaved changes.

Returns:

  • (Boolean)


199
200
201
# File 'lib/omnizip/zip/file.rb', line 199

def modified?
  @modified
end

#namesArray<String>

Get names of all entries

Returns:

  • (Array<String>)

    Array of entry names



212
213
214
# File 'lib/omnizip/zip/file.rb', line 212

def names
  entries.map(&:name)
end

#remove(entry_name) ⇒ Object

Remove an entry from the archive

Parameters:

  • entry_name (String)

    Name of the entry to remove



144
145
146
147
148
149
150
# File 'lib/omnizip/zip/file.rb', line 144

def remove(entry_name)
  entry = get_entry(entry_name)
  @entries.delete(entry) if entry
  @modified = true
  @reader = nil
  self
end

#rename(entry_name, new_name) ⇒ Object

Rename an entry

Parameters:

  • entry_name (String)

    Current entry name

  • new_name (String)

    New entry name



155
156
157
158
159
160
161
162
# File 'lib/omnizip/zip/file.rb', line 155

def rename(entry_name, new_name)
  entry = get_entry(entry_name)
  return unless entry

  entry.header.filename = new_name
  @modified = true
  self
end

#replace(entry_name, src_path = nil, &block) ⇒ Object

Replace entry content rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility

Parameters:

  • entry_name (String)

    Entry name

  • src_path (String, nil) (defaults to: nil)

    Source file path



168
169
170
171
# File 'lib/omnizip/zip/file.rb', line 168

def replace(entry_name, src_path = nil, &block)
  remove(entry_name)
  add(entry_name, src_path, &block)
end

#save_metadataObject

Save metadata changes Marks the archive as modified so changes are written on close



281
282
283
284
# File 'lib/omnizip/zip/file.rb', line 281

def 
  @modified = true
  .reset_modified
end

#sizeObject Also known as: length

Get number of entries



186
187
188
# File 'lib/omnizip/zip/file.rb', line 186

def size
  entries.size
end