omnizip 0.4.10-arm-linux → 0.4.12-arm-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +13 -0
  3. data/README.adoc +101 -1284
  4. data/docs/compatibility.adoc +1 -2
  5. data/docs/lychee.toml +1 -7
  6. data/lib/omnizip/version.rb +1 -1
  7. data/lib/tasks/docs.rake +146 -0
  8. data/readme-docs/rar-archives.adoc +505 -0
  9. data/scripts/generate_rar_oracle_fixtures.rb +177 -0
  10. data/vendor/libomnizip_ffi.so +0 -0
  11. metadata +4 -74
  12. data/TODO.refactor/00-overview.md +0 -67
  13. data/TODO.refactor/01-registry-base-class.md +0 -81
  14. data/TODO.refactor/02-error-hierarchy.md +0 -57
  15. data/TODO.refactor/03-autoload-entry-point.md +0 -69
  16. data/TODO.refactor/04-filter-base-consolidation.md +0 -49
  17. data/TODO.refactor/05-send-private-methods.md +0 -64
  18. data/TODO.refactor/06-instance-variable-access.md +0 -69
  19. data/TODO.refactor/07-respond-to-replacement.md +0 -237
  20. data/TODO.refactor/08-spec-doubles.md +0 -27
  21. data/TODO.refactor/09-cli-shared-module.md +0 -35
  22. data/TODO.refactor/10-format-detector-ocp.md +0 -34
  23. data/TODO.refactor/11-convenience-decoupling.md +0 -38
  24. data/TODO.refactor/12-thread-safety.md +0 -8
  25. data/TODO.refactor/13-lutaml-model-migration.md +0 -158
  26. data/TODO.refactor/14-add-missing-specs.md +0 -25
  27. data/docs/.github/workflows/docs.yml +0 -142
  28. data/docs/.gitignore +0 -21
  29. data/docs/Gemfile +0 -13
  30. data/docs/README.md +0 -101
  31. data/docs/_config.yml +0 -112
  32. data/docs/comparison/feature-matrix.adoc +0 -694
  33. data/docs/comparison/index.adoc +0 -113
  34. data/docs/comparison/vs-7zip.adoc +0 -309
  35. data/docs/comparison/vs-peazip.adoc +0 -77
  36. data/docs/comparison/vs-rubyzip.adoc +0 -342
  37. data/docs/comparison/vs-winrar.adoc +0 -100
  38. data/docs/concepts/index.adoc +0 -129
  39. data/docs/developer/architecture.adoc +0 -256
  40. data/docs/developer/contributing.adoc +0 -158
  41. data/docs/developer/index.adoc +0 -25
  42. data/docs/developer/testing.adoc +0 -212
  43. data/docs/getting-started/basic-usage.adoc +0 -263
  44. data/docs/getting-started/index.adoc +0 -42
  45. data/docs/getting-started/installation.adoc +0 -138
  46. data/docs/getting-started/quick-start.adoc +0 -183
  47. data/docs/getting-started/your-first-archive.adoc +0 -219
  48. data/docs/guides/advanced-features/encryption.adoc +0 -277
  49. data/docs/guides/advanced-features/index.adoc +0 -59
  50. data/docs/guides/advanced-features/parallel-processing.adoc +0 -144
  51. data/docs/guides/advanced-features/progress-tracking.adoc +0 -124
  52. data/docs/guides/advanced-features/streaming.adoc +0 -142
  53. data/docs/guides/archive-formats/gzip-format.adoc +0 -105
  54. data/docs/guides/archive-formats/index.adoc +0 -160
  55. data/docs/guides/archive-formats/ole-format.adoc +0 -151
  56. data/docs/guides/archive-formats/rar-format.adoc +0 -104
  57. data/docs/guides/archive-formats/rar5.adoc +0 -521
  58. data/docs/guides/archive-formats/rpm-format.adoc +0 -108
  59. data/docs/guides/archive-formats/seven-zip-format.adoc +0 -35
  60. data/docs/guides/archive-formats/tar-format.adoc +0 -106
  61. data/docs/guides/archive-formats/xz-format.adoc +0 -118
  62. data/docs/guides/archive-formats/zip-format.adoc +0 -35
  63. data/docs/guides/compression-algorithms/bzip2.adoc +0 -114
  64. data/docs/guides/compression-algorithms/deflate.adoc +0 -313
  65. data/docs/guides/compression-algorithms/index.adoc +0 -190
  66. data/docs/guides/compression-algorithms/lzma.adoc +0 -394
  67. data/docs/guides/compression-algorithms/lzma2.adoc +0 -244
  68. data/docs/guides/compression-algorithms/ppmd.adoc +0 -313
  69. data/docs/guides/compression-algorithms/zstandard.adoc +0 -296
  70. data/docs/guides/creating-archives.adoc +0 -348
  71. data/docs/guides/extracting-archives.adoc +0 -53
  72. data/docs/guides/format-conversion.adoc +0 -64
  73. data/docs/guides/index.adoc +0 -49
  74. data/docs/guides/migration-rubyzip.adoc +0 -217
  75. data/docs/guides/parity-archives.adoc +0 -605
  76. data/docs/guides/performance-tuning.adoc +0 -88
  77. data/docs/index.adoc +0 -228
  78. data/docs/reference/api/overview.adoc +0 -187
  79. data/docs/reference/cli/compress-command.adoc +0 -114
  80. data/docs/reference/cli/overview.adoc +0 -140
  81. data/docs/reference/index.adoc +0 -26
  82. data/docs/resources/faq.adoc +0 -185
  83. data/docs/resources/quick-reference.adoc +0 -222
  84. data/docs/troubleshooting/index.adoc +0 -207
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Regenerates the RAR oracle fixtures under spec/fixtures/rar/oracle/.
4
+ #
5
+ # The specs that used to shell out to `unrar` now assert against these
6
+ # committed files, so CI never needs the rar/unrar oracle. When the
7
+ # writers legitimately change their output, run:
8
+ #
9
+ # bundle exec ruby scripts/generate_rar_oracle_fixtures.rb
10
+ #
11
+ # and commit the refreshed fixtures. The script FAILS unless the local
12
+ # `unrar` oracle validates every generated archive, and unless each
13
+ # writer is byte-deterministic across two runs (the specs compare fresh
14
+ # writer output against these fixtures byte-for-byte).
15
+
16
+ require "digest"
17
+ require "fileutils"
18
+ require "tmpdir"
19
+
20
+ ROOT = File.expand_path("..", __dir__)
21
+ DEST = File.join(ROOT, "spec/fixtures/rar/oracle")
22
+ UNRAR = "unrar"
23
+ # RAR5 embeds mtime as epoch seconds; pin it so fixtures are reproducible
24
+ FIXED_TIME = Time.at(1_700_000_000)
25
+
26
+ def sh!(*cmd)
27
+ system(*cmd) or abort("FAILED: #{cmd.join(' ')}")
28
+ end
29
+
30
+ def oracle_t(path)
31
+ sh!(UNRAR, "t", "-idq", path)
32
+ end
33
+
34
+ def oracle_listing(path)
35
+ out = `#{UNRAR} l #{path} 2>&1`
36
+ abort("unrar l failed for #{path}:\n#{out}") if out.include?("ERROR") || $?.success? == false
37
+ out
38
+ end
39
+
40
+ def build_rar5_single(dir)
41
+ input = File.join(dir, "in.txt")
42
+ File.binwrite(input, "Test content for unrar")
43
+ archive = File.join(dir, "rar5_single.rar")
44
+ writer = Omnizip::Formats::Rar::Rar5::Writer.new(archive)
45
+ writer.add_file(input, "test.txt")
46
+ writer.write
47
+ archive
48
+ end
49
+
50
+ def build_rar4_store_tree(dir)
51
+ big = File.join(dir, "big.txt")
52
+ File.binwrite(big, "omnizip RAR4 interop fixture. " * 800)
53
+ tree = File.join(dir, "tree")
54
+ FileUtils.mkdir_p(File.join(tree, "sub"))
55
+ File.binwrite(File.join(tree, "README.md"), "# tree\n")
56
+ File.binwrite(File.join(tree, "sub", "main.rb"), "puts 'hi'\n")
57
+ File.binwrite(File.join(tree, "empty.bin"), "")
58
+ archive = File.join(dir, "rar4_store_tree.rar")
59
+ writer = Omnizip::Formats::Rar::Writer.new(archive, compression: :store)
60
+ writer.add_file(big)
61
+ writer.add_directory(tree)
62
+ writer.write
63
+ archive
64
+ end
65
+
66
+ def build_rar5_multivolume(dir)
67
+ %w[compat0.txt compat1.txt].each_with_index do |name, i|
68
+ File.binwrite(File.join(dir, name), "Compatible content #{i}\n" * 3000)
69
+ end
70
+ archive = File.join(dir, "rar5_mv.rar")
71
+ writer = Omnizip::Formats::Rar::Rar5::Writer.new(
72
+ archive, multi_volume: true, volume_size: 65_536, compression: :store
73
+ )
74
+ writer.add_file(File.join(dir, "compat0.txt"))
75
+ writer.add_file(File.join(dir, "compat1.txt"))
76
+ volumes = writer.write
77
+ raise "expected split volumes, got #{volumes.size}" unless volumes.size > 1
78
+
79
+ volumes
80
+ end
81
+
82
+ def build_rar5_large(dir)
83
+ archive = File.join(dir, "rar5_large.rar")
84
+ writer = Omnizip::Formats::Rar5::Writer.new
85
+ io = StringIO.new
86
+ # RAR5 stores mtime as epoch seconds; the fixed constant keeps the bytes
87
+ # reproducible across machines and timezones.
88
+ writer.write_archive(io, [{ name: "large.txt", data: "X" * 10_000, time: FIXED_TIME }])
89
+ File.binwrite(archive, io.string)
90
+ archive
91
+ end
92
+
93
+ def build_rar5_store(dir)
94
+ input = File.join(dir, "test.txt")
95
+ File.write(input, "Test content for unrar")
96
+ archive = File.join(dir, "rar5_store_omnizip.rar")
97
+ writer = Omnizip::Formats::Rar::Rar5::Writer.new(archive, compression: :store)
98
+ writer.add_file(input, "test.txt")
99
+ writer.write
100
+ archive
101
+ end
102
+
103
+ def build_rar5_lzss_fallback(dir)
104
+ input = File.join(dir, "test.txt")
105
+ File.write(input, "Test content for unrar")
106
+ archive = File.join(dir, "rar5_lzss_fallback.rar")
107
+ writer = Omnizip::Formats::Rar::Rar5::Writer.new(archive,
108
+ compression: :lzss, level: 3)
109
+ writer.add_file(input, "test.txt")
110
+ writer.write
111
+ archive
112
+ end
113
+
114
+ def build_rar5_multi_files(dir)
115
+ %w[file1.txt file2.txt].each_with_index do |name, i|
116
+ File.write(File.join(dir, name), "Content #{i + 1}\n" * 10)
117
+ end
118
+ archive = File.join(dir, "rar5_multi_files.rar")
119
+ writer = Omnizip::Formats::Rar::Rar5::Writer.new(archive,
120
+ compression: :lzma, level: 3)
121
+ writer.add_file(File.join(dir, "file1.txt"), "file1.txt")
122
+ writer.add_file(File.join(dir, "file2.txt"), "file2.txt")
123
+ writer.write
124
+ archive
125
+ end
126
+
127
+ builders = {
128
+ "rar5_single" => method(:build_rar5_single),
129
+ "rar4_store_tree" => method(:build_rar4_store_tree),
130
+ "rar5_multivolume" => method(:build_rar5_multivolume),
131
+ "rar5_large" => method(:build_rar5_large),
132
+ "rar5_store_omnizip" => method(:build_rar5_store),
133
+ "rar5_lzss_fallback" => method(:build_rar5_lzss_fallback),
134
+ "rar5_multi_files" => method(:build_rar5_multi_files),
135
+ }
136
+
137
+ abort("unrar oracle not available — these fixtures can only be regenerated where unrar exists") unless system("which #{UNRAR} > /dev/null 2>&1")
138
+ require "omnizip"
139
+
140
+ FileUtils.mkdir_p(DEST)
141
+ manifest = ["# RAR oracle fixtures — regenerated by scripts/generate_rar_oracle_fixtures.rb",
142
+ "# (unrar validated each archive at generation time; specs assert against these bytes)",
143
+ "generated: #{Time.now.utc.iso8601}",
144
+ "unrar_version: (derived from the first frozen listing's banner)",
145
+ "fixtures:"]
146
+
147
+ builders.each do |name, builder|
148
+ puts "== #{name}"
149
+ Dir.mktmpdir("rar_oracle") do |dir|
150
+ built1 = builder.call(dir)
151
+ h1 = Array(built1).map { |p| Digest::SHA256.file(p).hexdigest }
152
+ h2 = Dir.mktmpdir("rar_oracle2") do |dir2|
153
+ Array(builder.call(dir2)).map { |p| Digest::SHA256.file(p).hexdigest }
154
+ end
155
+ abort("#{name}: writer not byte-deterministic across runs") unless h1 == h2
156
+
157
+ first = Array(built1).first
158
+ oracle_t(first)
159
+ listing = oracle_listing(first)
160
+ digest_pairs = Array(built1).zip(h1).map do |path, h|
161
+ base = name == "rar5_multivolume" ? File.basename(path) : "#{name}.rar"
162
+ dest = File.join(DEST, base)
163
+ FileUtils.cp(path, dest)
164
+ manifest << " - file: #{base}"
165
+ manifest << " sha256: #{h}"
166
+ base
167
+ end
168
+ listing_name = "#{name}.unrar-l.txt"
169
+ File.write(File.join(DEST, listing_name), listing)
170
+ manifest << " - file: #{listing_name}"
171
+ manifest << " oracle_listing_of: #{digest_pairs.first}"
172
+ puts " frozen: #{digest_pairs.join(', ')}"
173
+ end
174
+ end
175
+
176
+ File.write(File.join(DEST, "MANIFEST.yml"), "#{manifest.join("\n")}\n")
177
+ puts "done → #{DEST}"
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnizip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.10
4
+ version: 0.4.12
5
5
  platform: arm-linux
