omnizip 0.4.7-x86_64-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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +293 -0
- data/CHANGELOG.md +1647 -0
- data/CONTEXT.md +68 -0
- data/COPYING +502 -0
- data/Gemfile +19 -0
- data/LICENSE +12 -0
- data/README.adoc +1327 -0
- data/Rakefile +15 -0
- data/TODO.refactor/00-overview.md +67 -0
- data/TODO.refactor/01-registry-base-class.md +81 -0
- data/TODO.refactor/02-error-hierarchy.md +57 -0
- data/TODO.refactor/03-autoload-entry-point.md +69 -0
- data/TODO.refactor/04-filter-base-consolidation.md +49 -0
- data/TODO.refactor/05-send-private-methods.md +64 -0
- data/TODO.refactor/06-instance-variable-access.md +69 -0
- data/TODO.refactor/07-respond-to-replacement.md +237 -0
- data/TODO.refactor/08-spec-doubles.md +27 -0
- data/TODO.refactor/09-cli-shared-module.md +35 -0
- data/TODO.refactor/10-format-detector-ocp.md +34 -0
- data/TODO.refactor/11-convenience-decoupling.md +38 -0
- data/TODO.refactor/12-thread-safety.md +8 -0
- data/TODO.refactor/13-lutaml-model-migration.md +158 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -0
- data/benchmark/README.md +260 -0
- data/benchmark/benchmark_suite.rb +125 -0
- data/benchmark/compression_bench.rb +181 -0
- data/benchmark/filter_bench.rb +180 -0
- data/benchmark/models/benchmark_result.rb +59 -0
- data/benchmark/models/comparison_result.rb +69 -0
- data/benchmark/profile_suite.rb +167 -0
- data/benchmark/reporter.rb +150 -0
- data/benchmark/run_benchmarks.rb +66 -0
- data/benchmark/test_data.rb +137 -0
- data/config/formats/rar3_spec.yml +92 -0
- data/config/formats/rar5_spec.yml +102 -0
- data/docs/.github/workflows/docs.yml +142 -0
- data/docs/.gitignore +21 -0
- data/docs/.lychee.toml +67 -0
- data/docs/Gemfile +13 -0
- data/docs/RAR_WRITE_SUPPORT.md +26 -0
- data/docs/README.md +101 -0
- data/docs/_config.yml +112 -0
- data/docs/assets/logo.svg +1 -0
- data/docs/assets/omnizip-logo.pdf +1540 -11
- data/docs/comparison/feature-matrix.adoc +694 -0
- data/docs/comparison/index.adoc +113 -0
- data/docs/comparison/vs-7zip.adoc +309 -0
- data/docs/comparison/vs-peazip.adoc +77 -0
- data/docs/comparison/vs-rubyzip.adoc +342 -0
- data/docs/comparison/vs-winrar.adoc +100 -0
- data/docs/compatibility.adoc +579 -0
- data/docs/concepts/index.adoc +129 -0
- data/docs/developer/architecture.adoc +256 -0
- data/docs/developer/contributing.adoc +158 -0
- data/docs/developer/index.adoc +25 -0
- data/docs/developer/testing.adoc +212 -0
- data/docs/getting-started/basic-usage.adoc +263 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +183 -0
- data/docs/getting-started/your-first-archive.adoc +219 -0
- data/docs/guides/advanced-features/encryption.adoc +277 -0
- data/docs/guides/advanced-features/index.adoc +59 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
- data/docs/guides/advanced-features/streaming.adoc +142 -0
- data/docs/guides/archive-formats/gzip-format.adoc +105 -0
- data/docs/guides/archive-formats/index.adoc +160 -0
- data/docs/guides/archive-formats/ole-format.adoc +151 -0
- data/docs/guides/archive-formats/rar-format.adoc +104 -0
- data/docs/guides/archive-formats/rar5.adoc +521 -0
- data/docs/guides/archive-formats/rpm-format.adoc +108 -0
- data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
- data/docs/guides/archive-formats/tar-format.adoc +106 -0
- data/docs/guides/archive-formats/xz-format.adoc +118 -0
- data/docs/guides/archive-formats/zip-format.adoc +35 -0
- data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
- data/docs/guides/compression-algorithms/deflate.adoc +313 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +394 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
- data/docs/guides/creating-archives.adoc +348 -0
- data/docs/guides/extracting-archives.adoc +53 -0
- data/docs/guides/format-conversion.adoc +64 -0
- data/docs/guides/index.adoc +49 -0
- data/docs/guides/migration-rubyzip.adoc +217 -0
- data/docs/guides/parity-archives.adoc +605 -0
- data/docs/guides/performance-tuning.adoc +88 -0
- data/docs/index.adoc +228 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +187 -0
- data/docs/reference/cli/compress-command.adoc +114 -0
- data/docs/reference/cli/overview.adoc +140 -0
- data/docs/reference/index.adoc +26 -0
- data/docs/resources/faq.adoc +185 -0
- data/docs/resources/quick-reference.adoc +222 -0
- data/docs/rust-backend.md +0 -0
- data/docs/troubleshooting/index.adoc +207 -0
- data/docs/xar_format.md +216 -0
- data/examples/api_comparison.rb +205 -0
- data/examples/deflate64_example.rb +96 -0
- data/examples/par2_demo.rb +121 -0
- data/examples/quick_start_native.rb +150 -0
- data/examples/quick_start_rubyzip.rb +115 -0
- data/examples/rubyzip_compatibility_demo.rb +194 -0
- data/exe/omnizip +27 -0
- data/lib/omnizip/algorithm.rb +176 -0
- data/lib/omnizip/algorithm_registry.rb +65 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
- data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
- data/lib/omnizip/algorithms/bzip2.rb +108 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
- data/lib/omnizip/algorithms/deflate.rb +135 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
- data/lib/omnizip/algorithms/deflate64.rb +118 -0
- data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
- data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
- data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
- data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
- data/lib/omnizip/algorithms/lzma/match.rb +32 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
- data/lib/omnizip/algorithms/lzma.rb +266 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +133 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +146 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +122 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
- data/lib/omnizip/algorithms/registration.rb +28 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
- data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
- data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
- data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
- data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
- data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
- data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
- data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
- data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +210 -0
- data/lib/omnizip/algorithms.rb +35 -0
- data/lib/omnizip/archive/builder.rb +48 -0
- data/lib/omnizip/archive/reader_session.rb +67 -0
- data/lib/omnizip/archive.rb +86 -0
- data/lib/omnizip/archive_handler.rb +82 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
- data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
- data/lib/omnizip/archive_handlers.rb +18 -0
- data/lib/omnizip/backends.rb +160 -0
- data/lib/omnizip/buffer/memory_archive.rb +246 -0
- data/lib/omnizip/buffer/memory_extractor.rb +234 -0
- data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
- data/lib/omnizip/buffer.rb +187 -0
- data/lib/omnizip/checksum_registry.rb +41 -0
- data/lib/omnizip/checksums/crc32.rb +101 -0
- data/lib/omnizip/checksums/crc64.rb +102 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/registration.rb +16 -0
- data/lib/omnizip/checksums/verifier.rb +130 -0
- data/lib/omnizip/checksums.rb +11 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +123 -0
- data/lib/omnizip/chunked.rb +123 -0
- data/lib/omnizip/cli/output_formatter.rb +112 -0
- data/lib/omnizip/cli.rb +604 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +245 -0
- data/lib/omnizip/commands/archive_extract_command.rb +231 -0
- data/lib/omnizip/commands/archive_list_command.rb +204 -0
- data/lib/omnizip/commands/archive_repair_command.rb +129 -0
- data/lib/omnizip/commands/archive_verify_command.rb +115 -0
- data/lib/omnizip/commands/compress_command.rb +115 -0
- data/lib/omnizip/commands/decompress_command.rb +149 -0
- data/lib/omnizip/commands/list_command.rb +51 -0
- data/lib/omnizip/commands/metadata_command.rb +215 -0
- data/lib/omnizip/commands/parity_create_command.rb +114 -0
- data/lib/omnizip/commands/parity_repair_command.rb +120 -0
- data/lib/omnizip/commands/parity_verify_command.rb +122 -0
- data/lib/omnizip/commands/profile_list_command.rb +54 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/commands.rb +21 -0
- data/lib/omnizip/convenience.rb +389 -0
- data/lib/omnizip/converter/conversion_registry.rb +50 -0
- data/lib/omnizip/converter/conversion_strategy.rb +108 -0
- data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
- data/lib/omnizip/converter.rb +124 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/crypto.rb +11 -0
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/error.rb +110 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
- data/lib/omnizip/eta/rate_calculator.rb +104 -0
- data/lib/omnizip/eta/sample_history.rb +143 -0
- data/lib/omnizip/eta/time_estimator.rb +106 -0
- data/lib/omnizip/eta.rb +68 -0
- data/lib/omnizip/extraction/filter_chain.rb +179 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
- data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
- data/lib/omnizip/extraction/regex_pattern.rb +50 -0
- data/lib/omnizip/extraction/selective_extractor.rb +247 -0
- data/lib/omnizip/extraction.rb +115 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +117 -0
- data/lib/omnizip/filter.rb +141 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +113 -0
- data/lib/omnizip/filters/bcj.rb +277 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
- data/lib/omnizip/filters/bcj2.rb +93 -0
- data/lib/omnizip/filters/bcj_arm.rb +174 -0
- data/lib/omnizip/filters/bcj_arm64.rb +242 -0
- data/lib/omnizip/filters/bcj_ia64.rb +194 -0
- data/lib/omnizip/filters/bcj_ppc.rb +188 -0
- data/lib/omnizip/filters/bcj_sparc.rb +174 -0
- data/lib/omnizip/filters/bcj_x86.rb +191 -0
- data/lib/omnizip/filters/delta.rb +195 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/filters.rb +20 -0
- data/lib/omnizip/format_detector.rb +166 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +159 -0
- data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +389 -0
- data/lib/omnizip/formats/cpio/reader.rb +194 -0
- data/lib/omnizip/formats/cpio/writer.rb +232 -0
- data/lib/omnizip/formats/cpio.rb +132 -0
- data/lib/omnizip/formats/format_spec_loader.rb +228 -0
- data/lib/omnizip/formats/gzip.rb +236 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
- data/lib/omnizip/formats/iso/directory_record.rb +162 -0
- data/lib/omnizip/formats/iso/joliet.rb +204 -0
- data/lib/omnizip/formats/iso/path_table.rb +125 -0
- data/lib/omnizip/formats/iso/reader.rb +194 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +543 -0
- data/lib/omnizip/formats/iso.rb +133 -0
- data/lib/omnizip/formats/lzip.rb +161 -0
- data/lib/omnizip/formats/lzma_alone.rb +149 -0
- data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
- data/lib/omnizip/formats/msi/constants.rb +157 -0
- data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
- data/lib/omnizip/formats/msi/entry.rb +134 -0
- data/lib/omnizip/formats/msi/reader.rb +301 -0
- data/lib/omnizip/formats/msi/string_pool.rb +246 -0
- data/lib/omnizip/formats/msi/table_parser.rb +244 -0
- data/lib/omnizip/formats/msi.rb +73 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
- data/lib/omnizip/formats/ole/constants.rb +61 -0
- data/lib/omnizip/formats/ole/dirent.rb +439 -0
- data/lib/omnizip/formats/ole/header.rb +199 -0
- data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
- data/lib/omnizip/formats/ole/storage.rb +482 -0
- data/lib/omnizip/formats/ole/types/variant.rb +338 -0
- data/lib/omnizip/formats/ole.rb +143 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
- data/lib/omnizip/formats/rar/block_parser.rb +282 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
- data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
- data/lib/omnizip/formats/rar/compression.rb +17 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +88 -0
- data/lib/omnizip/formats/rar/decompressor.rb +316 -0
- data/lib/omnizip/formats/rar/external_writer.rb +311 -0
- data/lib/omnizip/formats/rar/header.rb +209 -0
- data/lib/omnizip/formats/rar/license_validator.rb +111 -0
- data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
- data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
- data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
- data/lib/omnizip/formats/rar/models.rb +14 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
- data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
- data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
- data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
- data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
- data/lib/omnizip/formats/rar/reader.rb +377 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
- data/lib/omnizip/formats/rar/writer.rb +437 -0
- data/lib/omnizip/formats/rar.rb +193 -0
- data/lib/omnizip/formats/rar3/compressor.rb +71 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar3/reader.rb +107 -0
- data/lib/omnizip/formats/rar3/writer.rb +220 -0
- data/lib/omnizip/formats/rar3.rb +15 -0
- data/lib/omnizip/formats/rar5/compressor.rb +71 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar5/reader.rb +130 -0
- data/lib/omnizip/formats/rar5/writer.rb +65 -0
- data/lib/omnizip/formats/rar5.rb +15 -0
- data/lib/omnizip/formats/rpm/constants.rb +58 -0
- data/lib/omnizip/formats/rpm/entry.rb +106 -0
- data/lib/omnizip/formats/rpm/header.rb +106 -0
- data/lib/omnizip/formats/rpm/lead.rb +132 -0
- data/lib/omnizip/formats/rpm/tag.rb +228 -0
- data/lib/omnizip/formats/rpm/writer.rb +652 -0
- data/lib/omnizip/formats/rpm.rb +458 -0
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
- data/lib/omnizip/formats/seven_zip/header.rb +102 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/models.rb +20 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
- data/lib/omnizip/formats/seven_zip.rb +179 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +98 -0
- data/lib/omnizip/formats/tar/header.rb +206 -0
- data/lib/omnizip/formats/tar/reader.rb +119 -0
- data/lib/omnizip/formats/tar/writer.rb +212 -0
- data/lib/omnizip/formats/tar.rb +74 -0
- data/lib/omnizip/formats/xar/constants.rb +119 -0
- data/lib/omnizip/formats/xar/entry.rb +268 -0
- data/lib/omnizip/formats/xar/header.rb +223 -0
- data/lib/omnizip/formats/xar/reader.rb +400 -0
- data/lib/omnizip/formats/xar/toc.rb +570 -0
- data/lib/omnizip/formats/xar/writer.rb +461 -0
- data/lib/omnizip/formats/xar.rb +145 -0
- data/lib/omnizip/formats/xz/reader.rb +121 -0
- data/lib/omnizip/formats/xz/writer.rb +416 -0
- data/lib/omnizip/formats/xz.rb +210 -0
- data/lib/omnizip/formats/xz_const.rb +49 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl.rb +52 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
- data/lib/omnizip/formats/zip/reader.rb +376 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +489 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/formats.rb +29 -0
- data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
- data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
- data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
- data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
- data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
- data/lib/omnizip/implementations/base.rb +19 -0
- data/lib/omnizip/implementations/rust/archive.rb +93 -0
- data/lib/omnizip/implementations/rust/library.rb +221 -0
- data/lib/omnizip/implementations/rust.rb +26 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
- data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
- data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
- data/lib/omnizip/implementations/seven_zip.rb +11 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
- data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
- data/lib/omnizip/implementations/xz_utils.rb +10 -0
- data/lib/omnizip/implementations.rb +25 -0
- data/lib/omnizip/io/buffered_input.rb +147 -0
- data/lib/omnizip/io/buffered_output.rb +106 -0
- data/lib/omnizip/io/source.rb +143 -0
- data/lib/omnizip/io/stream_manager.rb +117 -0
- data/lib/omnizip/io.rb +15 -0
- data/lib/omnizip/link_handler/hard_link.rb +79 -0
- data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
- data/lib/omnizip/link_handler.rb +129 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +153 -0
- data/lib/omnizip/metadata/metadata_editor.rb +169 -0
- data/lib/omnizip/metadata/metadata_registry.rb +71 -0
- data/lib/omnizip/metadata/metadata_validator.rb +101 -0
- data/lib/omnizip/metadata.rb +58 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +41 -0
- data/lib/omnizip/models/attribute_apply.rb +40 -0
- data/lib/omnizip/models/compression_options.rb +53 -0
- data/lib/omnizip/models/conversion_options.rb +79 -0
- data/lib/omnizip/models/conversion_result.rb +141 -0
- data/lib/omnizip/models/eta_result.rb +45 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +142 -0
- data/lib/omnizip/models/filter_config.rb +148 -0
- data/lib/omnizip/models/match_result.rb +141 -0
- data/lib/omnizip/models/optimization_suggestion.rb +95 -0
- data/lib/omnizip/models/parallel_options.rb +116 -0
- data/lib/omnizip/models/performance_result.rb +85 -0
- data/lib/omnizip/models/profile_report.rb +116 -0
- data/lib/omnizip/models/progress_options.rb +39 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +45 -0
- data/lib/omnizip/parallel/engine.rb +52 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +225 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
- data/lib/omnizip/parallel/thread_pool.rb +60 -0
- data/lib/omnizip/parallel/worker_pool.rb +227 -0
- data/lib/omnizip/parallel.rb +156 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +71 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
- data/lib/omnizip/parity/models/main_packet.rb +126 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +102 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
- data/lib/omnizip/parity/models.rb +27 -0
- data/lib/omnizip/parity/par2_creator.rb +496 -0
- data/lib/omnizip/parity/par2_repairer.rb +409 -0
- data/lib/omnizip/parity/par2_verifier.rb +373 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
- data/lib/omnizip/parity.rb +207 -0
- data/lib/omnizip/password/encryption_registry.rb +26 -0
- data/lib/omnizip/password/encryption_strategy.rb +96 -0
- data/lib/omnizip/password/password_validator.rb +129 -0
- data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
- data/lib/omnizip/password.rb +88 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
- data/lib/omnizip/pipe.rb +120 -0
- data/lib/omnizip/platform/ntfs_streams.rb +200 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +36 -0
- data/lib/omnizip/profile/balanced_profile.rb +31 -0
- data/lib/omnizip/profile/binary_profile.rb +33 -0
- data/lib/omnizip/profile/compression_profile.rb +157 -0
- data/lib/omnizip/profile/custom_profile.rb +155 -0
- data/lib/omnizip/profile/fast_profile.rb +31 -0
- data/lib/omnizip/profile/maximum_profile.rb +31 -0
- data/lib/omnizip/profile/profile_detector.rb +108 -0
- data/lib/omnizip/profile/profile_registry.rb +160 -0
- data/lib/omnizip/profile/text_profile.rb +33 -0
- data/lib/omnizip/profile.rb +261 -0
- data/lib/omnizip/profiler/memory_profiler.rb +66 -0
- data/lib/omnizip/profiler/method_profiler.rb +49 -0
- data/lib/omnizip/profiler/report_generator.rb +158 -0
- data/lib/omnizip/profiler.rb +192 -0
- data/lib/omnizip/progress/callback_reporter.rb +34 -0
- data/lib/omnizip/progress/console_reporter.rb +59 -0
- data/lib/omnizip/progress/log_reporter.rb +89 -0
- data/lib/omnizip/progress/operation_progress.rb +118 -0
- data/lib/omnizip/progress/progress_bar.rb +156 -0
- data/lib/omnizip/progress/progress_reporter.rb +40 -0
- data/lib/omnizip/progress/progress_tracker.rb +215 -0
- data/lib/omnizip/progress/silent_reporter.rb +22 -0
- data/lib/omnizip/progress.rb +131 -0
- data/lib/omnizip/registry.rb +111 -0
- data/lib/omnizip/rubyzip_compat.rb +61 -0
- data/lib/omnizip/temp/safe_extract.rb +124 -0
- data/lib/omnizip/temp/temp_file.rb +123 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +184 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +160 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +270 -0
- data/lib/omnizip/zip/output_stream.rb +320 -0
- data/lib/omnizip/zip.rb +23 -0
- data/lib/omnizip.rb +157 -0
- data/lib/tasks/msi_test_files.rake +66 -0
- data/lib/tasks/platform_gems.rake +147 -0
- data/lib/tasks/rust_backend.rake +48 -0
- data/readme-docs/advanced-features.adoc +514 -0
- data/readme-docs/api-usage.adoc +445 -0
- data/readme-docs/architecture.adoc +450 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +446 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +316 -0
- data/readme-docs/installation.adoc +228 -0
- data/readme-docs/par2-archives.adoc +608 -0
- data/readme-docs/performance-profiler.adoc +389 -0
- data/readme-docs/preprocessing-filters.adoc +280 -0
- data/vendor/libomnizip_ffi.so +0 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +768 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# 07 — Replace `respond_to?` with proper typing
|
|
2
|
+
|
|
3
|
+
Priority: **medium**.
|
|
4
|
+
Status: **DONE**, with one known exception — `algorithms/lzma.rb:200` is a type
|
|
5
|
+
check we chose not to convert, not feature detection. See "The one exception".
|
|
6
|
+
|
|
7
|
+
## Rule
|
|
8
|
+
|
|
9
|
+
> NEVER use `respond_to?` for type checking. Use `is_a?` for type checks,
|
|
10
|
+
> or better yet, design the type hierarchy so the check isn't needed.
|
|
11
|
+
|
|
12
|
+
## Outcome
|
|
13
|
+
|
|
14
|
+
`lib/` went from 60 `respond_to?` occurrences to 49:
|
|
15
|
+
|
|
16
|
+
| | count |
|
|
17
|
+
|---|---|
|
|
18
|
+
| Converted to a real type check | 11 |
|
|
19
|
+
| Retained as genuine feature detection, annotated `# allowed:` | 45 |
|
|
20
|
+
| Retained as a **deferred type check**, annotated `# allowed:` | 1 |
|
|
21
|
+
| Prose inside doc comments (not code) | 3 |
|
|
22
|
+
|
|
23
|
+
46 sites carry an `# allowed:` annotation, but they are not all the same kind of
|
|
24
|
+
thing. 45 are feature detection on objects we do not control. **One is a type
|
|
25
|
+
check we decided not to convert** — counting it with the other 45 would overstate
|
|
26
|
+
how complete this track is, so it is broken out here and below.
|
|
27
|
+
|
|
28
|
+
The three prose occurrences are in `entry.rb`, `io/source.rb` and
|
|
29
|
+
`parallel/job_scheduler.rb`, where they document the pattern that was removed.
|
|
30
|
+
They are kept deliberately — rewording them so a `grep` returns zero would be
|
|
31
|
+
dishonest.
|
|
32
|
+
|
|
33
|
+
`spec/omnizip/respond_to_annotation_spec.rb` enforces the convention. It lexes
|
|
34
|
+
`lib/` with `Ripper` and fails on any `respond_to?` **identifier token** that
|
|
35
|
+
lacks a `# allowed: <reason>` **comment token** on its own line or the one
|
|
36
|
+
above. Being lexer-based rather than substring-based, a `# allowed:` inside a
|
|
37
|
+
string literal cannot satisfy it and a `respond_to?` inside a heredoc cannot
|
|
38
|
+
trip it.
|
|
39
|
+
|
|
40
|
+
Note what that spec does and does not do: it enforces that a reason is
|
|
41
|
+
**stated**, not that the reason is **good**. It cannot tell feature detection
|
|
42
|
+
from a deferred type check, which is exactly why the one exception is recorded
|
|
43
|
+
here in prose rather than left for the spec to imply.
|
|
44
|
+
|
|
45
|
+
## The governing distinction
|
|
46
|
+
|
|
47
|
+
A check is a **type check** (convert it) when every runtime type is enumerable
|
|
48
|
+
from the source. It is **feature detection** (annotate it) when a third party
|
|
49
|
+
can register or pass something we cannot enumerate.
|
|
50
|
+
|
|
51
|
+
The second half is what this pass got wrong at first. omnizip's world is open:
|
|
52
|
+
|
|
53
|
+
- `FilterRegistry.register` (`filter_registry.rb:30`) raises only on a nil name
|
|
54
|
+
or nil class. **No inheritance check.**
|
|
55
|
+
- `ProfileRegistry.register` (`profile_registry.rb:23`) requires only
|
|
56
|
+
`is_a?(CompressionProfile)`, not membership in the built-in set.
|
|
57
|
+
- `ArchiveHandler.register` (`archive_handler.rb:26`) accepts any object.
|
|
58
|
+
- The third positional `options` parameter on every `Algorithm#compress` /
|
|
59
|
+
`#decompress` is public and unconstrained.
|
|
60
|
+
|
|
61
|
+
So a check can look like a type check, and be one inside this repo today, while
|
|
62
|
+
still being reachable with a type we cannot name. Those stay, annotated.
|
|
63
|
+
|
|
64
|
+
## What was converted (11)
|
|
65
|
+
|
|
66
|
+
| site | conversion |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `algorithms/registration.rb:22` | guard dropped; `Algorithm.inherited` defines `register_algorithm` on every subclass |
|
|
69
|
+
| `algorithms/lzma/xz_utils_decoder.rb:291` | guard dropped; `@range_decoder ||=` runs earlier in the same method |
|
|
70
|
+
| `commands/archive_list_command.rb:72`, `:105` | `archive.entries`; the private builder returns one of three readers, all of which expose it |
|
|
71
|
+
| `implementations/seven_zip/lzma2/encoder.rb`, `implementations/xz_utils/lzma2/encoder.rb` | both `StringCompat` modules deleted, `byteslice` inlined at all three call sites — see below |
|
|
72
|
+
| `commands/archive_extract_command.rb:225` | `archive.is_a?(Omnizip::Zip::File)`; closed 4-way set, only ZIP closes |
|
|
73
|
+
| `implementations/xz_utils/lzma2/decoder.rb:420` | guard dropped; `@lzma_decoder` is always an `XzUtilsDecoder`, which exposes `range_decoder` |
|
|
74
|
+
| `io/stream_manager.rb:74` | `@source.close if @owned`; `@owned` is only true for a path the manager itself opened as a `File` |
|
|
75
|
+
| `algorithms/xz_lzma2.rb:59`, `algorithms/sevenzip_lzma2.rb:64` | routed through `Omnizip::IO::Source.for`, which accepts any `#read` duck |
|
|
76
|
+
|
|
77
|
+
The String branch in those last two was deliberately **not** routed through the
|
|
78
|
+
adapter: `Source::StringSource#read` treats a String that exists on disk as a
|
|
79
|
+
file path, so routing it would silently start reading files off disk whenever
|
|
80
|
+
input collided with a filename.
|
|
81
|
+
|
|
82
|
+
### The `StringCompat` modules
|
|
83
|
+
|
|
84
|
+
Each held `if "".respond_to?(:byteslice)` with a `string.bytes[start, length]`
|
|
85
|
+
fallback, under a comment claiming Ruby 3.0-3.1 lacks `String#byteslice`.
|
|
86
|
+
**That comment was simply wrong** — `String#byteslice` has existed since Ruby
|
|
87
|
+
1.9.3, so the fallback was unreachable on every Ruby that could ever have run
|
|
88
|
+
this gem.
|
|
89
|
+
|
|
90
|
+
Deleting only the `respond_to?` branch would have left a module named `Compat`
|
|
91
|
+
whose sole purpose was that branch, forwarding one call to `String#byteslice`
|
|
92
|
+
and nothing else — and two of the three call sites still carried a "for Ruby
|
|
93
|
+
3.0-3.1 compatibility" comment that would have become a lie. So both modules
|
|
94
|
+
were deleted outright and `temp_buffer.byteslice(0, out_pos.value)` inlined at
|
|
95
|
+
all three call sites (`xz_utils/lzma2/encoder.rb` ×2,
|
|
96
|
+
`seven_zip/lzma2/encoder.rb` ×1).
|
|
97
|
+
|
|
98
|
+
The separate comment at the two XZ Utils call sites is **kept**: it explains why
|
|
99
|
+
`byteslice` rather than `[]`, citing
|
|
100
|
+
https://bugs.ruby-lang.org/issues/15985 (the `[]` operator can return extra
|
|
101
|
+
bytes around NULs). That reason is real and outlives the compat shim.
|
|
102
|
+
|
|
103
|
+
## What was retained as feature detection (45)
|
|
104
|
+
|
|
105
|
+
Grouped by what the object actually is. `algorithms/lzma.rb:200` is deliberately
|
|
106
|
+
excluded from these counts and covered in the next section.
|
|
107
|
+
|
|
108
|
+
- **Caller-supplied IO** (24) — `formats/xz_impl/stream_decoder.rb` (8),
|
|
109
|
+
`formats/xz_impl/block_decoder.rb` (3), `algorithms/lzma/xz_utils_decoder.rb`
|
|
110
|
+
(2), `file_type.rb` (3), `io/source.rb` (4), `io/stream_manager.rb` (2),
|
|
111
|
+
`io/buffered_input.rb`, `io/buffered_output.rb`. Ruby has no `Seekable` or
|
|
112
|
+
`Ungettable` interface to type against; `StringIO`, `File`, `Socket`,
|
|
113
|
+
`Tempfile` and a user's own duck all differ in exactly `seek` / `pos` / `size`
|
|
114
|
+
/ `ungetbyte` / `set_encoding` / `close`.
|
|
115
|
+
- **Public `options` parameter** (7) — `algorithms/lzma.rb` (4),
|
|
116
|
+
`algorithms/bzip2.rb`, `algorithms/deflate.rb`, `algorithms/zstandard.rb`.
|
|
117
|
+
- **Open registries** (4) — `models/filter_config.rb`,
|
|
118
|
+
`commands/profile_show_command.rb`, `convenience.rb` (2).
|
|
119
|
+
- **Other caller-supplied objects** (10) — foreign archives and entries in
|
|
120
|
+
`extraction/selective_extractor.rb` (5) and `extraction/filter_chain.rb` (3),
|
|
121
|
+
an output sink in `implementations/seven_zip/lzma/encoder.rb`, and a metadata
|
|
122
|
+
object in `metadata/metadata_validator.rb`.
|
|
123
|
+
|
|
124
|
+
## The one exception (1)
|
|
125
|
+
|
|
126
|
+
`algorithms/lzma.rb:200` is annotated *"type check deferred, not feature
|
|
127
|
+
detection"*. That annotation is accurate and the code is honest, but it means
|
|
128
|
+
**track 07 is complete except for this single site**. It is a type check that
|
|
129
|
+
survives, not a capability probe.
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
level = if options.respond_to?(:level)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Two unrelated value objects reach `build_encoder_options` carrying `#level`:
|
|
136
|
+
`Models::CompressionOptions` and
|
|
137
|
+
`Formats::Rar::Rar5::Solid::SolidEncoder::LzmaOptions` (`solid_encoder.rb:95`,
|
|
138
|
+
reaching this method from `:52`). They share no ancestor. Rewriting the check to
|
|
139
|
+
`is_a?(Models::CompressionOptions)` would send solid-RAR5 compression down the
|
|
140
|
+
`else` branch and pin its level to 5 instead of the configured 1–5 — a silent
|
|
141
|
+
regression, which is why the conversion was rejected rather than attempted.
|
|
142
|
+
|
|
143
|
+
**What would close it:** unify `SolidEncoder::LzmaOptions`,
|
|
144
|
+
`Compression::LZMA::LzmaOptions` (`rar5/compression/lzma.rb:184`) and
|
|
145
|
+
`Models::CompressionOptions` into one type. That is RAR5 work, it breaks
|
|
146
|
+
`solid_encoder_spec.rb` and `lzma_spec.rb` assertions on `dict_size`, and
|
|
147
|
+
`CompressionOptions` names the attribute `dictionary_size`. Once those are one
|
|
148
|
+
type, this site converts to `is_a?` in a single line and track 07 is
|
|
149
|
+
unconditionally done.
|
|
150
|
+
|
|
151
|
+
Three cheaper-looking alternatives were considered and rejected: reaching from
|
|
152
|
+
`algorithms/` into `formats/rar/rar5/solid/` with a two-armed `is_a?`; a shared
|
|
153
|
+
`LevelledOptions` mixin introduced for exactly two call sites; and replacing
|
|
154
|
+
`LzmaOptions` with `CompressionOptions` outright, which the specs block.
|
|
155
|
+
|
|
156
|
+
## Corrections to the previous version of this document
|
|
157
|
+
|
|
158
|
+
- The count was **60**, not 109.
|
|
159
|
+
- Category B (`job.respond_to?(:size)` in `parallel/job_scheduler.rb`) and
|
|
160
|
+
category E (`opts.respond_to?(:"#{k}=")`) were **already done**.
|
|
161
|
+
- Category D was wrong. No `File.respond_to?(:symlink)` / `(:link)` sites
|
|
162
|
+
remained and `link_handler.rb` had none at all. The survivors filed under D
|
|
163
|
+
were `io.respond_to?(:pos)` / `(:seek)` in `file_type.rb`, which are **IO**
|
|
164
|
+
capability checks. The proposed `Platform.seekable?(io)` was rejected:
|
|
165
|
+
seekability is not a platform property, and the helper would still have
|
|
166
|
+
contained `respond_to?`, merely relocated.
|
|
167
|
+
- `formats/ole/` contained **zero** occurrences. The capability cluster was
|
|
168
|
+
`formats/xz_impl/` plus `algorithms/lzma/xz_utils_decoder.rb`.
|
|
169
|
+
- Category C was partly done already: `Omnizip::Entry` existed and was included
|
|
170
|
+
by 12 entry classes. Converting `extraction/filter_chain.rb` to use it was
|
|
171
|
+
attempted and rejected — below.
|
|
172
|
+
|
|
173
|
+
## Rejected: converting `extraction/filter_chain.rb`
|
|
174
|
+
|
|
175
|
+
`FilterChain#extract_filename` still walks `name` / `path` / `filename`. Routing
|
|
176
|
+
it through `Omnizip::Entry` looked like the intended fix, but a foreign entry
|
|
177
|
+
with `name == "secret.txt"` and `to_s == "opaque"` matches `*.txt` today and
|
|
178
|
+
would not afterwards. Because these filters drive **exclusion** as well as
|
|
179
|
+
inclusion, a filter that stops matching means a file the caller meant to block
|
|
180
|
+
gets extracted. `Extraction.extract_with_filter` is public, so this is
|
|
181
|
+
reachable. The conversion needs every entry reaching `FilterChain` to include
|
|
182
|
+
`Omnizip::Entry`, which the public API cannot guarantee.
|
|
183
|
+
|
|
184
|
+
## Bug found while doing this work
|
|
185
|
+
|
|
186
|
+
Auditing `IO::Source` for this track surfaced a live `NameError` in shipped
|
|
187
|
+
code. `io/source.rb` had **no `require` statements at all**, while `Source.for`
|
|
188
|
+
and `Sink.for` both `case` on `::IO, ::StringIO, ::Tempfile`. After a bare
|
|
189
|
+
`require "omnizip"` neither `StringIO` nor `Tempfile` is defined, so any input
|
|
190
|
+
that was not already an `::IO` raised:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
$ ruby -Ilib -e 'require "omnizip"
|
|
194
|
+
sink = Object.new; def sink.write(d); end
|
|
195
|
+
Omnizip::Formats::Xz.create("hello", sink)'
|
|
196
|
+
NameError: uninitialized constant Tempfile
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The adapter had 12 production call sites across `Formats::Xz`, `Formats::Lzip`,
|
|
200
|
+
`Formats::LzmaAlone` and `Algorithms::LZMA2`. The failure moved with the caller
|
|
201
|
+
— whichever constant the load path happened to pull in first appeared to work —
|
|
202
|
+
which is why it survived.
|
|
203
|
+
|
|
204
|
+
Fixed in its own commit across 15 files: 12 requires added to 11 files that
|
|
205
|
+
referenced a constant without requiring it, and 4 requires relocated out of
|
|
206
|
+
method and class bodies into the file prologue.
|
|
207
|
+
|
|
208
|
+
`spec/omnizip/constant_require_spec.rb` enforces the invariant statically —
|
|
209
|
+
`Ripper.lex` finds the constant references, `Ripper.sexp` confirms the matching
|
|
210
|
+
require is a top-level unconditional statement in the prologue, accepting both
|
|
211
|
+
`require "x"` and `require("x")`. `spec/omnizip/clean_load_spec.rb` adds four
|
|
212
|
+
subprocess regression proofs. Those must shell out: an in-process example passes
|
|
213
|
+
on the broken library, because `spec_helper` and sibling specs load both
|
|
214
|
+
constants as a side effect. That is the same masking that hid the bug.
|
|
215
|
+
|
|
216
|
+
## Acceptance
|
|
217
|
+
|
|
218
|
+
- `grep -rn "respond_to?" lib/` → 49: 46 annotated code sites (45 feature
|
|
219
|
+
detection + 1 deferred type check) and 3 doc comments.
|
|
220
|
+
- `spec/omnizip/respond_to_annotation_spec.rb` passes, and fails loudly on any
|
|
221
|
+
new unannotated occurrence.
|
|
222
|
+
- The one deferred type check is tracked in "The one exception" above, not
|
|
223
|
+
quietly folded into the feature-detection count.
|
|
224
|
+
|
|
225
|
+
## Follow-ups
|
|
226
|
+
|
|
227
|
+
- Unify `SolidEncoder::LzmaOptions`, `Compression::LZMA::LzmaOptions` and
|
|
228
|
+
`Models::CompressionOptions`, which would let `algorithms/lzma.rb:200`
|
|
229
|
+
convert.
|
|
230
|
+
- Normalize algorithm `options` to a single type. `Algorithm.compress(data,
|
|
231
|
+
level: 9)` forwards a Hash, so `bzip2`, `deflate` and `zstandard` silently
|
|
232
|
+
drop the level today — reached from `formats/zip/writer.rb:390`,
|
|
233
|
+
`zip/output_stream.rb:278` and `parallel/parallel_compressor.rb:104`. This
|
|
234
|
+
changes compressed output, so it needs its own pass. It would delete most of
|
|
235
|
+
the `options` annotations.
|
|
236
|
+
- Give `FilterChain` a guaranteed `Omnizip::Entry` contract, which would let
|
|
237
|
+
`extract_filename` convert.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# 08 — Remove `double()` from specs
|
|
2
|
+
|
|
3
|
+
Priority: **low** (1 occurrence).
|
|
4
|
+
Status: TODO.
|
|
5
|
+
|
|
6
|
+
## Rule
|
|
7
|
+
|
|
8
|
+
> NEVER use `double()` in specs. Use real model instances or lightweight
|
|
9
|
+
Structs.
|
|
10
|
+
|
|
11
|
+
## Inventory
|
|
12
|
+
|
|
13
|
+
| File:Line | Code |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `spec/omnizip/formats/rar/rar5/solid/solid_stream_spec.rb:41` | `stat = double("stat")` |
|
|
16
|
+
|
|
17
|
+
## Plan
|
|
18
|
+
|
|
19
|
+
1. Read the spec context to see which `File::Stat` interface the spec
|
|
20
|
+
exercises.
|
|
21
|
+
2. Replace with `Struct.new(:mtime, :size, :mode, ...).new(...)` or
|
|
22
|
+
`File::Stat.new(real_path)` if a real file is available.
|
|
23
|
+
|
|
24
|
+
## Acceptance
|
|
25
|
+
|
|
26
|
+
- `grep -rn "double(" spec/` returns zero matches.
|
|
27
|
+
- Spec passes.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 09 — CLI shared module
|
|
2
|
+
|
|
3
|
+
Priority: **low**.
|
|
4
|
+
Status: TODO.
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
`handle_error` is duplicated verbatim in three Thor classes inside
|
|
9
|
+
`lib/omnizip/cli.rb` (lines 81–84, 312–315, 557–560). `format_bytes`
|
|
10
|
+
(line 562) is a utility that doesn't belong inside the CLI class.
|
|
11
|
+
|
|
12
|
+
## Plan
|
|
13
|
+
|
|
14
|
+
1. Create `lib/omnizip/cli/shared.rb` defining:
|
|
15
|
+
```ruby
|
|
16
|
+
module Omnizip
|
|
17
|
+
class Cli
|
|
18
|
+
module Shared
|
|
19
|
+
def handle_error(err)
|
|
20
|
+
# ...
|
|
21
|
+
end
|
|
22
|
+
module_function :format_bytes
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
2. Each Thor class `include`s `Shared`.
|
|
28
|
+
3. Move `format_bytes` out of the CLI class proper; place it in a
|
|
29
|
+
`Omnizip::Cli::Formatters` module (or under `Omnizip::Utils::Bytes` if
|
|
30
|
+
broader use exists).
|
|
31
|
+
|
|
32
|
+
## Acceptance
|
|
33
|
+
|
|
34
|
+
- Single definition of `handle_error` and `format_bytes`.
|
|
35
|
+
- CLI specs pass.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 10 — FormatDetector OCP
|
|
2
|
+
|
|
3
|
+
Priority: **medium**.
|
|
4
|
+
Status: TODO.
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
`lib/omnizip/format_detector.rb:112-123` maps format symbols to reader
|
|
9
|
+
classes via a `case` statement. Adding a new format requires modifying
|
|
10
|
+
this method — a clear OCP violation. The `FormatRegistry` already
|
|
11
|
+
registers each format handler; this case statement duplicates that
|
|
12
|
+
knowledge.
|
|
13
|
+
|
|
14
|
+
## Plan
|
|
15
|
+
|
|
16
|
+
1. Replace the case statement with a lookup against `FormatRegistry`:
|
|
17
|
+
```ruby
|
|
18
|
+
def reader_for(format)
|
|
19
|
+
FormatRegistry.get(format) ||
|
|
20
|
+
raise(UnsupportedFormatError, "No reader for #{format}")
|
|
21
|
+
end
|
|
22
|
+
```
|
|
23
|
+
2. Ensure every format that previously appeared in the case statement is
|
|
24
|
+
registered in `FormatRegistry` with its reader class.
|
|
25
|
+
3. If a format is detected but its handler hasn't been required yet, the
|
|
26
|
+
registry lookup must trigger autoload — verify the autoload wiring in
|
|
27
|
+
`lib/omnizip.rb` makes this work.
|
|
28
|
+
|
|
29
|
+
## Acceptance
|
|
30
|
+
|
|
31
|
+
- `lib/omnizip/format_detector.rb` no longer has a format-specific case.
|
|
32
|
+
- All format_detector specs pass.
|
|
33
|
+
- A new format can be added by registering it, with zero edits to
|
|
34
|
+
FormatDetector.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# 11 — Convenience module decoupling
|
|
2
|
+
|
|
3
|
+
Priority: **medium**.
|
|
4
|
+
Status: TODO.
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
`lib/omnizip/convenience.rb` (359 lines) hardcodes `Omnizip::Zip::File`
|
|
9
|
+
in 7 method bodies (lines 45, 87, 112, 149, 175, 207, 227) —
|
|
10
|
+
`compress_file`, `compress_directory`, `extract_archive`,
|
|
11
|
+
`list_archive`, `read_from_archive`, `add_to_archive`,
|
|
12
|
+
`remove_from_archive`. The codebase supports 7z, XZ, tar, gzip, bzip2,
|
|
13
|
+
RAR, but convenience methods are ZIP-only.
|
|
14
|
+
|
|
15
|
+
## Plan
|
|
16
|
+
|
|
17
|
+
1. Add a `format:` keyword argument to each convenience method.
|
|
18
|
+
Default to `:zip` for backward compatibility.
|
|
19
|
+
2. Resolve the format handler via `FormatRegistry.get(format)` and
|
|
20
|
+
delegate. If the handler doesn't expose the needed operation, raise a
|
|
21
|
+
clear `UnsupportedFormatError` describing what's missing.
|
|
22
|
+
3. Each format handler (zip, seven_zip, tar, gzip, xz, bzip2) should
|
|
23
|
+
implement a shared `Handler` interface with `#add_file`,
|
|
24
|
+
`#add_directory`, `#extract`, `#list`, `#read`, `#remove`. This
|
|
25
|
+
becomes the contract for being usable from `convenience.rb`.
|
|
26
|
+
|
|
27
|
+
## Acceptance
|
|
28
|
+
|
|
29
|
+
- Convenience methods accept `format:` and dispatch via registry.
|
|
30
|
+
- ZIP path remains the default with no behavior change.
|
|
31
|
+
- At least one non-ZIP format (e.g., tar) is wired up end-to-end.
|
|
32
|
+
|
|
33
|
+
## Scope note
|
|
34
|
+
|
|
35
|
+
Full format handler interface extraction is large. This pass:
|
|
36
|
+
1. Adds the `format:` keyword with ZIP default.
|
|
37
|
+
2. Wires tar as a second supported format (simplest after zip).
|
|
38
|
+
3. Leaves the remaining formats as documented future work.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# 12 — Thread safety
|
|
2
|
+
|
|
3
|
+
Priority: covered by track 01.
|
|
4
|
+
Status: n/a.
|
|
5
|
+
|
|
6
|
+
The `Registry` base class introduced in track 01 includes `Mutex`-based
|
|
7
|
+
synchronization around mutations (`register`, `reset!`). All migrated
|
|
8
|
+
registries inherit this for free. No standalone work.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# 13 — lutaml-model migration
|
|
2
|
+
|
|
3
|
+
Priority: **medium**.
|
|
4
|
+
Status: DONE for the models that should migrate. The remaining `to_h`
|
|
5
|
+
methods are deliberate — see "Why 17 stay" below.
|
|
6
|
+
|
|
7
|
+
## Rule
|
|
8
|
+
|
|
9
|
+
> ALL (de)serialization goes through the framework. Declare attributes
|
|
10
|
+
> with `attribute :name, :type`. Declare wire names with a `mapping do
|
|
11
|
+
> ... end` block. Never write `def to_h` / `def from_h` / `def to_json`
|
|
12
|
+
> / `def from_json` on a model class.
|
|
13
|
+
|
|
14
|
+
## Result
|
|
15
|
+
|
|
16
|
+
Six models now inherit `Lutaml::Model::Serializable`:
|
|
17
|
+
|
|
18
|
+
- `CompressionOptions`, `AlgorithmMetadata` (earlier pass)
|
|
19
|
+
- `ConversionOptions`, `ProgressOptions`, `ETAResult`, `ParallelOptions`
|
|
20
|
+
|
|
21
|
+
Counts, measured against the tree rather than estimated:
|
|
22
|
+
|
|
23
|
+
| Metric | Before | After |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `grep -rn "def to_h" lib/ \| wc -l` | 21 | 17 |
|
|
26
|
+
| Same under `lib/omnizip/models/` | 10 | 6 |
|
|
27
|
+
| `def to_json` / `from_h` / `from_json` in `lib/` | 0 | 0 |
|
|
28
|
+
|
|
29
|
+
An earlier version of this document claimed "26 `def to_h` across 22
|
|
30
|
+
files, 2 `def to_json`". Both were wrong; the numbers above are real.
|
|
31
|
+
|
|
32
|
+
## The symbol-type blocker was not real
|
|
33
|
+
|
|
34
|
+
This document previously held `ConversionOptions` back pending "lutaml
|
|
35
|
+
symbol-type support". There is nothing to wait for. `:symbol` is a
|
|
36
|
+
built-in type from 0.8.0 on: it is registered in `TYPE_CODES` in
|
|
37
|
+
`lib/lutaml/model/type.rb` and implemented in
|
|
38
|
+
`lib/lutaml/model/type/symbol.rb`. It casts symbols, strings, and nil
|
|
39
|
+
correctly and round-trips through JSON. `ConversionOptions` uses it for
|
|
40
|
+
`source_format`, `target_format`, `compression`, and `filter`.
|
|
41
|
+
|
|
42
|
+
The gemspec asks for `~> 0.8` because of this. `~> 0.7` also resolved to
|
|
43
|
+
0.8 on a fresh install, but it still admitted 0.7.1 through 0.7.7, where
|
|
44
|
+
`:symbol` is unregistered and `default: -> { detect_cpu_count }` is
|
|
45
|
+
evaluated against the class. Pin a build to 0.7.7 and 25 examples fail.
|
|
46
|
+
|
|
47
|
+
## Recipe
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
require "lutaml/model"
|
|
51
|
+
|
|
52
|
+
class Thing < Lutaml::Model::Serializable
|
|
53
|
+
attribute :level, :integer, default: 5
|
|
54
|
+
attribute :name, :string
|
|
55
|
+
|
|
56
|
+
key_value do
|
|
57
|
+
map "level", to: :level, render_default: true, render_nil: true
|
|
58
|
+
map "name", to: :name, render_default: true, render_nil: true
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`key_value` covers hash, YAML, TOML, and JSON in one declaration.
|
|
64
|
+
|
|
65
|
+
### Two behaviours that will catch you out
|
|
66
|
+
|
|
67
|
+
**1. `to_hash` returns String keys.** The hand-rolled `to_h` methods
|
|
68
|
+
returned Symbol keys. These are not interchangeable, and
|
|
69
|
+
`Serializable` does not define `to_h` at all — calling it raises
|
|
70
|
+
`NoMethodError`. Removing `to_h` is a breaking change for any external
|
|
71
|
+
caller.
|
|
72
|
+
|
|
73
|
+
**2. `render_default: true` alone does not give you a fixed key set.**
|
|
74
|
+
It renders an unassigned default, but still drops a key that was
|
|
75
|
+
explicitly assigned `nil`:
|
|
76
|
+
|
|
77
|
+
| Mapping | fresh `.new` | after `x.a = nil` |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| `render_default: true` | `{"a" => 5}` | `{}` |
|
|
80
|
+
| `+ render_nil: true` | `{"a" => 5, "b" => nil}` | `{"a" => nil}` |
|
|
81
|
+
|
|
82
|
+
Use **both** flags when the old `to_h` emitted every key. Use
|
|
83
|
+
`render_default` alone when it ended in `.compact`. Use neither when
|
|
84
|
+
there are no defaults and nils were dropped. There is no class-level or
|
|
85
|
+
global switch — `render_default:` is per-rule and defaults to `false`.
|
|
86
|
+
|
|
87
|
+
### Other gotchas
|
|
88
|
+
|
|
89
|
+
- Lambda defaults (`default: -> { detect_cpu_count }`) are evaluated
|
|
90
|
+
with `self` bound to the **instance**. A private instance method
|
|
91
|
+
works; a class method raises `NameError`.
|
|
92
|
+
- `dup` shares the internal `@using_default` hash. With both render
|
|
93
|
+
flags set this is unobservable, so no `dup` override or
|
|
94
|
+
`initialize_copy` hook is needed.
|
|
95
|
+
- Unknown keyword arguments to `.new` are silently ignored, where a
|
|
96
|
+
plain-Ruby `initialize` would raise `ArgumentError`.
|
|
97
|
+
- `self.class.attributes` returns a `Hash{Symbol=>Attribute}`. Iterate
|
|
98
|
+
it with `each_key`.
|
|
99
|
+
|
|
100
|
+
## Why 17 `to_h` methods stay
|
|
101
|
+
|
|
102
|
+
These are computed reports, projections over another object, or
|
|
103
|
+
wire-format builders — not serializations of the receiver's own state.
|
|
104
|
+
Converting them would drop the computed fields or force a second method
|
|
105
|
+
back onto the class. Leave them alone.
|
|
106
|
+
|
|
107
|
+
| File | Reason |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `models/conversion_result.rb` | Three computed fields; drops a stored one |
|
|
110
|
+
| `models/match_result.rb` | Keys don't match attributes; renames and computes |
|
|
111
|
+
| `models/optimization_suggestion.rb` | Computed `priority_score`; ctor validates enums |
|
|
112
|
+
| `models/performance_result.rb` | Computed fields plus `timestamp.iso8601` |
|
|
113
|
+
| `models/profile_report.rb` | Nested computed `summary:`; maps nested results |
|
|
114
|
+
| `models/filter_config.rb` | Emits `:name` for `@name_sym`; binary properties; registry lookups |
|
|
115
|
+
| `formats/rpm/header.rb` | Tag-map projection over a collection |
|
|
116
|
+
| `formats/xar/entry.rb` | XAR XML attributes; octal mode, formatted timestamps |
|
|
117
|
+
| `formats/zip/unix_extra_field.rb` | Emits a constant tag; wire format is manual pack |
|
|
118
|
+
| `metadata/entry_metadata.rb` | Pure delegation; stores no attributes of its own |
|
|
119
|
+
| `metadata/archive_metadata.rb` | Computed aggregates |
|
|
120
|
+
| `profile/compression_profile.rb` | `CustomProfile#to_h` calls `super` on it |
|
|
121
|
+
| `profile/custom_profile.rb` | Inheritance chain over `to_h` |
|
|
122
|
+
| `profile/profile_registry.rb` | Registry projection under a mutex |
|
|
123
|
+
| `progress/operation_progress.rb` | Computed percentages and elapsed time |
|
|
124
|
+
| `link_handler/symbolic_link.rb` | Type discriminator; storage uses `serialize` |
|
|
125
|
+
| `link_handler/hard_link.rb` | Type discriminator; storage uses `serialize` |
|
|
126
|
+
|
|
127
|
+
Because these stay, `grep "def to_h" lib/` will never reach zero. That
|
|
128
|
+
is the intended end state, not unfinished work.
|
|
129
|
+
|
|
130
|
+
## Follow-up work
|
|
131
|
+
|
|
132
|
+
1. **Rename the 17 — DECIDED: deferred to a deliberate major/minor
|
|
133
|
+
release.** The names below remain the plan if that release
|
|
134
|
+
happens: `to_report` for the computed ones, `to_tag_map` /
|
|
135
|
+
`to_attributes` for projections, `to_xml_attributes` / `to_fields`
|
|
136
|
+
for wire-format builders. Each rename is a public-API break
|
|
137
|
+
(every one of the 17 is a public class method), so it cannot ship
|
|
138
|
+
silently in a patch; the 17 staying is the intended end state for
|
|
139
|
+
now, per "Why 17 stay" above.
|
|
140
|
+
2. **DONE (0.3.28, PR #42).** `apply` fixed in both classes — all
|
|
141
|
+
three options models now share the tested
|
|
142
|
+
`Models::AttributeApply` concern, which also delivers (3).
|
|
143
|
+
3. **DONE (0.3.28, PR #42)** — see (2).
|
|
144
|
+
4. **Considered — decided against, with reasons.**
|
|
145
|
+
- `FilterConfig` is a behavior-heavy domain object, not a
|
|
146
|
+
serialization model: `filter_instance` reaches into
|
|
147
|
+
`FilterRegistry`, `id_for_format`/`bcj?`/`delta?` are domain
|
|
148
|
+
queries, `properties` defaults to a binary String (lutaml's
|
|
149
|
+
`:string` is UTF-8-oriented, so the attribute would need a
|
|
150
|
+
custom type), and initialization accepts two alias keys
|
|
151
|
+
(`:name`/`:name_sym`). Its `to_h` is a projection with no
|
|
152
|
+
round-trip consumer. Migration would fight the framework to
|
|
153
|
+
achieve nothing the class needs.
|
|
154
|
+
- The profile classes are abstract domain objects: subclasses
|
|
155
|
+
override `suitable_for?`, `apply_to` mutates an options object,
|
|
156
|
+
five validators run at construction, and `to_h` coexists with
|
|
157
|
+
`to_s`/`inspect` as display projections. No wire format round
|
|
158
|
+
trips them. Same verdict.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 14 — Add missing specs
|
|
2
|
+
|
|
3
|
+
Priority: **high**.
|
|
4
|
+
Status: TODO.
|
|
5
|
+
|
|
6
|
+
## Plan
|
|
7
|
+
|
|
8
|
+
Add or strengthen specs for:
|
|
9
|
+
|
|
10
|
+
1. `Omnizip::Registry` (new base class from track 01) — register / get /
|
|
11
|
+
registered? / available / reset! / thread-safety smoke test / custom
|
|
12
|
+
not-found error.
|
|
13
|
+
2. `Omnizip::Error` hierarchy (track 02) — confirm inheritance and
|
|
14
|
+
aliases.
|
|
15
|
+
3. `Omnizip::Cli::Shared` (track 09) — `handle_error` and
|
|
16
|
+
`format_bytes`.
|
|
17
|
+
4. `Omnizip::IO::Source` / `Omnizip::IO::Sink` (track 07) — adapter
|
|
18
|
+
behavior for String / StringIO / File / Pathname.
|
|
19
|
+
5. Promoted public methods (track 05) — wherever a method moves from
|
|
20
|
+
private to public, ensure a spec covers its new visibility.
|
|
21
|
+
|
|
22
|
+
## Acceptance
|
|
23
|
+
|
|
24
|
+
- All new specs pass.
|
|
25
|
+
- No `double()` introduced.
|