iml 0.1.5 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b7e6733d34170f5e21e789e97e1bab6445ca7c27
4
- data.tar.gz: c4cb48f0dfed03e962079557cb6d1f2a8109b892
2
+ SHA256:
3
+ metadata.gz: 0df9f622d736c3aa7a80b02aa71d1b038dfb0a3f2f6f050d09a8a012c0e1c6fc
4
+ data.tar.gz: 72ae2f50c874deec6f145861114a14d4d3cff71a80dbbc74a127bd80d841958c
5
5
  SHA512:
6
- metadata.gz: 7aa32d2ce71502c7f83f7bf5b49cbd0278dabde6045aa92a00d72c1c08b655e48538b669630a16c6821641904ad69073d068fd81adaa0d0b1a929b7888656f1d
7
- data.tar.gz: 80793842a7767881a3e243d04f31f76b73f0786ab6c61272fca0af9f3c6d1a57828f97fda8796fd55ad4d96e83dbfc0dacc1fb8285ed91fb25dcc6e4c5c6208f
6
+ metadata.gz: ee56baf5a3197379b45cae3065881ef7f2a2517e60434c4cc54a16a55a8e9afd57ef8edf85f94c895e0256ed99ff7190d553a8113bd1acb7757f097b8865cb1e
7
+ data.tar.gz: 89aba00474efb6bda24faf7c9ba76c8b17cd6d691602a1f1712299c6c33c160fdf4578674d433f7daf4b79f93805d936e82b0d7b5a95b083df33fd2564a6df0c
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "WebFetch(domain:thepiratebay.org)"
5
+ ]
6
+ }
7
+ }
@@ -0,0 +1,30 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ ruby-version: ['3.1', '3.2', '3.3']
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Ruby
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby-version }}
24
+ bundler-cache: true
25
+
26
+ - name: Run tests
27
+ run: bundle exec rspec
28
+
29
+ - name: Run linter
30
+ run: bundle exec standardrb
@@ -0,0 +1,32 @@
1
+ name: Publish Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: write
10
+ packages: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ publish:
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Ruby
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: '3.3'
24
+ bundler-cache: true
25
+
26
+ - name: Publish to RubyGems
27
+ uses: rubygems/release-gem@v1
28
+
29
+ - name: Publish to GitHub Packages
30
+ env:
31
+ GEM_HOST_API_KEY: "Bearer ${{ secrets.GITHUB_TOKEN }}"
32
+ run: gem push --host https://rubygems.pkg.github.com/${{ github.repository_owner }} pkg/*.gem
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
6
 
data/Gemfile.lock CHANGED
@@ -1,87 +1,127 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- iml (0.1.5)
5
- activesupport (~> 5.2)
6
- nokogiri (~> 1.8)
7
- tqdm (~> 0.3)
4
+ iml (0.2.0)
8
5
 
9
6
  GEM
10
7
  remote: https://rubygems.org/
11
8
  specs:
12
- activesupport (5.2.0)
13
- concurrent-ruby (~> 1.0, >= 1.0.2)
14
- i18n (>= 0.7, < 2)
15
- minitest (~> 5.1)
16
- tzinfo (~> 1.1)
17
- addressable (2.5.2)
18
- public_suffix (>= 2.0.2, < 4.0)
19
- codeclimate-test-reporter (1.0.7)
20
- simplecov
21
- coderay (1.1.2)
22
- concurrent-ruby (1.0.5)
23
- crack (0.4.3)
24
- safe_yaml (~> 1.0.0)
25
- diff-lcs (1.3)
26
- docile (1.3.1)
27
- hashdiff (0.3.7)
28
- i18n (1.0.1)
29
- concurrent-ruby (~> 1.0)
30
- json (2.1.0)
31
- method_source (0.9.0)
32
- mini_portile2 (2.3.0)
33
- minitest (5.11.3)
34
- nokogiri (1.8.4)
35
- mini_portile2 (~> 2.3.0)
36
- pry (0.11.3)
37
- coderay (~> 1.1.0)
38
- method_source (~> 0.9.0)
39
- public_suffix (3.0.2)
40
- rake (12.3.1)
41
- rspec (3.7.0)
42
- rspec-core (~> 3.7.0)
43
- rspec-expectations (~> 3.7.0)
44
- rspec-mocks (~> 3.7.0)
45
- rspec-core (3.7.1)
46
- rspec-support (~> 3.7.0)
47
- rspec-expectations (3.7.0)
9
+ ast (2.4.3)
10
+ diff-lcs (1.6.2)
11
+ docile (1.4.1)
12
+ json (2.18.1)
13
+ language_server-protocol (3.17.0.5)
14
+ lint_roller (1.1.0)
15
+ parallel (1.27.0)
16
+ parser (3.3.10.1)
17
+ ast (~> 2.4.1)
18
+ racc
19
+ prism (1.9.0)
20
+ racc (1.8.1)
21
+ rainbow (3.1.1)
22
+ rake (13.3.1)
23
+ regexp_parser (2.11.3)
24
+ rspec (3.13.2)
25
+ rspec-core (~> 3.13.0)
26
+ rspec-expectations (~> 3.13.0)
27
+ rspec-mocks (~> 3.13.0)
28
+ rspec-core (3.13.6)
29
+ rspec-support (~> 3.13.0)
30
+ rspec-expectations (3.13.5)
48
31
  diff-lcs (>= 1.2.0, < 2.0)
