rubocop-kata 0.7.0 → 0.9.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
2
  SHA256:
3
- metadata.gz: 4d84b32b4beb311cd73ed3af609400cc07a4a1e7fb41258e813feab7a7477ae9
4
- data.tar.gz: 3038bc491f3197c6623f30f68742fda4008c4519cbacc2c95dc36e0ebc10276c
3
+ metadata.gz: 6c1ecc1a90d7d43dba2861011f7f9c8c1ecc97e71040908f1018df3199aca660
4
+ data.tar.gz: 216cb124bc0565ab89d5cf3ee52225e24771d6f4d0812e8a272b0fc14517e45e
5
5
  SHA512:
6
- metadata.gz: b38144839ec596e2f646f89f2c28328978cf030d7bbc9c31deccad49fe94ad9775e75a2af69d51961cfed832f3acc7b49c32c43f0830fc98d300c8033cda1230
7
- data.tar.gz: 5ab77b46b9eab5d756368860c1f40866111964217dc0fda9cda532c49574fc6472dc60fb2a091c1e3d54269b63266b956f4bfd9a900ad50528dae96a8a8dd3de
6
+ metadata.gz: 5a806b0b657d6fa01fe422361616304f6581e23e041f76a70d3dc33f61814a600a808439282417de3f8ea34d03612927fdfcbced3f18010b90660407ffa165f7
7
+ data.tar.gz: 687dd4b67fb477cd51e4440e79f7d81a020f4712c1802541447eb489f97be8fab728cb26460c947113a2789f1fddf1f0e93ecd9bad70d2eadd232cbe025bf74d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,129 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.0] - 2026-08-27
4
+
5
+ - The shared rule behind the naming cops is now explicit: compound syntax is
6
+ not the smell — multiple semantic concepts are. A name should name one thing,
7
+ not describe where it came from, what it manipulates, or which layer it
8
+ lives in.
9
+ - New `Kata/GoodClassName` replaces `Kata/AgentNoun` and the class half of
10
+ `Kata/NoUtilName`: a class names one object that exists in the model. It
11
+ keeps the doer check and its derived suggestions, adds junk-drawer names
12
+ matched whole or as a trailing segment (`Service` catches `InvoiceService`),
13
+ and flags names packing more than `MaxWords` concepts
14
+ (`CustomerOrderPayment`) unless `Terms` blesses them as one concept
15
+ (`CreditCard`). The default `Terms` ships the established technical
16
+ compounds: `AbstractSyntaxTree`, `RedBlackTree`, `UnitOfWork`,
17
+ `TimeWithZone`, `HashWithIndifferentAccess` and kin.
18
+ - New `Kata/GoodModuleName` replaces the module half of `Kata/NoUtilName`: a
19
+ module names a domain vocabulary, not an implementation category. Layer
20
+ buckets (`Services`, `Helpers`, `Logic` — so `BusinessLogic` too), vague
21
+ shared namespaces (`Common`, `Shared`, `Core`), doer modules, and crowded
22
+ names are flagged; `AccessControl` and `Billing` pass.
23
+ - `Kata/GoodMethodName` flags names chaining actions with a conjunction
24
+ (`validate_and_save`, `find_or_create`): each action wants its own method.
25
+ Traversal names (`customer_address`) were already priced by the word rule;
26
+ the message stays advisory — the cop cannot know your object model.
27
+ - `Kata/GoodMethodName` and `Kata/GoodVariableName` bless grammatical
28
+ suffixes `id` and `ms` (`user_id`, `timeout_ms`) alongside `at`, the role
29
+ prefixes `max`/`min`/`start`/`end` (`max_retries`, `start_time`), and ship
30
+ established lexical compounds and protocol vocabulary as default `Terms`:
31
+ `first_name`, `postal_code`, `time_zone`, `ip_address`, `user_agent`,
32
+ `mime_type`, `status_code`, `access_token` and kin — names that read as one
33
+ concept. Where names must mirror an external schema, `Exclude` the file:
34
+ the file is the boundary.
35
+ - The defaults were then pressure-tested against corpora of real stdlib, gem,
36
+ Rails, and business-domain names, and grew to absorb what any codebase hits:
37
+ role suffixes (`number`, `code`, `price`, `rate`, `date`, `path`, `url`,
38
+ `count`, `size`, `key`, `token`, `params`, `secret`, `level`, `file`, `dir`,
39
+ `period`, `seconds`, `cents`), role prefixes (`current`, `default`, `total`,
40
+ `new`, `other`, `raw`, `set`, `sort`, `expected`, `actual`, `assert`),
41
+ domain terms (`line_item`, `credit_card`, `payment_method`,
42
+ `billing_address`, `date_of_birth`, `dry_run`, `stack_trace` and kin), and
43
+ the contract names of Ruby, Rails, Sidekiq, Devise, Pundit and RSpec
44
+ (`perform_async`, `deconstruct_keys`, `authenticate_user!`, `policy_scope`,
45
+ `failure_message` and kin). Name suffixes that would bless owner+property
46
+ (`name`, `message`, `amount`) stayed out on purpose: `user_name` and
47
+ `error_message` are still priced.
48
+ - `Kata/GoodClassName` `AllowedNames` also covers the class families a
49
+ framework resolves or subclasses by name (`Validator`, `Decorator`,
50
+ `Presenter`, `Helper`, `Job`, `Logger`, `Delegator`, `Enumerator`,
51
+ `Driver`) and more thing-words (`Center`, `Transfer`);
52
+ `Kata/GoodModuleName` mirrors the class cop's allowed list, and its
53
+ `BannedNames` grows the layer plurals (`Jobs`, `Workers`, `Queries`,
54
+ `Policies`, `Forms`, `Decorators`, `Presenters`, `Serializers`,
55
+ `Validators`, `Mixins`, `Extensions`).
56
+ - The doer check no longer flags thing-words that merely end in `-er`/`-or`:
57
+ `User`, `Order`, `Customer`, `Monitor`, `Buffer` and kin ship in
58
+ `Kata/GoodClassName` `AllowedNames`. `Kata/GoodModuleName` ships the
59
+ framework suffixes (`Controller`, `Mailer`, `Serializer`) so reopening
60
+ `ActionController` is not an offense. `Kata/GoodMethodName` exempts the
61
+ names Ruby and Rails resolve by contract: `method_missing`,
62
+ `respond_to_missing?`, `marshal_dump`, `deep_dup`, `table_name`,
63
+ `primary_key` and kin.
64
+
65
+ ## [0.8.0] - 2026-08-20
66
+
67
+ - New `rubocop-kata plan` command: buckets the backlog into `structure`,
68
+ `naming`, `prose` and `rest`, and names the stage to take next. Kata's
69
+ structural cops create names and its naming cops charge for them, so the net
70
+ offense count moves the wrong way mid-refactor and cannot be read as progress.
71
+ - New `rubocop-kata skill` command: prints an agent skill to stdout, so
72
+ redirecting it installs the skill wherever an agent reads them from. It works
73
+ the stage `plan` names one file at a time, checks every name it introduces
74
+ against the dictionary `Kata/RealWords` reads, and reports removed and
75
+ created separately.
76
+ - `Kata/AgentNoun` no longer truncates a compound to its prefix. Truncation is
77
+ not injective — `EvidencePoller`, `EvidenceValidator` and `EvidenceWaiter`
78
+ were each told to become `Evidence` — and it lands on names that already
79
+ exist elsewhere, which a per-file cop cannot see. It now derives the agent
80
+ word and keeps the rest, so `EvidenceValidator` suggests
81
+ `EvidenceValidation`, and stays quiet when no derivation applies.
82
+ - `Kata/AgentNoun` `AllowedNames` gains `Controller`, `Mailer` and
83
+ `Serializer`: suffixes a framework resolves a class by are contracts, not
84
+ naming choices.
85
+ - `Kata/EnvDiscipline` no longer flags `ENV` as a parameter default.
86
+ `def enabled?(env = ENV)` is the injection the cop asks for: the parameter
87
+ is the seam, and the default is what the boot layer would pass anyway.
88
+ - Every cop that excluded `spec/**/*` now excludes `test/**/*` too. Fifteen
89
+ cops shipped an RSpec-only exclusion, so a Minitest suite got the
90
+ production rules.
91
+ - The boot layer that `Kata/EnvDiscipline`, `Kata/IoDiscipline` and
92
+ `Kata/ClockDiscipline` exempt now covers an application's, not only a gem's:
93
+ `config/`, `db/seeds.rb`, `db/seeds/`, `lib/tasks/`, `Rakefile` and
94
+ `*.rake`, alongside `bin/` and `exe/`.
95
+ - `Kata/NoComments` now exempts `Gemfile` as it already exempts `*.gemspec`. A
96
+ dependency manifest cannot say why a dependency is pinned in code.
97
+ - `Metrics/MethodLength` counts an array, hash, heredoc or method call that
98
+ spans lines as one line. `Max: 5` and `Layout/LineLength: 120` were
99
+ otherwise unsatisfiable together: wrapping a long line spent method budget.
100
+ - `Layout/ArgumentAlignment` now uses `with_fixed_indentation`. Its default
101
+ aligns continuation arguments under the first argument's column, a step
102
+ `Elegant/MonotonicIndents` rejects.
103
+ - `Layout/EmptyLinesAroundAttributeAccessor` is off. It requires a blank line
104
+ after `attr_reader` where `Elegant/NoEmptyLinesInBlocks` forbids one; inside
105
+ an `included do` block the two autocorrect in a loop.
106
+ - `Lint/NumberConversion` is off. Its message names a replacement that
107
+ raises: `Integer(x, 10)` is only valid when `x` is a String, and a `.to_i`
108
+ receiver is usually a Time, a BigDecimal or an Integer.
109
+ - The five bundled cops that exempt test files now also match Rails'
110
+ `foo_test.rb`, `foo_spec.rb`, and suites addressed by directory. Upstream
111
+ matched `**/*Test.rb` and `**/test_*.rb` only.
112
+ - `Elegant/ClassInModule` is off. Its offenses cannot be cleared: it reports a
113
+ class nested in a class as global, and `Elegant/NoClassInModule` forbids the
114
+ module its message asks for, so the pair admits no shape. It also reads a
115
+ top-level constant as a defect, which is how Rails resolves one. Reported
116
+ upstream as yegor256/rubocop-elegant#75.
117
+ - `Elegant/PairedBrackets` autocorrect is off. It inserts a newline beside a
118
+ bracket without taking the whitespace already there, so corrected lines drift
119
+ right and `Elegant/MonotonicIndents` then reports the line it just wrote. The
120
+ rule still reports; fix the brackets by hand. Reported upstream as
121
+ yegor256/rubocop-elegant#76.
122
+ - Development runs against giacope/rubocop-elegant#fixes, the released gem plus
123
+ five open pull requests. A gemspec cannot name a git source, so consumers who
124
+ want the fixes rather than the workarounds add the same line to their own
125
+ Gemfile; the README says how.
126
+
3
127
  ## [0.7.0] - 2026-08-16