6
6
  authors:
7
7
  - Ribose Inc.
@@ -135,21 +135,6 @@ files:
135
135
  - LICENSE
136
136
  - README.adoc
137
137
  - Rakefile
138
- - TODO.refactor/00-overview.md
139
- - TODO.refactor/01-registry-base-class.md
140
- - TODO.refactor/02-error-hierarchy.md
141
- - TODO.refactor/03-autoload-entry-point.md
142
- - TODO.refactor/04-filter-base-consolidation.md
143
- - TODO.refactor/05-send-private-methods.md
144
- - TODO.refactor/06-instance-variable-access.md
145
- - TODO.refactor/07-respond-to-replacement.md
146
- - TODO.refactor/08-spec-doubles.md
147
- - TODO.refactor/09-cli-shared-module.md
148
- - TODO.refactor/10-format-detector-ocp.md
149
- - TODO.refactor/11-convenience-decoupling.md
150
- - TODO.refactor/12-thread-safety.md
151
- - TODO.refactor/13-lutaml-model-migration.md
152
- - TODO.refactor/14-add-missing-specs.md
153
138
  - benchmark/README.md
154
139
  - benchmark/benchmark_suite.rb
155
140
  - benchmark/compression_bench.rb
@@ -162,71 +147,13 @@ files:
162
147
  - benchmark/test_data.rb