49
- rspec-support (~> 3.7.0)
50
- rspec-mocks (3.7.0)
32
+ rspec-support (~> 3.13.0)
33
+ rspec-mocks (3.13.7)
51
34
  diff-lcs (>= 1.2.0, < 2.0)
52
- rspec-support (~> 3.7.0)
53
- rspec-support (3.7.1)
54
- safe_yaml (1.0.4)
55
- simplecov (0.16.1)
35
+ rspec-support (~> 3.13.0)
36
+ rspec-support (3.13.7)
37
+ rubocop (1.82.1)
38
+ json (~> 2.3)
39
+ language_server-protocol (~> 3.17.0.2)
40
+ lint_roller (~> 1.1.0)
41
+ parallel (~> 1.10)
42
+ parser (>= 3.3.0.2)
43
+ rainbow (>= 2.2.2, < 4.0)
44
+ regexp_parser (>= 2.9.3, < 3.0)
45
+ rubocop-ast (>= 1.48.0, < 2.0)
46
+ ruby-progressbar (~> 1.7)
47
+ unicode-display_width (>= 2.4.0, < 4.0)
48
+ rubocop-ast (1.49.0)
49
+ parser (>= 3.3.7.2)
50
+ prism (~> 1.7)
51
+ rubocop-performance (1.26.1)
52
+ lint_roller (~> 1.1)
53
+ rubocop (>= 1.75.0, < 2.0)
54
+ rubocop-ast (>= 1.47.1, < 2.0)
55
+ ruby-progressbar (1.13.0)
56
+ simplecov (0.22.0)
56
57
  docile (~> 1.1)
57
- json (>= 1.8, < 3)
58
- simplecov-html (~> 0.10.0)
59
- simplecov-html (0.10.2)
60
- thread_safe (0.3.6)
61
- tqdm (0.3.0)
62
- tzinfo (1.2.5)
63
- thread_safe (~> 0.1)
64
- vcr (4.0.0)
65
- webmock (3.4.2)
66
- addressable (>= 2.3.6)
67
- crack (>= 0.3.2)
68
- hashdiff
69
- yard (0.9.14)
58
+ simplecov-html (~> 0.11)
59
+ simplecov_json_formatter (~> 0.1)
60
+ simplecov-html (0.13.2)
61
+ simplecov_json_formatter (0.1.4)
62
+ standard (1.53.0)
63
+ language_server-protocol (~> 3.17.0.2)
64
+ lint_roller (~> 1.0)
65
+ rubocop (~> 1.82.0)
66
+ standard-custom (~> 1.0.0)
67
+ standard-performance (~> 1.8)
68
+ standard-custom (1.0.2)
69
+ lint_roller (~> 1.0)
70
+ rubocop (~> 1.50)
71
+ standard-performance (1.9.0)
72
+ lint_roller (~> 1.1)
73
+ rubocop-performance (~> 1.26.0)
74
+ unicode-display_width (3.2.0)
75
+ unicode-emoji (~> 4.1)
76
+ unicode-emoji (4.2.0)
77
+ yard (0.9.38)
70
78
 
71
79
  PLATFORMS