4
128
 
5
129
  - New `rubocop-kata doctor` command: reports `.rubocop.yml` entries that
data/README.md CHANGED
@@ -14,10 +14,10 @@ that dodge with a shipped dictionary instead of a word list you maintain:
14
14
 
15
15
  - **One dependency.** Bundles rubocop-rspec, rubocop-performance, rubocop-elegant, rubocop-packaging, and rubocop-thread_safety behind a single gem.
16
16
  - **Opinionated defaults.** Methods under 5 lines, classes under 100, 4 parameters max, 120-column lines, double quotes, `NewCops: enable`. See [config/default.yml](config/default.yml).
17
- - **Fifteen house cops.** Naming, dependency discipline, and data honesty in the Elegant Objects spirit — from `Kata/AgentNoun` to `Kata/ClockDiscipline`.
17
+ - **Fifteen house cops.** Naming, dependency discipline, and data honesty in the Elegant Objects spirit — from `Kata/GoodClassName` to `Kata/ClockDiscipline`.
18
18
 
19
19
  ```ruby
20
- class PaymentProcessor # Kata/AgentNoun: `PaymentProcessor` names a doer; name the class
20
+ class PaymentProcessor # Kata/GoodClassName: `PaymentProcessor` names a doer; name the class
21
21
  end # for the thing it is, not the work it does. Try `Payment`.
22
22
 
23
23
  class Payment # OK
@@ -53,17 +53,62 @@ bundle exec rubocop
53
53
 
54
54
  That's it. The plugin loads the bundled extensions and the shared defaults, so your `.rubocop.yml` keeps only what's specific to your project. Requires Ruby >= 3.4 and RuboCop ~> 1.75.
55
55
 
56
+ ### The bundled rubocop-elegant
57
+
58
+ The released `rubocop-elegant` 0.7.1 has four defects this project reported
59
+ upstream: `NoRedundantVariable` autocorrect corrupts Ruby 3.1 shorthand
60
+ ([#74](https://github.com/yegor256/rubocop-elegant/issues/74)), `ClassInModule`
61
+ reports a class nested in a class as global
62
+ ([#75](https://github.com/yegor256/rubocop-elegant/issues/75)),
63
+ `PairedBrackets` autocorrect drifts the indent
64
+ ([#76](https://github.com/yegor256/rubocop-elegant/issues/76)), and the
65
+ test-file exclusions never match a Rails or RSpec suite
66
+ ([#77](https://github.com/yegor256/rubocop-elegant/issues/77)).
67
+
68
+ The defaults here neutralise all four. `Elegant/ClassInModule` is off, because
69
+ its offences cannot be cleared: the cop it ships beside forbids the module it
70
+ asks for. The two broken correctors are set to report only, because their
71
+ offences can be cleared, by hand. The exclusions are widened. Nothing corrupts
72
+ your code out of the box, and nothing reports a defect you cannot fix.
73
+
74
+ A gemspec cannot name a git source, so to take the fixes themselves rather than
75
+ the workarounds, add this to your own `Gemfile`:
76
+
77
+ ```ruby
78
+ gem "rubocop-elegant", github: "giacope/rubocop-elegant", branch: "fixes"
79
+ ```
80
+
81
+ That branch is the released gem plus the five pull requests, with the version
82
+ pinned so Bundler resolves it. With it in place you can turn the two correctors
83
+ back on:
84
+
85
+ ```yaml
86
+ Elegant/NoRedundantVariable:
87
+ AutoCorrect: true
88
+
89
+ Elegant/PairedBrackets:
90
+ AutoCorrect: true
91
+
92
+ Elegant/ClassInModule:
93
+ Enabled: true
94
+ ```
95
+
96
+ Drop all three once upstream releases the fixes. On a Rails codebase, consider
97
+ leaving `Elegant/ClassInModule` off for good: it wants every class inside a
98
+ module, and Zeitwerk resolves `class Account` from `app/models/account.rb` as a
99
+ top-level constant by design.
100
+
56
101
  ## The cops
57
102
 
58
103
  | Cop | Default | What it enforces |
59
104
  | --- | --- | --- |
60
- | `Kata/AgentNoun` | on | Classes named for what they are, not `-er`/`-or` doers. Suggests the better name when it can derive one. `AllowedNames` matches a whole name or a trailing segment, so `Error` covers `UsageError`. |
105
+ | `Kata/GoodClassName` | on | A class names one object that exists in the model: no `-er`/`-or` doers (suggests the better name when it can derive one), no junk drawers (`Service`, `Util`, `Data`), no packing several concepts into one name (`CustomerOrderPayment`). Compound syntax is not the smell — `CreditCard` is one concept, and `Terms` holds those. `AllowedNames` and `BannedNames` match a whole name or a trailing segment, so `Error` covers `UsageError` and `Service` catches `InvoiceService`. |
106
+ | `Kata/GoodModuleName` | on | A module names a domain vocabulary (`Billing`, `AccessControl`), not an implementation category: no layer buckets (`Services`, `Helpers`, `Logic`), no vague shared namespaces (`Common`, `Shared`, `Core`), no doers. Tune via `BannedNames`/`Terms`/`AllowedNames`. |
61
107
  | `Kata/NoComments` | on | No prose comments; say it in the code. Magic comments, linter directives, and licence headers survive. Autocorrects. |
62
- | `Kata/IoDiscipline` | on | No bare `puts`/`warn`/`pp`/`p` outside specs/scripts; write through an injected `@io` or an explicit receiver. |
108
+ | `Kata/IoDiscipline` | on | No bare `puts`/`warn`/`pp`/`p` outside the test suite and the boot layer; write through an injected `@io` or an explicit receiver. |
63
109
  | `Kata/ProsePlacement` | off | Sentence-length strings belong in the presentation layer. Enable with an `Include`/`Exclude` matching your layering. |
64
- | `Kata/NoUtilName` | on | No junk-drawer names (`Util`, `Helper`, `Manager`, `Service`, …). Tune via `BannedNames`. |
65
110
  | `Kata/RealWords` | on | Every name segment is a word the shipped dictionary knows — `errorcount` (smash) and `cfg` (abbreviation) both fail, with no word list to maintain. Tune via `Terms`/`BannedWords`/`AllowedNames`. |
66
- | `Kata/GoodMethodName` | on | One word per method name; a second word needs a role prefix (`after_fork`), a role suffix (`file_of`), or a reviewed `Terms` entry. Tune via `MaxWords`/`Prefixes`/`Suffixes`/`Terms`/`AllowedNames`. |
111
+ | `Kata/GoodMethodName` | on | One word per method name; a second word needs a role prefix (`after_fork`), a role suffix (`file_of`), or a reviewed `Terms` entry. A name chaining actions (`validate_and_save`, `find_or_create`) is flagged as two methods in one. Tune via `MaxWords`/`Prefixes`/`Suffixes`/`Terms`/`AllowedNames`. |
67
112
  | `Kata/GoodVariableName` | on | The same rule for locals, parameters, ivars, class variables, and globals; `_name` and `@_name` stay exempt. |
68
113
  | `Kata/BuilderNoun` | on | Builders named for what they return: `total`, not `calculate_total`. Tune via `BannedPrefixes`/`AllowedNames`. |
69
114
  | `Kata/NoBooleanFlag` | on | No positional boolean arguments; split the method or use a keyword. |
@@ -71,7 +116,7 @@ That's it. The plugin loads the bundled extensions and the shared defaults, so y
71
116
  | `Kata/NoClassMethodLogic` | on | Class methods construct (`build`, `parse`, `of`, `from_*`); instances do the work. |
72
117
  | `Kata/NoHashAsObject` | on | A hash with `MaxKeys`+ keys (default 4) wants to be an object. Keyword-argument call sites exempt. |
73
118
  | `Kata/ClockDiscipline` | on | No bare `Time.now`/`Date.today`/`.current`; inject a clock. |
74
- | `Kata/EnvDiscipline` | on | `ENV` reads only in the boot layer (`config/`, `bin/`, `exe/`). |
119
+ | `Kata/EnvDiscipline` | on | `ENV` reads only in the boot layer (`config/`, `db/seeds*`, `lib/tasks/`, rake files, `bin/`, `exe/`) — or as a parameter default, which is the seam the cop asks for. |
75
120
 
76
121
  ## Dead configuration
77
122
 
@@ -92,6 +137,42 @@ lib/registry.rb:44: the directive names `Elegant/GoodMethodName`, which is not e
92
137
 
93
138
  It exits non-zero when it finds something, so it can gate CI.
94
139
 
140
+ ## Adoption order
141
+
142
+ Kata's structural cops create names and its naming cops charge for them, so a
143
+ structural refactor removes offenses and adds more. A single total cannot tell
144
+ progress from regression. `plan` buckets the backlog into the stages that cause
145
+ each other and names the one to take next.
146
+
147
+ ```sh
148
+ bundle exec rubocop-kata plan # or: plan path/to/project
149
+ ```
150
+
151
+ ```
152
+ structure 184 Kata/ConstructorDiscipline 92, Kata/NoHashAsObject 48, Kata/EnvDiscipline 44
153
+ naming 263 Kata/RealWords 141, Kata/GoodVariableName 88, Kata/GoodClassName 34
154
+ prose 57 Kata/NoComments 57
155
+ rest 412 Elegant/PairedBrackets 300, Layout/LineLength 112
156
+ next: structure — 184 offenses in 61 files; these mint the names `naming` then prices, so take them first
157
+ densest: app/models/account.rb (14)
158
+ ```
159
+
160
+ Structure before naming, because doing naming first means renaming things the
161
+ structural pass is about to move.
162
+
163
+ The gem also ships an agent skill that runs this loop: it works the stage `plan`
164
+ names, checks every name it introduces against the same dictionary
165
+ `Kata/RealWords` reads, and reports removed and created separately instead of a
166
+ net total.
167
+
168
+ ```sh
169
+ mkdir -p .claude/skills/rubocop-kata
170
+ bundle exec rubocop-kata skill > .claude/skills/rubocop-kata/SKILL.md
171
+ ```
172
+
173
+ It writes to stdout, so the same command installs it anywhere an agent reads
174
+ skills from — a project, `~/.claude/skills/`, or a plugin.
175
+
95
176
  ## The defaults
96
177
 
97
178
  Double-quoted strings, `Metrics/MethodLength: 5`, `Metrics/ClassLength: 100`,