163
148
  - config/formats/rar3_spec.yml
164
149
  - config/formats/rar5_spec.yml
165
- - docs/.github/workflows/docs.yml
166
- - docs/.gitignore
167
150
  - docs/.lychee.toml
168
- - docs/Gemfile
169
151
  - docs/RAR_WRITE_SUPPORT.md
170
- - docs/README.md
171
- - docs/_config.yml
172
152
  - docs/assets/logo.svg
173
153
  - docs/assets/omnizip-logo.pdf
174
- - docs/comparison/feature-matrix.adoc
175
- - docs/comparison/index.adoc
176
- - docs/comparison/vs-7zip.adoc
177
- - docs/comparison/vs-peazip.adoc
178
- - docs/comparison/vs-rubyzip.adoc
179
- - docs/comparison/vs-winrar.adoc
180
154
  - docs/compatibility.adoc
181
- - docs/concepts/index.adoc
182
- - docs/developer/architecture.adoc
183
- - docs/developer/contributing.adoc
184
- - docs/developer/index.adoc
185
- - docs/developer/testing.adoc
186
- - docs/getting-started/basic-usage.adoc
187
- - docs/getting-started/index.adoc
188
- - docs/getting-started/installation.adoc
189
- - docs/getting-started/quick-start.adoc
190
- - docs/getting-started/your-first-archive.adoc
191
- - docs/guides/advanced-features/encryption.adoc
192
- - docs/guides/advanced-features/index.adoc
193
- - docs/guides/advanced-features/parallel-processing.adoc
194
- - docs/guides/advanced-features/progress-tracking.adoc
195
- - docs/guides/advanced-features/streaming.adoc
196
- - docs/guides/archive-formats/gzip-format.adoc
197
- - docs/guides/archive-formats/index.adoc
198
- - docs/guides/archive-formats/ole-format.adoc
199
- - docs/guides/archive-formats/rar-format.adoc
200
- - docs/guides/archive-formats/rar5.adoc
201
- - docs/guides/archive-formats/rpm-format.adoc
202
- - docs/guides/archive-formats/seven-zip-format.adoc
203
- - docs/guides/archive-formats/tar-format.adoc
204
- - docs/guides/archive-formats/xz-format.adoc
205
- - docs/guides/archive-formats/zip-format.adoc
206
- - docs/guides/compression-algorithms/bzip2.adoc
207
- - docs/guides/compression-algorithms/deflate.adoc
208
- - docs/guides/compression-algorithms/index.adoc
209
- - docs/guides/compression-algorithms/lzma.adoc
210
- - docs/guides/compression-algorithms/lzma2.adoc
211
- - docs/guides/compression-algorithms/ppmd.adoc
212
- - docs/guides/compression-algorithms/zstandard.adoc
213
- - docs/guides/creating-archives.adoc
214
- - docs/guides/extracting-archives.adoc
215
- - docs/guides/format-conversion.adoc
216
- - docs/guides/index.adoc
217
- - docs/guides/migration-rubyzip.adoc
218
- - docs/guides/parity-archives.adoc
219
- - docs/guides/performance-tuning.adoc
220
- - docs/index.adoc
221
155
  - docs/lychee.toml
