omnizip 0.4.7-aarch64-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 (632) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +293 -0
  5. data/CHANGELOG.md +1647 -0
  6. data/CONTEXT.md +68 -0
  7. data/COPYING +502 -0
  8. data/Gemfile +19 -0
  9. data/LICENSE +12 -0
  10. data/README.adoc +1327 -0
  11. data/Rakefile +15 -0
  12. data/TODO.refactor/00-overview.md +67 -0
  13. data/TODO.refactor/01-registry-base-class.md +81 -0
  14. data/TODO.refactor/02-error-hierarchy.md +57 -0
  15. data/TODO.refactor/03-autoload-entry-point.md +69 -0
  16. data/TODO.refactor/04-filter-base-consolidation.md +49 -0
  17. data/TODO.refactor/05-send-private-methods.md +64 -0
  18. data/TODO.refactor/06-instance-variable-access.md +69 -0
  19. data/TODO.refactor/07-respond-to-replacement.md +237 -0
  20. data/TODO.refactor/08-spec-doubles.md +27 -0
  21. data/TODO.refactor/09-cli-shared-module.md +35 -0
  22. data/TODO.refactor/10-format-detector-ocp.md +34 -0
  23. data/TODO.refactor/11-convenience-decoupling.md +38 -0
  24. data/TODO.refactor/12-thread-safety.md +8 -0
  25. data/TODO.refactor/13-lutaml-model-migration.md +158 -0
  26. data/TODO.refactor/14-add-missing-specs.md +25 -0
  27. data/benchmark/README.md +260 -0
  28. data/benchmark/benchmark_suite.rb +125 -0
  29. data/benchmark/compression_bench.rb +181 -0
  30. data/benchmark/filter_bench.rb +180 -0
  31. data/benchmark/models/benchmark_result.rb +59 -0
  32. data/benchmark/models/comparison_result.rb +69 -0
  33. data/benchmark/profile_suite.rb +167 -0
  34. data/benchmark/reporter.rb +150 -0
  35. data/benchmark/run_benchmarks.rb +66 -0
  36. data/benchmark/test_data.rb +137 -0
  37. data/config/formats/rar3_spec.yml +92 -0
  38. data/config/formats/rar5_spec.yml +102 -0
  39. data/docs/.github/workflows/docs.yml +142 -0
  40. data/docs/.gitignore +21 -0
  41. data/docs/.lychee.toml +67 -0
  42. data/docs/Gemfile +13 -0
  43. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  44. data/docs/README.md +101 -0
  45. data/docs/_config.yml +112 -0
  46. data/docs/assets/logo.svg +1 -0
  47. data/docs/assets/omnizip-logo.pdf +1540 -11
  48. data/docs/comparison/feature-matrix.adoc +694 -0
  49. data/docs/comparison/index.adoc +113 -0
  50. data/docs/comparison/vs-7zip.adoc +309 -0
  51. data/docs/comparison/vs-peazip.adoc +77 -0
  52. data/docs/comparison/vs-rubyzip.adoc +342 -0
  53. data/docs/comparison/vs-winrar.adoc +100 -0
  54. data/docs/compatibility.adoc +579 -0
  55. data/docs/concepts/index.adoc +129 -0
  56. data/docs/developer/architecture.adoc +256 -0
  57. data/docs/developer/contributing.adoc +158 -0
  58. data/docs/developer/index.adoc +25 -0
  59. data/docs/developer/testing.adoc +212 -0
  60. data/docs/getting-started/basic-usage.adoc +263 -0
  61. data/docs/getting-started/index.adoc +42 -0
  62. data/docs/getting-started/installation.adoc +138 -0
  63. data/docs/getting-started/quick-start.adoc +183 -0
  64. data/docs/getting-started/your-first-archive.adoc +219 -0
  65. data/docs/guides/advanced-features/encryption.adoc +277 -0
  66. data/docs/guides/advanced-features/index.adoc +59 -0
  67. data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
  68. data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
  69. data/docs/guides/advanced-features/streaming.adoc +142 -0
  70. data/docs/guides/archive-formats/gzip-format.adoc +105 -0
  71. data/docs/guides/archive-formats/index.adoc +160 -0
  72. data/docs/guides/archive-formats/ole-format.adoc +151 -0
  73. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  74. data/docs/guides/archive-formats/rar5.adoc +521 -0
  75. data/docs/guides/archive-formats/rpm-format.adoc +108 -0
  76. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  77. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  78. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  79. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  80. data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
  81. data/docs/guides/compression-algorithms/deflate.adoc +313 -0
  82. data/docs/guides/compression-algorithms/index.adoc +190 -0
  83. data/docs/guides/compression-algorithms/lzma.adoc +394 -0
  84. data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
  85. data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
  86. data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
  87. data/docs/guides/creating-archives.adoc +348 -0
  88. data/docs/guides/extracting-archives.adoc +53 -0
  89. data/docs/guides/format-conversion.adoc +64 -0
  90. data/docs/guides/index.adoc +49 -0
  91. data/docs/guides/migration-rubyzip.adoc +217 -0
  92. data/docs/guides/parity-archives.adoc +605 -0
  93. data/docs/guides/performance-tuning.adoc +88 -0
  94. data/docs/index.adoc +228 -0
  95. data/docs/lychee.toml +67 -0
  96. data/docs/reference/api/overview.adoc +187 -0
  97. data/docs/reference/cli/compress-command.adoc +114 -0
  98. data/docs/reference/cli/overview.adoc +140 -0
  99. data/docs/reference/index.adoc +26 -0
  100. data/docs/resources/faq.adoc +185 -0
  101. data/docs/resources/quick-reference.adoc +222 -0
  102. data/docs/rust-backend.md +0 -0
  103. data/docs/troubleshooting/index.adoc +207 -0
  104. data/docs/xar_format.md +216 -0
  105. data/examples/api_comparison.rb +205 -0
  106. data/examples/deflate64_example.rb +96 -0
  107. data/examples/par2_demo.rb +121 -0
  108. data/examples/quick_start_native.rb +150 -0
  109. data/examples/quick_start_rubyzip.rb +115 -0
  110. data/examples/rubyzip_compatibility_demo.rb +194 -0
  111. data/exe/omnizip +27 -0
  112. data/lib/omnizip/algorithm.rb +176 -0
  113. data/lib/omnizip/algorithm_registry.rb +65 -0
  114. data/lib/omnizip/algorithms/.keep +0 -0
  115. data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
  116. data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
  117. data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
  118. data/lib/omnizip/algorithms/bzip2.rb +108 -0
  119. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  120. data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
  121. data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
  122. data/lib/omnizip/algorithms/deflate.rb +135 -0
  123. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  124. data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
  125. data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
  126. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
  127. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
  128. data/lib/omnizip/algorithms/deflate64.rb +118 -0
  129. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  130. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  131. data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
  132. data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
  133. data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
  134. data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
  135. data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
  136. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
  137. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
  138. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
  139. data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
  140. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
  141. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  142. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  143. data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
  144. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  145. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
  146. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
  147. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  148. data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
  149. data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
  150. data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
  151. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  152. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
  153. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
  154. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
  155. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
  156. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
  157. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
  158. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  159. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
  160. data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
  161. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
  162. data/lib/omnizip/algorithms/lzma.rb +266 -0
  163. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
  164. data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
  165. data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
  166. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
  167. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  168. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
  169. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  170. data/lib/omnizip/algorithms/lzma2.rb +133 -0
  171. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  172. data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
  173. data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
  174. data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
  175. data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
  176. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  177. data/lib/omnizip/algorithms/ppmd7.rb +146 -0
  178. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  179. data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
  180. data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
  181. data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
  182. data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
  183. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  184. data/lib/omnizip/algorithms/ppmd8.rb +122 -0
  185. data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
  186. data/lib/omnizip/algorithms/registration.rb +28 -0
  187. data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
  188. data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
  189. data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
  190. data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
  191. data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
  192. data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
  193. data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
  194. data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
  195. data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
  196. data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
  197. data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
  198. data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
  199. data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
  200. data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
  201. data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
  202. data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
  203. data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
  204. data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
  205. data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
  206. data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
  207. data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
  208. data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
  209. data/lib/omnizip/algorithms/zstandard.rb +210 -0
  210. data/lib/omnizip/algorithms.rb +35 -0
  211. data/lib/omnizip/archive/builder.rb +48 -0
  212. data/lib/omnizip/archive/reader_session.rb +67 -0
  213. data/lib/omnizip/archive.rb +86 -0
  214. data/lib/omnizip/archive_handler.rb +82 -0
  215. data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
  216. data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
  217. data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
  218. data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
  219. data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
  220. data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
  221. data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
  222. data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
  223. data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
  224. data/lib/omnizip/archive_handlers.rb +18 -0
  225. data/lib/omnizip/backends.rb +160 -0
  226. data/lib/omnizip/buffer/memory_archive.rb +246 -0
  227. data/lib/omnizip/buffer/memory_extractor.rb +234 -0
  228. data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
  229. data/lib/omnizip/buffer.rb +187 -0
  230. data/lib/omnizip/checksum_registry.rb +41 -0
  231. data/lib/omnizip/checksums/crc32.rb +101 -0
  232. data/lib/omnizip/checksums/crc64.rb +102 -0
  233. data/lib/omnizip/checksums/crc_base.rb +158 -0
  234. data/lib/omnizip/checksums/registration.rb +16 -0
  235. data/lib/omnizip/checksums/verifier.rb +130 -0
  236. data/lib/omnizip/checksums.rb +11 -0
  237. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  238. data/lib/omnizip/chunked/reader.rb +78 -0
  239. data/lib/omnizip/chunked/writer.rb +123 -0
  240. data/lib/omnizip/chunked.rb +123 -0
  241. data/lib/omnizip/cli/output_formatter.rb +112 -0
  242. data/lib/omnizip/cli.rb +604 -0
  243. data/lib/omnizip/commands/.keep +0 -0
  244. data/lib/omnizip/commands/archive_create_command.rb +245 -0
  245. data/lib/omnizip/commands/archive_extract_command.rb +231 -0
  246. data/lib/omnizip/commands/archive_list_command.rb +204 -0
  247. data/lib/omnizip/commands/archive_repair_command.rb +129 -0
  248. data/lib/omnizip/commands/archive_verify_command.rb +115 -0
  249. data/lib/omnizip/commands/compress_command.rb +115 -0
  250. data/lib/omnizip/commands/decompress_command.rb +149 -0
  251. data/lib/omnizip/commands/list_command.rb +51 -0
  252. data/lib/omnizip/commands/metadata_command.rb +215 -0
  253. data/lib/omnizip/commands/parity_create_command.rb +114 -0
  254. data/lib/omnizip/commands/parity_repair_command.rb +120 -0
  255. data/lib/omnizip/commands/parity_verify_command.rb +122 -0
  256. data/lib/omnizip/commands/profile_list_command.rb +54 -0
  257. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  258. data/lib/omnizip/commands.rb +21 -0
  259. data/lib/omnizip/convenience.rb +389 -0
  260. data/lib/omnizip/converter/conversion_registry.rb +50 -0
  261. data/lib/omnizip/converter/conversion_strategy.rb +108 -0
  262. data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
  263. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
  264. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
  265. data/lib/omnizip/converter.rb +124 -0
  266. data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
  267. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  268. data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
  269. data/lib/omnizip/crypto/aes256.rb +102 -0
  270. data/lib/omnizip/crypto.rb +11 -0
  271. data/lib/omnizip/entry.rb +44 -0
  272. data/lib/omnizip/error.rb +110 -0
  273. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
  274. data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
  275. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  276. data/lib/omnizip/eta/sample_history.rb +143 -0
  277. data/lib/omnizip/eta/time_estimator.rb +106 -0
  278. data/lib/omnizip/eta.rb +68 -0
  279. data/lib/omnizip/extraction/filter_chain.rb +179 -0
  280. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  281. data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
  282. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  283. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  284. data/lib/omnizip/extraction/selective_extractor.rb +247 -0
  285. data/lib/omnizip/extraction.rb +115 -0
  286. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  287. data/lib/omnizip/file_type.rb +117 -0
  288. data/lib/omnizip/filter.rb +141 -0
  289. data/lib/omnizip/filter_pipeline.rb +108 -0
  290. data/lib/omnizip/filter_registry.rb +113 -0
  291. data/lib/omnizip/filters/bcj.rb +277 -0
  292. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  293. data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
  294. data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
  295. data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
  296. data/lib/omnizip/filters/bcj2.rb +93 -0
  297. data/lib/omnizip/filters/bcj_arm.rb +174 -0
  298. data/lib/omnizip/filters/bcj_arm64.rb +242 -0
  299. data/lib/omnizip/filters/bcj_ia64.rb +194 -0
  300. data/lib/omnizip/filters/bcj_ppc.rb +188 -0
  301. data/lib/omnizip/filters/bcj_sparc.rb +174 -0
  302. data/lib/omnizip/filters/bcj_x86.rb +191 -0
  303. data/lib/omnizip/filters/delta.rb +195 -0
  304. data/lib/omnizip/filters/xz_delta.rb +258 -0
  305. data/lib/omnizip/filters.rb +20 -0
  306. data/lib/omnizip/format_detector.rb +166 -0
  307. data/lib/omnizip/formats/.keep +0 -0
  308. data/lib/omnizip/formats/bzip2_file.rb +159 -0
  309. data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
  310. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  311. data/lib/omnizip/formats/cpio/entry.rb +389 -0
  312. data/lib/omnizip/formats/cpio/reader.rb +194 -0
  313. data/lib/omnizip/formats/cpio/writer.rb +232 -0
  314. data/lib/omnizip/formats/cpio.rb +132 -0
  315. data/lib/omnizip/formats/format_spec_loader.rb +228 -0
  316. data/lib/omnizip/formats/gzip.rb +236 -0
  317. data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
  318. data/lib/omnizip/formats/iso/directory_record.rb +162 -0
  319. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  320. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  321. data/lib/omnizip/formats/iso/reader.rb +194 -0
  322. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  323. data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
  324. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  325. data/lib/omnizip/formats/iso/writer.rb +543 -0
  326. data/lib/omnizip/formats/iso.rb +133 -0
  327. data/lib/omnizip/formats/lzip.rb +161 -0
  328. data/lib/omnizip/formats/lzma_alone.rb +149 -0
  329. data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
  330. data/lib/omnizip/formats/msi/constants.rb +157 -0
  331. data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
  332. data/lib/omnizip/formats/msi/entry.rb +134 -0
  333. data/lib/omnizip/formats/msi/reader.rb +301 -0
  334. data/lib/omnizip/formats/msi/string_pool.rb +246 -0
  335. data/lib/omnizip/formats/msi/table_parser.rb +244 -0
  336. data/lib/omnizip/formats/msi.rb +73 -0
  337. data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
  338. data/lib/omnizip/formats/ole/constants.rb +61 -0
  339. data/lib/omnizip/formats/ole/dirent.rb +439 -0
  340. data/lib/omnizip/formats/ole/header.rb +199 -0
  341. data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
  342. data/lib/omnizip/formats/ole/storage.rb +482 -0
  343. data/lib/omnizip/formats/ole/types/variant.rb +338 -0
  344. data/lib/omnizip/formats/ole.rb +143 -0
  345. data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
  346. data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
  347. data/lib/omnizip/formats/rar/block_parser.rb +282 -0
  348. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  349. data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
  350. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
  351. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
  352. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  353. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  354. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  355. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  356. data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
  357. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
  358. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
  359. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
  360. data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
  361. data/lib/omnizip/formats/rar/compression.rb +17 -0
  362. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  363. data/lib/omnizip/formats/rar/constants.rb +88 -0
  364. data/lib/omnizip/formats/rar/decompressor.rb +316 -0
  365. data/lib/omnizip/formats/rar/external_writer.rb +311 -0
  366. data/lib/omnizip/formats/rar/header.rb +209 -0
  367. data/lib/omnizip/formats/rar/license_validator.rb +111 -0
  368. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  369. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  370. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  371. data/lib/omnizip/formats/rar/models.rb +14 -0
  372. data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
  373. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
  374. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
  375. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  376. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  377. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
  378. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  379. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
  380. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  381. data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
  382. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  383. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  384. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  385. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  386. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  387. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
  388. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  389. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
  390. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
  391. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
  392. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  393. data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
  394. data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
  395. data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
  396. data/lib/omnizip/formats/rar/reader.rb +377 -0
  397. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  398. data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
  399. data/lib/omnizip/formats/rar/writer.rb +437 -0
  400. data/lib/omnizip/formats/rar.rb +193 -0
  401. data/lib/omnizip/formats/rar3/compressor.rb +71 -0
  402. data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
  403. data/lib/omnizip/formats/rar3/reader.rb +107 -0
  404. data/lib/omnizip/formats/rar3/writer.rb +220 -0
  405. data/lib/omnizip/formats/rar3.rb +15 -0
  406. data/lib/omnizip/formats/rar5/compressor.rb +71 -0
  407. data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
  408. data/lib/omnizip/formats/rar5/reader.rb +130 -0
  409. data/lib/omnizip/formats/rar5/writer.rb +65 -0
  410. data/lib/omnizip/formats/rar5.rb +15 -0
  411. data/lib/omnizip/formats/rpm/constants.rb +58 -0
  412. data/lib/omnizip/formats/rpm/entry.rb +106 -0
  413. data/lib/omnizip/formats/rpm/header.rb +106 -0
  414. data/lib/omnizip/formats/rpm/lead.rb +132 -0
  415. data/lib/omnizip/formats/rpm/tag.rb +228 -0
  416. data/lib/omnizip/formats/rpm/writer.rb +652 -0
  417. data/lib/omnizip/formats/rpm.rb +458 -0
  418. data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
  419. data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
  420. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  421. data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
  422. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
  423. data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
  424. data/lib/omnizip/formats/seven_zip/header.rb +102 -0
  425. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
  426. data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
  427. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  428. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
  429. data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
  430. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  431. data/lib/omnizip/formats/seven_zip/models.rb +20 -0
  432. data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
  433. data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
  434. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
  435. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
  436. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  437. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
  438. data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
  439. data/lib/omnizip/formats/seven_zip.rb +179 -0
  440. data/lib/omnizip/formats/tar/constants.rb +73 -0
  441. data/lib/omnizip/formats/tar/entry.rb +98 -0
  442. data/lib/omnizip/formats/tar/header.rb +206 -0
  443. data/lib/omnizip/formats/tar/reader.rb +119 -0
  444. data/lib/omnizip/formats/tar/writer.rb +212 -0
  445. data/lib/omnizip/formats/tar.rb +74 -0
  446. data/lib/omnizip/formats/xar/constants.rb +119 -0
  447. data/lib/omnizip/formats/xar/entry.rb +268 -0
  448. data/lib/omnizip/formats/xar/header.rb +223 -0
  449. data/lib/omnizip/formats/xar/reader.rb +400 -0
  450. data/lib/omnizip/formats/xar/toc.rb +570 -0
  451. data/lib/omnizip/formats/xar/writer.rb +461 -0
  452. data/lib/omnizip/formats/xar.rb +145 -0
  453. data/lib/omnizip/formats/xz/reader.rb +121 -0
  454. data/lib/omnizip/formats/xz/writer.rb +416 -0
  455. data/lib/omnizip/formats/xz.rb +210 -0
  456. data/lib/omnizip/formats/xz_const.rb +49 -0
  457. data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
  458. data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
  459. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  460. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
  461. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  462. data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
  463. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
  464. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
  465. data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
  466. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
  467. data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
  468. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
  469. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  470. data/lib/omnizip/formats/xz_impl.rb +52 -0
  471. data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
  472. data/lib/omnizip/formats/zip/constants.rb +69 -0
  473. data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
  474. data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
  475. data/lib/omnizip/formats/zip/reader.rb +376 -0
  476. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  477. data/lib/omnizip/formats/zip/writer.rb +489 -0
  478. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
  479. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
  480. data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
  481. data/lib/omnizip/formats/zip.rb +50 -0
  482. data/lib/omnizip/formats.rb +29 -0
  483. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  484. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  485. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  486. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  487. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  488. data/lib/omnizip/implementations/base.rb +19 -0
  489. data/lib/omnizip/implementations/rust/archive.rb +93 -0
  490. data/lib/omnizip/implementations/rust/library.rb +221 -0
  491. data/lib/omnizip/implementations/rust.rb +26 -0
  492. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
  493. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
  494. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
  495. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
  496. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
  497. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
  498. data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
  499. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
  500. data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
  501. data/lib/omnizip/implementations/seven_zip.rb +11 -0
  502. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
  503. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
  504. data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
  505. data/lib/omnizip/implementations/xz_utils.rb +10 -0
  506. data/lib/omnizip/implementations.rb +25 -0
  507. data/lib/omnizip/io/buffered_input.rb +147 -0
  508. data/lib/omnizip/io/buffered_output.rb +106 -0
  509. data/lib/omnizip/io/source.rb +143 -0
  510. data/lib/omnizip/io/stream_manager.rb +117 -0
  511. data/lib/omnizip/io.rb +15 -0
  512. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  513. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  514. data/lib/omnizip/link_handler.rb +129 -0
  515. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  516. data/lib/omnizip/metadata/entry_metadata.rb +153 -0
  517. data/lib/omnizip/metadata/metadata_editor.rb +169 -0
  518. data/lib/omnizip/metadata/metadata_registry.rb +71 -0
  519. data/lib/omnizip/metadata/metadata_validator.rb +101 -0
  520. data/lib/omnizip/metadata.rb +58 -0
  521. data/lib/omnizip/models/.keep +0 -0
  522. data/lib/omnizip/models/algorithm_metadata.rb +41 -0
  523. data/lib/omnizip/models/attribute_apply.rb +40 -0
  524. data/lib/omnizip/models/compression_options.rb +53 -0
  525. data/lib/omnizip/models/conversion_options.rb +79 -0
  526. data/lib/omnizip/models/conversion_result.rb +141 -0
  527. data/lib/omnizip/models/eta_result.rb +45 -0
  528. data/lib/omnizip/models/extraction_rule.rb +115 -0
  529. data/lib/omnizip/models/filter_chain.rb +142 -0
  530. data/lib/omnizip/models/filter_config.rb +148 -0
  531. data/lib/omnizip/models/match_result.rb +141 -0
  532. data/lib/omnizip/models/optimization_suggestion.rb +95 -0
  533. data/lib/omnizip/models/parallel_options.rb +116 -0
  534. data/lib/omnizip/models/performance_result.rb +85 -0
  535. data/lib/omnizip/models/profile_report.rb +116 -0
  536. data/lib/omnizip/models/progress_options.rb +39 -0
  537. data/lib/omnizip/models/split_options.rb +116 -0
  538. data/lib/omnizip/optimization_registry.rb +45 -0
  539. data/lib/omnizip/parallel/engine.rb +52 -0
  540. data/lib/omnizip/parallel/job_queue.rb +209 -0
  541. data/lib/omnizip/parallel/job_scheduler.rb +225 -0
  542. data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
  543. data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
  544. data/lib/omnizip/parallel/thread_pool.rb +60 -0
  545. data/lib/omnizip/parallel/worker_pool.rb +227 -0
  546. data/lib/omnizip/parallel.rb +156 -0
  547. data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
  548. data/lib/omnizip/parity/galois16.rb +145 -0
  549. data/lib/omnizip/parity/models/creator_packet.rb +71 -0
  550. data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
  551. data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
  552. data/lib/omnizip/parity/models/main_packet.rb +126 -0
  553. data/lib/omnizip/parity/models/packet.rb +156 -0
  554. data/lib/omnizip/parity/models/packet_registry.rb +102 -0
  555. data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
  556. data/lib/omnizip/parity/models.rb +27 -0
  557. data/lib/omnizip/parity/par2_creator.rb +496 -0
  558. data/lib/omnizip/parity/par2_repairer.rb +409 -0
  559. data/lib/omnizip/parity/par2_verifier.rb +373 -0
  560. data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
  561. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  562. data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
  563. data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
  564. data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
  565. data/lib/omnizip/parity.rb +207 -0
  566. data/lib/omnizip/password/encryption_registry.rb +26 -0
  567. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  568. data/lib/omnizip/password/password_validator.rb +129 -0
  569. data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
  570. data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
  571. data/lib/omnizip/password.rb +88 -0
  572. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  573. data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
  574. data/lib/omnizip/pipe.rb +120 -0
  575. data/lib/omnizip/platform/ntfs_streams.rb +200 -0
  576. data/lib/omnizip/platform.rb +189 -0
  577. data/lib/omnizip/profile/archive_profile.rb +36 -0
  578. data/lib/omnizip/profile/balanced_profile.rb +31 -0
  579. data/lib/omnizip/profile/binary_profile.rb +33 -0
  580. data/lib/omnizip/profile/compression_profile.rb +157 -0
  581. data/lib/omnizip/profile/custom_profile.rb +155 -0
  582. data/lib/omnizip/profile/fast_profile.rb +31 -0
  583. data/lib/omnizip/profile/maximum_profile.rb +31 -0
  584. data/lib/omnizip/profile/profile_detector.rb +108 -0
  585. data/lib/omnizip/profile/profile_registry.rb +160 -0
  586. data/lib/omnizip/profile/text_profile.rb +33 -0
  587. data/lib/omnizip/profile.rb +261 -0
  588. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  589. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  590. data/lib/omnizip/profiler/report_generator.rb +158 -0
  591. data/lib/omnizip/profiler.rb +192 -0
  592. data/lib/omnizip/progress/callback_reporter.rb +34 -0
  593. data/lib/omnizip/progress/console_reporter.rb +59 -0
  594. data/lib/omnizip/progress/log_reporter.rb +89 -0
  595. data/lib/omnizip/progress/operation_progress.rb +118 -0
  596. data/lib/omnizip/progress/progress_bar.rb +156 -0
  597. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  598. data/lib/omnizip/progress/progress_tracker.rb +215 -0
  599. data/lib/omnizip/progress/silent_reporter.rb +22 -0
  600. data/lib/omnizip/progress.rb +131 -0
  601. data/lib/omnizip/registry.rb +111 -0
  602. data/lib/omnizip/rubyzip_compat.rb +61 -0
  603. data/lib/omnizip/temp/safe_extract.rb +124 -0
  604. data/lib/omnizip/temp/temp_file.rb +123 -0
  605. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  606. data/lib/omnizip/temp.rb +184 -0
  607. data/lib/omnizip/version.rb +5 -0
  608. data/lib/omnizip/zip/entry.rb +160 -0
  609. data/lib/omnizip/zip/file.rb +485 -0
  610. data/lib/omnizip/zip/input_stream.rb +270 -0
  611. data/lib/omnizip/zip/output_stream.rb +320 -0
  612. data/lib/omnizip/zip.rb +23 -0
  613. data/lib/omnizip.rb +157 -0
  614. data/lib/tasks/msi_test_files.rake +66 -0
  615. data/lib/tasks/platform_gems.rake +147 -0
  616. data/lib/tasks/rust_backend.rake +48 -0
  617. data/readme-docs/advanced-features.adoc +514 -0
  618. data/readme-docs/api-usage.adoc +445 -0
  619. data/readme-docs/architecture.adoc +450 -0
  620. data/readme-docs/archive-formats.adoc +479 -0
  621. data/readme-docs/cli-usage.adoc +222 -0
  622. data/readme-docs/compression-algorithms.adoc +446 -0
  623. data/readme-docs/compression-profiles.adoc +247 -0
  624. data/readme-docs/encryption-checksums.adoc +328 -0
  625. data/readme-docs/format-converter.adoc +316 -0
  626. data/readme-docs/installation.adoc +228 -0
  627. data/readme-docs/par2-archives.adoc +608 -0
  628. data/readme-docs/performance-profiler.adoc +389 -0
  629. data/readme-docs/preprocessing-filters.adoc +280 -0
  630. data/vendor/libomnizip_ffi.so +0 -0
  631. data/xz-file-format-1.2.1.txt +1174 -0
  632. 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.