80
+ arm64-darwin-25
72
81
  ruby
73
82
 
74
83
  DEPENDENCIES
75
- bundler (~> 1.16)
76
- codeclimate-test-reporter (~> 1.0)
84
+ bundler (>= 2.4)
77
85
  iml!
78
- pry (~> 0.11)
79
- rake (~> 12.3)
80
- rspec (~> 3.7)
81
- simplecov (~> 0.16)
82
- vcr (~> 4.0)
83
- webmock (~> 3.4)
86
+ rake (~> 13.0)
87
+ rspec (~> 3.13)
88
+ simplecov (~> 0.22)
89
+ standard (~> 1.40)
84
90
  yard (~> 0.9)
85
91
 
92
+ CHECKSUMS
93
+ ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
94
+ diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
95
+ docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
96
+ iml (0.2.0)
97
+ json (2.18.1) sha256=fe112755501b8d0466b5ada6cf50c8c3f41e897fa128ac5d263ec09eedc9f986
98
+ language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
99
+ lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
100
+ parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
101
+ parser (3.3.10.1) sha256=06f6a725d2cd91e5e7f2b7c32ba143631e1f7c8ae2fb918fc4cebec187e6a688
102
+ prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
103
+ racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
104
+ rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
105
+ rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
106
+ regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
107
+ rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
108
+ rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
109
+ rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
110
+ rspec-mocks (3.13.7) sha256=0979034e64b1d7a838aaaddf12bf065ea4dc40ef3d4c39f01f93ae2c66c62b1c
111
+ rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
112
+ rubocop (1.82.1) sha256=09f1a6a654a960eda767aebea33e47603080f8e9c9a3f019bf9b94c9cab5e273
113
+ rubocop-ast (1.49.0) sha256=49c3676d3123a0923d333e20c6c2dbaaae2d2287b475273fddee0c61da9f71fd
114
+ rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
115
+ ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
116
+ simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
117
+ simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
118
+ simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
119
+ standard (1.53.0) sha256=f3c9493385db7079d0abce6f7582f553122156997b81258cd361d3480eeacf9c
120
+ standard-custom (1.0.2) sha256=424adc84179a074f1a2a309bb9cf7cd6bfdb2b6541f20c6bf9436c0ba22a652b
121
+ standard-performance (1.9.0) sha256=49483d31be448292951d80e5e67cdcb576c2502103c7b40aec6f1b6e9c88e3f2
122
+ unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
123
+ unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
124
+ yard (0.9.38) sha256=721fb82afb10532aa49860655f6cc2eaa7130889df291b052e1e6b268283010f
125
+
86
126
  BUNDLED WITH