222
- - docs/reference/api/overview.adoc
223
- - docs/reference/cli/compress-command.adoc
224
- - docs/reference/cli/overview.adoc
225
- - docs/reference/index.adoc
226
- - docs/resources/faq.adoc
227
- - docs/resources/quick-reference.adoc
228
156
  - docs/rust-backend.md
229
- - docs/troubleshooting/index.adoc
230
157
  - docs/xar_format.md
231
158
  - examples/api_comparison.rb
232
159
  - examples/deflate64_example.rb
@@ -739,6 +666,7 @@ files:
739
666
  - lib/omnizip/zip/file.rb
740
667
  - lib/omnizip/zip/input_stream.rb
741
668
  - lib/omnizip/zip/output_stream.rb
669
+ - lib/tasks/docs.rake
742
670
  - lib/tasks/msi_test_files.rake
743
671
  - lib/tasks/platform_gems.rake
744
672
  - lib/tasks/rust_backend.rake
@@ -755,6 +683,8 @@ files:
755
683
  - readme-docs/par2-archives.adoc
756
684
  - readme-docs/performance-profiler.adoc
757
685
  - readme-docs/preprocessing-filters.adoc
686
+ - readme-docs/rar-archives.adoc
687
+ - scripts/generate_rar_oracle_fixtures.rb
758
688
  - vendor/libomnizip_ffi.so
759
689
  - xz-file-format-1.2.1.txt
760
690
  homepage: https://github.com/omnizip/omnizip
@@ -1,67 +0,0 @@
1
- # 00 — Refactor Plan Overview
2
-
3
- Date: 2026-07-20 (updated 2026-07-21)
4
- Scope: `lib/` and `spec/` of the omnizip gem.
5
-
6
- ## Goals
7
-
8
- Apply OCP, DRY, MECE, model-driven design, open/closed principle, and high
9
- performance to the omnizip codebase. Eliminate the anti-patterns declared
10
- as absolute rules:
11
-
12
- - `require_relative` (and internal `require`) inside `lib/`
13
- - `.send` against private methods (breaks encapsulation)
14
- - `instance_variable_set` / `instance_variable_get` on other objects
15
- - `respond_to?` as a substitute for proper typing
16
- - `double()` in specs (use real instances or `Struct`)
17
- - Hand-rolled `to_h` / `from_h` / `to_json` on model classes (use `lutaml-model`)
18
-
19
- ## Track status
20
-
21
- | # | File | Priority | Status |
22
- |---|---|---|---|
23
- | 01 | `01-registry-base-class.md` | high | **DONE** |
24
- | 02 | `02-error-hierarchy.md` | high | **DONE** |
25
- | 03 | `03-autoload-entry-point.md` | high | **DONE** |
26
- | 04 | `04-filter-base-consolidation.md` | medium | **DONE** |
27
- | 05 | `05-send-private-methods.md` | high | **DONE** |
28
- | 06 | `06-instance-variable-access.md` | high | **DONE** |
29
- | 07 | `07-respond-to-replacement.md` | medium | **DONE** — 11 type checks converted; 45 feature-detection sites annotated `# allowed:` and enforced by a spec; 1 deferred type check in `algorithms/lzma.rb` pending `LzmaOptions` unification |
30
- | 08 | `08-spec-doubles.md` | low | **DONE** |
31
- | 09 | `09-cli-shared-module.md` | low | **DONE** |
32
- | 10 | `10-format-detector-ocp.md` | medium | **DONE** |
33
- | 11 | `11-convenience-decoupling.md` | medium | **DONE** (ArchiveHandler dispatcher + ZipHandler + TarHandler) |
34
- | 12 | `12-thread-safety.md` | covered by 01 | n/a |
35
- | 13 | `13-lutaml-model-migration.md` | medium | **DONE** — six models migrated; follow-ups 2+3 landed in 0.3.28; 1 and 4 decided (deferred rename / migration declined with reasons) |
36
- | 14 | `14-add-missing-specs.md` | high | **DONE** |
37
-
38
- ## Anti-pattern counts (lib/)
39
-
40
- | Pattern | Before | After |
41
- |---|---|---|
42
- | `require_relative` / `require "omnizip/..."` | ~290 | **0** |
43
- | `.send` on private methods | 17 | **0** |
44
- | `instance_variable_set`/`get` | 54 | **0** |
45
- | `double()` in specs | 1 | **0** |
46
- | `respond_to?` | 60 at track 07 start (111 originally) | 49 — 46 annotated `# allowed:` (45 feature detection + 1 deferred type check) plus 3 doc comments |
47
- | Hand-rolled model `to_h` | 26 | 24 (2 migrated to lutaml-model) |
48
-
49
- ## Architecture summary
50
-
51
- - **`Omnizip::Registry`** — thread-safe base class with lazy-load triggers.
52
- - **`Omnizip::IO::Source` / `Sink`** — polymorphic adapters for
53
- String/Path/IO/StringIO/Tempfile.
54
- - **`Omnizip::ArchiveHandler`** — dispatcher decoupling Convenience from
55
- ZIP. New formats plug in by registering a handler.
56
- - **`Omnizip::Platform`** — predicates for symlink/hardlink/NTFS support.
57
- - **Error hierarchy** consolidated with backward-compat aliases.
58
- - **`Filter` / `FilterBase`** unified.
59
-
60
- ## Test coverage
61
-
62
- 3643 examples, 0 failures. New specs:
63
-
64
- - `spec/omnizip/registry_spec.rb`
65
- - `spec/omnizip/error_spec.rb`
66
- - `spec/omnizip/io/source_spec.rb`
67
- - `spec/omnizip/convenience_tar_spec.rb`
@@ -1,81 +0,0 @@
1
- # 01 — Registry base class
2
-
3
- Priority: **high**.
4
- Status: TODO.
5
-
6
- ## Problem
7
-
8
- Five registry classes duplicate an identical pattern:
9
-
10
- - `Omnizip::AlgorithmRegistry` (`lib/omnizip/algorithm_registry.rb`)
11
- - `Omnizip::FormatRegistry` (`lib/omnizip/format_registry.rb`)
12
- - `Omnizip::FilterRegistry` (`lib/omnizip/filter_registry.rb`)
13
- - `Omnizip::ChecksumRegistry` (`lib/omnizip/checksum_registry.rb`)
14
- - `Omnizip::OptimizationRegistry` (`lib/omnizip/optimization_registry.rb`)
15
- - `Omnizip::Password::EncryptionRegistry` (`lib/omnizip/password/encryption_registry.rb`)
16
- - `Omnizip::Converter::ConversionRegistry` (`lib/omnizip/converter/conversion_registry.rb`)
17
-
18
- Each implements a slightly different version of `register / get /
19
- registered? / available / reset` with different naming, error classes, and
20
- key-normalization rules.
21
-
22
- Inconsistencies:
23
-
24
- | Registry | Storage | Reset | Not-found error |
25
- |---|---|---|---|
26
- | AlgorithmRegistry | `@algorithms ||= {}` | `reset!` | `UnknownAlgorithmError` |
27
- | FormatRegistry | `@registry ||= {}` | (none) | returns nil |
28
- | FilterRegistry | `@filters = {}` | `reset!` | `UnknownFilterError` |
29
- | ChecksumRegistry | `@checksums = {}` | `clear` | `UnknownAlgorithmError` |
30
- | OptimizationRegistry | `@strategies ||= {}` | `clear!` | `OptimizationNotFound` |
31
- | EncryptionRegistry | `@strategies = {}` | `reset` | `ArgumentError` |
32
- | ConversionRegistry | array of classes | `reset` | returns nil |
33
-
34
- None are thread-safe.
35
-
36
- ## Plan
37
-
38
- 1. Create `lib/omnizip/registry.rb` defining `Omnizip::Registry` — a
39
- thread-safe generic registry with:
40
- - `register(name, value, **opts)` (overrides per subclass)
41
- - `get(name)` → raises `not_found_error` if missing
42
- - `registered?(name)` → bool
43
- - `available` / `all` → keys
44
- - `reset!` → clears store (canonical name)
45
- - `Mutex`-synchronized mutations
46
- - Configurable `not_found_error` class and `normalize_key` hook.
47
-
48
- 2. Migrate each registry to inherit from `Omnizip::Registry`. Preserve the
49
- existing public class names and method names so call sites still work.
50
- For backward compatibility, alias `clear`/`reset` to `reset!`,
51
- `supported_formats`/`strategies` to `available` where applicable.
52
-
53
- 3. FormatRegistry keeps `normalize_extension` as its `normalize_key` hook.
54
-
55
- 4. FilterRegistry keeps its `formats:` registry metadata and
56
- `get_for_format` / `supports_format?` / `filters_for_format` extensions
57
- on top of the base.
58
-
59
- 5. ConversionRegistry is array-based and is the only outlier; leave as-is
60
- or convert to a key based on `[source, target]` tuple. Pragmatically:
61
- leave as-is, document why.
62
-
63
- ## Acceptance
64
-
65
- - All existing registry specs pass unchanged.
66
- - `bundle exec rspec` failure count is ≤ baseline (2).
67
- - No new rubocop offenses.
68
- - `lib/omnizip/registry_spec.rb` covers register/get/registered?/reset! and
69
- thread-safety smoke test.
70
-
71
- ## Files to touch
72
-
73
- - create `lib/omnizip/registry.rb`
74
- - create `spec/omnizip/registry_spec.rb`
75
- - modify `lib/omnizip/algorithm_registry.rb`
76
- - modify `lib/omnizip/format_registry.rb`
77
- - modify `lib/omnizip/filter_registry.rb`
78
- - modify `lib/omnizip/checksum_registry.rb`
79
- - modify `lib/omnizip/optimization_registry.rb`
80
- - modify `lib/omnizip/password/encryption_registry.rb`
81
- - modify `lib/omnizip.rb` to autoload `:Registry`
@@ -1,57 +0,0 @@
1
- # 02 — Error hierarchy consolidation
2
-
3
- Priority: **high**.
4
- Status: TODO.
5
-
6
- ## Problems
7
-
8
- 1. `AlgorithmNotFoundError` and `UnknownAlgorithmError` both exist in
9
- `lib/omnizip/error.rb` and are used interchangeably. The two registries
10
- that raise on miss (`AlgorithmRegistry`, `ChecksumRegistry`) both raise
11
- `UnknownAlgorithmError`.
12
- 2. `OptimizationNotFound` lacks the `Error` suffix convention.
13
- 3. `Omnizip::IOError` shadows Ruby's built-in `IOError` — confusing for
14
- users who `rescue IOError`.
15
- 4. `UnknownFilterError` is defined at the bottom of
16
- `lib/omnizip/filter_registry.rb` instead of `lib/omnizip/error.rb`.
17
- 5. `EncryptionRegistry` raises vanilla `ArgumentError` instead of a
18
- domain-specific error.
19
- 6. `ConversionRegistry` returns nil instead of raising.
20
-
21
- ## Plan
22
-
23
- 1. In `lib/omnizip/error.rb`:
24
- - Keep `AlgorithmNotFoundError` as canonical; make
25
- `UnknownAlgorithmError` an alias (subclass) for backward compatibility.
26
- Document the alias.
27
- - Rename `OptimizationNotFound` → `OptimizationNotFoundError`. Keep the
28
- old name as an alias for backward compatibility.
29
- - Rename `IOError` → `IOOperationError`. Keep `IOError` as an alias for
30
- backward compatibility (or deprecate it).
31
- - Add `UnknownFilterError` to `error.rb` (and remove from
32
- `filter_registry.rb`).
33
- - Add `UnknownEncryptionStrategyError < Error`.
34
- - Add `ConversionNotSupportedError < Error`.
35
-
36
- 2. Update all internal `raise` sites to use the canonical names.
37
-
38
- 3. Update `FormatRegistry`, `ConversionRegistry` to raise their new errors
39
- instead of returning nil where the caller cannot reasonably handle nil.
40
-
41
- 4. Update `lib/omnizip.rb` autoload entries to include the new error names.
42
-
43
- ## Acceptance
44
-
45
- - All existing specs pass.
46
- - No new rubocop offenses.
47
- - `lib/omnizip/error_spec.rb` confirms hierarchy and aliases.
48
-
49
- ## Files
50
-
51
- - modify `lib/omnizip/error.rb`
52
- - modify `lib/omnizip/filter_registry.rb` (remove inline error)
53
- - modify `lib/omnizip/optimization_registry.rb` (raise renamed error)
54
- - modify `lib/omnizip/password/encryption_registry.rb` (raise new error)
55
- - modify `lib/omnizip/converter/conversion_registry.rb` (raise on miss)
56
- - modify `lib/omnizip.rb` autoload list
57
- - create `spec/omnizip/error_spec.rb`
@@ -1,69 +0,0 @@
1
- # 03 — Autoload entry point
2
-
3
- Priority: **high**.
4
- Status: TODO.
5
-
6
- ## Problem
7
-
8
- `lib/omnizip.rb` lines 99–139 contain 31 `require_relative` calls for
9
- algorithms, filters, checksums, and formats. Per the global rule,
10
- `require_relative` is forbidden inside `lib/`. The justification given is
11
- "these classes self-register at load time" — but self-registration only
12
- needs to happen *before first lookup*, not at gem boot.
13
-
14
- Additional inconsistency: line 179 uses `require "omnizip/convenience"`
15
- while similar modules are autoloaded.
16
-
17
- ## Plan
18
-
19
- 1. Convert each `require_relative` line in `lib/omnizip.rb` to an autoload
20
- declaration in the appropriate namespace:
21
-
22
- ```ruby
23
- module Omnizip
24
- module Algorithms
25
- autoload :LZMA, "omnizip/algorithms/lzma"
26
- autoload :LZMA2, "omnizip/algorithms/lzma2"
27
- # ...
28
- end
29
- end
30
- ```
31
-
32
- 2. For self-registering classes, keep the registration call at the bottom
33
- of each implementation file (`AlgorithmRegistry.register(:lzma, LZMA)`).
34
- Autoload will load the file on first reference, which triggers
35
- registration. Tests that pre-populate the registry should reference the
36
- constant first (e.g., `Omnizip::Algorithms::LZMA`).
37
-
38
- 3. For files that are currently eager-required because *nothing else*
39
- references them (only the registration matters), add an explicit
40
- autoload entry in the right namespace *and* arrange for the constant to
41
- be referenced on first registry miss. Concretely: change registries to
42
- trigger autoload by referencing the constant rather than calling
43
- `register` from the file body. See `08-registry-lazy-trigger.md` if a
44
- fallback is needed.
45
-
46
- 4. Replace the trailing `require "omnizip/convenience"` with an autoload
47
- entry — `autoload :Convenience, "omnizip/convenience"` — and reference
48
- it lazily where used (or eager-load at the very end of `lib/omnizip.rb`
49
- via `require "omnizip/convenience"` ONLY if Convenience must extend
50
- Omnizip at boot; document why).
51
-
52
- 5. Run specs. If any spec fails because a class never autoloaded, fix by
53
- adding a `require` at the top of the spec file (specs are NOT subject
54
- to the no-`require_relative` rule for library code; they ARE subject to
55
- it for sibling spec files but not for library files).
56
-
57
- ## Acceptance
58
-
59
- - `grep -rn "require_relative" lib/` returns zero matches.
60
- - `grep -rn '^require "omnizip/' lib/` is limited to the convenience
61
- fallback (documented) and any in-file registration triggers.
62
- - All specs pass.
63
-
64
- ## Files
65
-
66
- - modify `lib/omnizip.rb` (replace lines 99–139 and line 179)
67
- - ensure each `lib/omnizip/algorithms/*.rb`, `lib/omnizip/filters/*.rb`,
68
- `lib/omnizip/checksums/*.rb`, `lib/omnizip/formats/*.rb` ends with its
69
- own registration call (most already do).
@@ -1,49 +0,0 @@
1
- # 04 — Filter base consolidation
2
-
3
- Priority: **medium**.
4
- Status: TODO.
5
-
6
- ## Problem
7
-
8
- Two parallel base classes exist:
9
-
10
- - `Omnizip::Filter` (`lib/omnizip/filter.rb`) — has `architecture` and
11
- `name` attrs plus `id_for_format(format)`. Used by `BCJ` and `Delta`.
12
- - `Omnizip::Filters::FilterBase` (`lib/omnizip/filters/filter_base.rb`) —
13
- minimal `encode`/`decode`/`.metadata` stub. Used by `BcjX86`, `BcjArm`,
14
- `BcjArm64`, `BcjIa64`, `BcjPpc`, `BcjSparc`, `Bcj2`.
15
-
16
- They share identical `encode(data, position=0)` / `decode(data,
17
- position=0)` / `.metadata` stubs. `FilterBase` is a subset of `Filter`.
18
-
19
- ## Plan
20
-
21
- 1. Keep `Filter` as the canonical base, located at
22
- `lib/omnizip/filters/base.rb`. Make `architecture` optional (defaults
23
- to nil).
24
- 2. Make `Omnizip::Filters::FilterBase` an alias / subclass of the unified
25
- base for backward compatibility.
26
- 3. Migrate subclasses of `FilterBase` to inherit from the unified base.
27
- 4. Delete the body of `lib/omnizip/filters/filter_base.rb`, leaving it as
28
- a backward-compat alias:
29
- ```ruby
30
- require "omnizip/filters/base"
31
- module Omnizip::Filters
32
- FilterBase = Filter # backward-compat alias
33
- end
34
- ```
35
- (or define `FilterBase < Filter` if a true subclass is preferred.)
36
-
37
- ## Acceptance
38
-
39
- - All filter specs pass.
40
- - No public API breaks.
41
- - `lib/omnizip/filter.rb` removed or stubbed to alias.
42
-
43
- ## Files
44
-
45
- - modify `lib/omnizip/filter.rb`
46
- - create or modify `lib/omnizip/filters/base.rb`
47
- - modify `lib/omnizip/filters/filter_base.rb` (alias)
48
- - modify each subclass to inherit from the new base
49
- - add autoload entry in `lib/omnizip/filters.rb`