87
- 1.16.2
127
+ 4.0.5
data/PLAN.md ADDED
@@ -0,0 +1,350 @@
1
+ # Plan: IML Gem Comprehensive Refactor
2
+
3
+ ## Phase 1: Modernize Dependencies and Tooling
4
+
5
+ ### Description
6
+ Update all dependencies to modern versions, replace Travis CI with GitHub Actions for testing, switch linting from RuboCop to StandardRB, and bump minimum Ruby version to 3.1+. This phase establishes the foundation for all subsequent changes.
7
+
8
+ ### Steps
9
+
10
+ #### Step 1.1: Update Ruby Version Requirement and Gemspec
11
+ - **Objective**: Bump minimum Ruby to 3.1, modernize gemspec structure
12
+ - **Files**: `iml.gemspec`, `gemspec.yml`, `.ruby-version` (create)
13
+ - **Dependencies**: None
14
+ - **Implementation**:
15
+ - Set `required_ruby_version` to `>= 3.1`
16
+ - Update `activesupport` from `~> 5.2` to `~> 7.1`
17
+ - Update `bundler` dev dependency to `~> 2.4`
18
+ - Update `rake` to `~> 13.0`
19
+ - Update `rspec` to `~> 3.13`
20
+ - Replace `simplecov ~> 0.16` with `simplecov ~> 0.22`
21
+ - Remove `codeclimate-test-reporter` (deprecated)
22
+ - Remove `pry` dependency (use `irb` or `debug` gem instead)
23
+ - Remove `tqdm` dependency (replace with Ruby-native progress in CLI)
24
+ - Add `standard ~> 1.40` as dev dependency
25
+ - Create `.ruby-version` file with `3.1.0`
26
+
27
+ #### Step 1.2: Replace Travis CI with GitHub Actions
28
+ - **Objective**: Modern CI pipeline with matrix testing
29
+ - **Files**: `.github/workflows/ci.yml` (create), `.travis.yml` (delete)
30
+ - **Dependencies**: Step 1.1
31
+ - **Implementation**:
32
+ - Create GitHub Actions workflow for CI (Ruby 3.1, 3.2, 3.3)
33
+ - Run `bundle exec rspec` and `bundle exec standardrb`
34
+ - Remove `.travis.yml`
35
+
36
+ #### Step 1.3: Switch Linting to StandardRB
37
+ - **Objective**: Replace RuboCop with StandardRB for zero-config linting
38
+ - **Files**: `.rubocop.yml` (delete), `.standard.yml` (create)
39
+ - **Dependencies**: Step 1.1
40
+ - **Implementation**:
41
+ - Remove `.rubocop.yml`
42
+ - Create `.standard.yml` if any overrides needed
43
+ - Update Rakefile to include StandardRB task
44
+
45
+ #### Step 1.4: Update Gemfile and Run Bundle Install
46
+ - **Objective**: Lock new dependency versions
47
+ - **Files**: `Gemfile`, `Gemfile.lock`
48
+ - **Dependencies**: Steps 1.1-1.3
49
+ - **Implementation**:
50
+ - Update Gemfile if needed
51
+ - Run `bundle install`
52
+ - Verify all dependencies resolve
53
+
54
+ ## Phase 2: Architecture Rewrite — Composition Over Inheritance
55
+
56
+ ### Description
57
+ Replace OpenStruct inheritance with plain Ruby objects using composition. Eliminate `method_missing` reliance in favor of explicit interfaces. Replace `IML::Hash` with a simple configuration object. This phase fundamentally restructures the core domain model.
58
+
59
+ ### Steps
60
+
61
+ #### Step 2.1: Create Configuration Module
62
+ - **Objective**: Replace `IML::Hash` and `IML::Patterns.config` with a proper configuration object
63
+ - **Files**: `lib/iml/configuration.rb` (create), `lib/iml/hash.rb` (delete)
64
+ - **Dependencies**: Phase 1 complete
65
+ - **Implementation**:
66
+ - Create `IML::Configuration` class that loads `patterns.yml`
67
+ - Use `Struct` or plain Ruby with explicit accessors instead of `HashWithIndifferentAccess`
68
+ - Provide `IML.configuration` singleton method
69
+ - Cache loaded config (load once, not on every pattern build)
70
+ - Remove dependency on `activesupport/core_ext/hash`
71
+
72
+ #### Step 2.2: Rewrite Pattern Builder
73
+ - **Objective**: Replace `method_missing`-based pattern building with explicit methods
74
+ - **Files**: `lib/iml/pattern_builder.rb` (create), `lib/iml/patterns.rb` (rewrite)
75
+ - **Dependencies**: Step 2.1
76
+ - **Implementation**:
77
+ - Create `IML::PatternBuilder` that constructs regex from config
78
+ - Explicit methods for each pattern component (`title_pattern`, `year_pattern`, etc.)
79
+ - Move pattern templates (movie/tv formats) into config or constants
80
+ - Remove `method_missing` / `respond_to_missing?` from patterns
81
+ - Return frozen Regexp objects
82
+
83
+ #### Step 2.3: Create Media Result Value Objects
84
+ - **Objective**: Replace OpenStruct-based Base/Movie/TVSeries with composition-based value objects
85
+ - **Files**: `lib/iml/media/result.rb` (create), `lib/iml/media/movie.rb` (create), `lib/iml/media/tv_series.rb` (create)
86
+ - **Dependencies**: Step 2.1
87
+ - **Implementation**:
88
+ - Create `IML::Media::Result` as a plain Ruby class with explicit attributes
89
+ - Use `Data.define` (Ruby 3.2+) or `Struct` for immutable value objects
90
+ - Compose with a `Formatter` for output path generation (not inherited)
91
+ - Compose with a `Normalizer` for codec/audio normalization
92
+ - `IML::Media::Movie` and `IML::Media::TvSeries` as specialized result types
93
+ - Remove all OpenStruct usage
94
+
95
+ #### Step 2.4: Create Formatter Service
96
+ - **Objective**: Extract output path formatting into a dedicated service
97
+ - **Files**: `lib/iml/formatter.rb` (create)
98
+ - **Dependencies**: Step 2.3
99
+ - **Implementation**:
100
+ - Create `IML::Formatter` that takes a result and format string
101
+ - `call(result, format: nil)` returns formatted string
102
+ - Placeholder definitions live with the formatter, not the model
103
+ - Support custom format strings
104
+
105
+ #### Step 2.5: Create Normalizer Service
106
+ - **Objective**: Extract codec/audio normalization into a dedicated service
107
+ - **Files**: `lib/iml/normalizer.rb` (create)
108
+ - **Dependencies**: Steps 2.1, 2.3
109
+ - **Implementation**:
110
+ - Create `IML::Normalizer` that normalizes codec and audio names
111
+ - `call(attributes)` returns normalized attribute hash
112
+ - Uses config for lookup tables
113
+ - Handles title case conversion
114
+
115
+ #### Step 2.6: Rewrite Parser (formerly Text)
116
+ - **Objective**: Replace `IML::Text < String` with a proper parser using composition
117
+ - **Files**: `lib/iml/parser.rb` (create), `lib/iml/text.rb` (delete)
118
+ - **Dependencies**: Steps 2.2, 2.3, 2.5
119
+ - **Implementation**:
120
+ - Create `IML::Parser` class (does not inherit from String)
121
+ - `parse(filename)` returns `Media::Movie`, `Media::TvSeries`, or `nil`
122
+ - Inject pattern builder and normalizer
123
+ - Clean separation: parsing, normalization, and result creation are distinct steps
124
+
125
+ #### Step 2.7: Create File Mover Service
126
+ - **Objective**: Extract file operations from Base into a dedicated service
127
+ - **Files**: `lib/iml/file_mover.rb` (create)
128
+ - **Dependencies**: Steps 2.3, 2.4
129
+ - **Implementation**:
130
+ - Create `IML::FileMover` service
131
+ - `call(source_path, result, format: nil, target: nil, pretend: false)`
132
+ - Handles directory creation, file moving, error handling
133
+ - Returns result object (success/failure) instead of integer codes
134
+
135
+ #### Step 2.8: Update Main Entry Point
136
+ - **Objective**: Wire up new architecture in `lib/iml.rb`
137
+ - **Files**: `lib/iml.rb` (rewrite)
138
+ - **Dependencies**: Steps 2.1-2.7
139
+ - **Implementation**:
140
+ - Remove old requires (text, base, movie, tvseries, hash)
141
+ - Add new requires (configuration, parser, formatter, normalizer, file_mover, media/*)
142
+ - Provide `IML.parse(filename)` convenience method
143
+ - Provide `IML.configuration` accessor
144
+ - Remove conditional `pry` require
145
+ - Remove `puts` for missing iml-imdb (use proper logging or silence)
146
+
147
+ #### Step 2.9: Delete Legacy Files
148
+ - **Objective**: Remove old architecture files
149
+ - **Files**: `lib/iml/base.rb`, `lib/iml/text.rb`, `lib/iml/movie.rb`, `lib/iml/tvseries.rb`, `lib/iml/hash.rb` (all delete)
150
+ - **Dependencies**: Steps 2.6-2.8
151
+ - **Implementation**:
152
+ - Delete all legacy class files
153
+ - Verify no remaining references
154
+
155
+ ## Phase 3: CLI Modernization
156
+
157
+ ### Description
158
+ Rewrite the CLI script to use the new architecture, add `--version` flag, remove `tqdm` dependency, and improve error handling.
159
+
160
+ ### Steps
161
+
162
+ #### Step 3.1: Rewrite CLI Script
163
+ - **Objective**: Modern CLI using new architecture with proper structure
164
+ - **Files**: `bin/iml` (rewrite)
165
+ - **Dependencies**: Phase 2 complete
166
+ - **Implementation**:
167
+ - Add `--version` / `-V` flag (print `IML::VERSION` and exit)
168
+ - Replace `tqdm` progress bar with simple STDERR output or `$stderr.print`
169
+ - Use `IML::Parser` and `IML::FileMover` services
170
+ - Move `file_operations` from top-level method into a CLI class or module
171
+ - Proper exit codes (0 success, 1 error)
172
+ - Replace `Logger.new(STDOUT)` with configurable logger
173
+ - Handle SIGINT gracefully
174
+
175
+ ## Phase 4: Remove ActiveSupport Dependency
176
+
177
+ ### Description
178
+ Replace remaining ActiveSupport usage with lightweight Ruby equivalents to eliminate the heavy dependency.
179
+
180
+ ### Steps
181
+
182
+ #### Step 4.1: Replace ActiveSupport Inflector
183
+ - **Objective**: Remove `titleize` dependency on ActiveSupport
184
+ - **Files**: `lib/iml/utils.rb` (create)
185
+ - **Dependencies**: Phase 2 complete
186
+ - **Implementation**:
187
+ - Create `IML::Utils.titleize(string)` — simple implementation
188
+ - Replace `.titleize` calls with `IML::Utils.titleize`
189
+ - Verify edge cases match expected behavior
190
+
191
+ #### Step 4.2: Remove HashWithIndifferentAccess Usage
192
+ - **Objective**: Eliminate remaining ActiveSupport hash dependency
193
+ - **Files**: Various (already handled in Phase 2 config rewrite)
194
+ - **Dependencies**: Step 2.1
195
+ - **Implementation**:
196
+ - Verify `IML::Configuration` uses plain Ruby hashes with string keys
197
+ - Use `transform_keys(&:to_s)` or `symbolize_keys` as needed
198
+ - Remove `require 'active_support/core_ext/hash'`
199
+
200
+ #### Step 4.3: Remove ActiveSupport from Gemspec
201
+ - **Objective**: Drop the activesupport runtime dependency entirely
202
+ - **Files**: `gemspec.yml`, `lib/iml.rb`
203
+ - **Dependencies**: Steps 4.1-4.2
204
+ - **Implementation**:
205
+ - Remove `activesupport` from dependencies in `gemspec.yml`
206
+ - Remove all `require 'active_support/*'` lines
207
+ - Run tests to verify nothing breaks
208
+
209
+ ## Phase 5: Comprehensive Test Suite
210
+
211
+ ### Description
212
+ Rewrite the test suite to match the new architecture with thorough coverage, proper organization, and `:verified` tags.
213
+
214
+ ### Steps
215
+
216
+ #### Step 5.1: Set Up Test Infrastructure
217
+ - **Objective**: Modern RSpec configuration with proper helpers
218
+ - **Files**: `spec/spec_helper.rb` (rewrite), `.rspec` (update)
219
+ - **Dependencies**: Phase 2 complete
220
+ - **Implementation**:
221
+ - Configure SimpleCov with minimum coverage threshold
222
+ - Add `:verified` tag filtering
223
+ - Set up shared contexts for common test data
224
+ - Create `spec/support/` directory for shared examples
225
+
226
+ #### Step 5.2: Test Configuration
227
+ - **Objective**: Full coverage of pattern configuration loading
228
+ - **Files**: `spec/configuration_spec.rb` (create)
229
+ - **Dependencies**: Step 5.1
230
+ - **Implementation**:
231
+ - Test config loads from YAML
232
+ - Test all config keys accessible
233
+ - Test caching behavior
234
+ - Test with missing/malformed config file
235
+
236
+ #### Step 5.3: Test Pattern Builder
237
+ - **Objective**: Full coverage of regex pattern construction
238
+ - **Files**: `spec/pattern_builder_spec.rb` (create)
239
+ - **Dependencies**: Step 5.1
240
+ - **Implementation**:
241
+ - Test each pattern component generates valid regex
242
+ - Test movie patterns match expected filenames
243
+ - Test TV patterns match expected filenames
244
+ - Test patterns reject non-matching filenames
245
+ - Edge cases: special characters, unusual formats
246
+
247
+ #### Step 5.4: Test Parser
248
+ - **Objective**: Comprehensive filename parsing tests
249
+ - **Files**: `spec/parser_spec.rb` (create)
250
+ - **Dependencies**: Step 5.1
251
+ - **Implementation**:
252
+ - Test movie detection with various formats
253
+ - Test TV series detection with various formats
254
+ - Test unrecognized filenames return nil
255
+ - Test edge cases: missing fields, unusual separators, 4K content
256
+ - Test with real-world filename examples
257
+
258
+ #### Step 5.5: Test Media Result Objects
259
+ - **Objective**: Full coverage of value objects
260
+ - **Files**: `spec/media/movie_spec.rb` (create), `spec/media/tv_series_spec.rb` (create)
261
+ - **Dependencies**: Step 5.1
262
+ - **Implementation**:
263
+ - Test attribute access
264
+ - Test immutability (if using Data.define)
265
+ - Test type predicates (`movie?`, `tv?`)
266
+ - Test season_i / episode_i for TV series
267
+
268
+ #### Step 5.6: Test Formatter
269
+ - **Objective**: Full coverage of output path formatting
270
+ - **Files**: `spec/formatter_spec.rb` (create)
271
+ - **Dependencies**: Step 5.1
272
+ - **Implementation**:
273
+ - Test default format strings for movie and TV
274
+ - Test custom format strings
275
+ - Test all placeholder substitutions
276
+ - Test with missing attributes (graceful handling)
277
+
278
+ #### Step 5.7: Test Normalizer
279
+ - **Objective**: Full coverage of codec/audio normalization
280
+ - **Files**: `spec/normalizer_spec.rb` (create)
281
+ - **Dependencies**: Step 5.1
282
+ - **Implementation**:
283
+ - Test video codec normalization (x264 -> h.264, etc.)
284
+ - Test audio codec normalization with channels
285
+ - Test title case conversion
286
+ - Test unknown codecs pass through unchanged
287
+
288
+ #### Step 5.8: Test File Mover
289
+ - **Objective**: Full coverage of file operations
290
+ - **Files**: `spec/file_mover_spec.rb` (create)
291
+ - **Dependencies**: Step 5.1
292
+ - **Implementation**:
293
+ - Test directory creation
294
+ - Test file moving
295
+ - Test pretend mode (no actual operations)
296
+ - Test error handling (missing source, permission errors)
297
+ - Use tmpdir for actual file operations
298
+
299
+ #### Step 5.9: Delete Legacy Tests
300
+ - **Objective**: Remove old test file
301
+ - **Files**: `spec/iml_spec.rb` (delete)
302
+ - **Dependencies**: Steps 5.2-5.8
303
+ - **Implementation**:
304
+ - Delete monolithic test file
305
+ - Verify all test scenarios covered by new specs
306
+ - Run full suite to confirm green
307
+
308
+ ## Phase 6: Final Cleanup and Verification
309
+
310
+ ### Description
311
+ Run all linters and tests, verify the gem builds, update documentation, and ensure everything is release-ready.
312
+
313
+ ### Steps
314
+
315
+ #### Step 6.1: Run StandardRB and Fix Issues
316
+ - **Objective**: Zero linting warnings
317
+ - **Files**: Various (auto-fix)
318
+ - **Dependencies**: Phases 1-5 complete
319
+ - **Implementation**:
320
+ - Run `bundle exec standardrb --fix .`
321
+ - Review and manually fix any remaining issues
322
+ - Ensure all files have `frozen_string_literal: true`
323
+
324
+ #### Step 6.2: Run Full Test Suite
325
+ - **Objective**: All tests pass with good coverage
326
+ - **Files**: None (verification only)
327
+ - **Dependencies**: Step 6.1
328
+ - **Implementation**:
329
+ - Run `bundle exec rspec`
330
+ - Verify coverage meets threshold
331
+ - Fix any failures
332
+
333
+ #### Step 6.3: Build and Verify Gem
334
+ - **Objective**: Gem builds cleanly
335
+ - **Files**: None (verification only)
336
+ - **Dependencies**: Step 6.2
337
+ - **Implementation**:
338
+ - Run `gem build iml.gemspec`
339
+ - Verify gem file contents are correct
340
+ - Test `gem install` locally
341
+
342
+ #### Step 6.4: Update README
343
+ - **Objective**: Documentation reflects new architecture and usage
344
+ - **Files**: `README.md`
345
+ - **Dependencies**: Step 6.2
346
+ - **Implementation**:
347
+ - Update usage examples to new API (`IML.parse`)
348
+ - Update dependency requirements (Ruby 3.1+)
349
+ - Document new CLI flags (`--version`)
350
+ - Remove references to ActiveSupport