rubocop-dev_doc 0.10.3 → 0.10.4

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: 0ba7422e97cc011bf4700f5f6bfd1c87fd7e358c9c707baf73b5360abbf40129
4
- data.tar.gz: 10ced56ec89a8d05f3897c76ff85df357cb52a9dc97d155f7caf11b1917faaa6
3
+ metadata.gz: b11d7c80b04d4ef7ecbff606f3920260773ae1767ffcacab78e99663920ca9d7
4
+ data.tar.gz: eaae1ebc845ca76bc72a878916d1f096c5495ce16b9238734c823875b0ba2323
5
5
  SHA512:
6
- metadata.gz: 403c116d677b765d86ef3a8852b1087ffa5821a12a1db76f59343d067cfd6c942c4fe1ae69c65a67ae1ad24a07922e7312f2a4f2a84b5164e379f8928c90a57c
7
- data.tar.gz: 4bd0b0fb718cf6ac10540735e49077da57e0d34b54111dcc5fe9da0a531383546eb83a9300503a10612f7bb0f90b6f6434acf0b307ea6125316202563bd89a52
6
+ metadata.gz: 0c227078e2a29302744d3b14cd3058f5912b50831221b82d7ab8cb13885ffaf4bca0eb7e8784745bd470533190e6c522d3f69b28f7e64cc18f183d2a39d6dd19
7
+ data.tar.gz: b7f474e88689ce7bd672e735458b5b8e45c5c47448b44461b673a46b8ac4b74c997ccebf548b02b33460095214c2d6920211ffb621a82eca3e231d8f65898f4d
data/config/default.yml CHANGED
@@ -170,7 +170,7 @@ DevDoc/Rails/NoPerformLaterInModel:
170
170
  - "app/models/**/*.rb"
171
171
 
172
172
  DevDoc/Rails/EnumMustBeSymbolized:
173
- Description: "Pair every `enum :foo` with `enum_symbolize :foo` so the reader returns a symbol."
173
+ Description: "Declare enums with `enum_symbolize :foo, { … }` instead of a bare `enum`, so the attribute type is set before the enum and the reader returns a symbol."
174
174
  Enabled: true
175
175
  Include:
176
176
  - "app/models/**/*.rb"
@@ -436,6 +436,18 @@ Rails/SaveBang:
436
436
  Exclude:
437
437
  - "app/controllers/**/*"
438
438
 
439
+ # MySQL-oriented performance cop: it wants multiple ALTER TABLE operations on
440
+ # one table combined into `change_table :t, bulk: true` to avoid repeated
441
+ # full-table rewrites. That payoff is real on MySQL/MariaDB but marginal on
442
+ # PostgreSQL, where ALTER sub-commands are cheap metadata ops — and our projects
443
+ # run PostgreSQL. It also contradicts our own doctrine: the `bulk: true` form it
444
+ # demands trips DevDoc/Migration/AvoidColumnDefault (on the backfill `default:`)
445
+ # and Rails/ReversibleMigration (on `t.change_default`), neither disable-able
446
+ # inline, for the standard add-column-then-drop-default backfill — making the
447
+ # three rules mutually unsatisfiable. Off for all projects.
448
+ Rails/BulkChangeTable:
449
+ Enabled: false
450
+
439
451
  # Superseded by DevDoc/Style/CaseElseDecision below: same detection, but the
440
452
  # offense message carries the raise/report/fall-through decision framework
441
453
  # instead of upstream's "Missing else statement" (which teaches the wrong
@@ -2,44 +2,51 @@ module RuboCop
2
2
  module Cop
3
3
  module DevDoc
4
4
  module Rails
5
- # Every Rails `enum` declaration must be paired with `enum_symbolize`
6
- # so the reader returns a symbol instead of Rails' default string form.
5
+ # Rails `enum` must never be declared directly — use glib-web's
6
+ # `enum_symbolize :name, { }` declaring form instead.
7
7
  #
8
8
  # ## Rationale
9
- # Strings and symbols are not equal in Ruby (`:foo == 'foo'` is `false`).
10
- # Rails' `enum` macro defines a reader that returns the string form, so
11
- # downstream comparisons like `record.status == :active` silently fail.
12
- # Pairing `enum :status, …` with `enum_symbolize :status` overrides the
13
- # reader to hand back a symbol, eliminating the footgun.
9
+ # Two problems with a bare `enum`:
10
+ #
11
+ # 1. **Type.** `enum` resolves its attribute type by introspecting the
12
+ # DB column. When the column doesn't exist yet a not-yet-migrated
13
+ # column loaded on deploy, eager-loaded CI, or an un-migrated local
14
+ # DB — Rails raises "Undeclared attribute type for enum". Declaring
15
+ # the attribute up front (which `enum_symbolize` does, from the enum's
16
+ # own values) removes that dependency on the column.
17
+ # 2. **Reader.** `enum` defines a reader that returns the string form, so
18
+ # `record.status == :active` silently fails (`:foo == 'foo'` is
19
+ # false). `enum_symbolize` overrides the reader to return a symbol.
20
+ #
21
+ # The `enum_symbolize :name, { … }` form does both in one call — it
22
+ # declares the attribute, defines the enum, adds a presence validation,
23
+ # and symbolizes the reader — so neither footgun can be reintroduced by
24
+ # forgetting a pairing line.
14
25
  #
15
26
  # See `best_practices/backend/en/01a_defensive_programming.md` item 7.
16
27
  #
17
28
  # ❌
18
29
  # class Order < ApplicationRecord
19
30
  # enum :payment_status, { draft: 0, pending: 1, finalized: 2 }
31
+ # enum_symbolize :payment_status
20
32
  # end
21
33
  #
22
34
  # ✔
23
35
  # class Order < ApplicationRecord
24
- # enum :payment_status, { draft: 0, pending: 1, finalized: 2 }
25
- #
26
- # enum_symbolize :payment_status
36
+ # enum_symbolize :payment_status, { draft: 0, pending: 1, finalized: 2 }
27
37
  # end
28
38
  #
29
- # `enum_symbolize` accepts multiple names so several enums can be
30
- # paired in one call:
39
+ # Enum options pass straight through:
31
40
  #
32
41
  # ✔
33
- # enum_symbolize :payment_status, :finalize_intent
42
+ # enum_symbolize :finalize_intent, { unknown: 0, charge: 1 }, prefix: true
34
43
  #
35
44
  # Enums declared inside a concern's `included do` block are checked the
36
- # same way — the pairing must live in the same `included do` block,
37
- # which is also where it belongs so every includer gets both:
45
+ # same way:
38
46
  #
39
47
  # ✔
40
48
  # included do
41
- # enum :discount_type, DISCOUNT_TYPES
42
- # enum_symbolize :discount_type
49
+ # enum_symbolize :discount_type, DISCOUNT_TYPES
43
50
  # end
44
51
  #
45
52
  # @example
@@ -47,20 +54,16 @@ module RuboCop
47
54
  # enum :status, { active: 0, archived: 1 }
48
55
  #
49
56
  # # good
50
- # enum :status, { active: 0, archived: 1 }
51
- # enum_symbolize :status
57
+ # enum_symbolize :status, { active: 0, archived: 1 }
52
58
  class EnumMustBeSymbolized < Base
53
- MSG = 'Pair `enum :%<name>s` with `enum_symbolize :%<name>s` so the reader returns a symbol ' \
54
- '(see backend/01a_defensive_programming.md item 7).'.freeze
59
+ MSG = 'Declare enums with `enum_symbolize :%<name>s, { … }` instead of `enum`, so the ' \
60
+ 'attribute type is set before the enum (surviving a not-yet-migrated column) and the ' \
61
+ 'reader returns a symbol (see backend/01a_defensive_programming.md item 7).'.freeze
55
62
 
56
63
  def_node_matcher :enum_call, <<~PATTERN
57
64
  (send nil? :enum (sym $_) ...)
58
65
  PATTERN
59
66
 
60
- def_node_matcher :enum_symbolize_call, <<~PATTERN
61
- (send nil? :enum_symbolize $...)
62
- PATTERN
63
-
64
67
  def_node_matcher :included_block?, <<~PATTERN
65
68
  (block (send nil? :included) (args) _)
66
69
  PATTERN
@@ -83,28 +86,15 @@ module RuboCop
83
86
  return unless body
84
87
 
85
88
  statements = body.begin_type? ? body.children : [body]
86
- enum_decls, symbolized = scan(statements)
89
+ statements.each do |stmt|
90
+ next unless stmt.respond_to?(:send_type?) && stmt.send_type?
87
91
 
88
- enum_decls.each do |name, decl|
89
- next if symbolized.include?(name)
92
+ name = enum_call(stmt)
93
+ next unless name
90
94
 
91
- add_offense(decl, message: format(MSG, name: name))
95
+ add_offense(stmt, message: format(MSG, name: name))
92
96
  end
93
97
  end
94
-
95
- def scan(statements)
96
- sends = statements.select { |stmt| stmt.respond_to?(:send_type?) && stmt.send_type? }
97
- enum_decls = sends.filter_map { |stmt| (name = enum_call(stmt)) && [name, stmt] }
98
- symbolized = sends.flat_map { |stmt| symbolized_names(stmt) }
99
- [enum_decls, symbolized]
100
- end
101
-
102
- def symbolized_names(stmt)
103
- args = enum_symbolize_call(stmt)
104
- return [] unless args
105
-
106
- args.select(&:sym_type?).map(&:value)
107
- end
108
98
  end
109
99
  end
110
100
  end
@@ -1,5 +1,5 @@
1
1
  module RuboCop
2
2
  module DevDoc
3
- VERSION = "0.10.3".freeze
3
+ VERSION = "0.10.4".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-dev_doc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.3
4
+ version: 0.10.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - dev-doc contributors
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-07-09 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: activesupport
@@ -79,6 +80,8 @@ dependencies:
79
80
  - - ">="
80
81
  - !ruby/object:Gem::Version
81
82
  version: '2.29'
83
+ description:
84
+ email:
82
85
  executables: []
83
86
  extensions: []
84
87
  extra_rdoc_files: []
@@ -157,10 +160,12 @@ files:
157
160
  - lib/rubocop/dev_doc.rb
158
161
  - lib/rubocop/dev_doc/plugin.rb
159
162
  - lib/rubocop/dev_doc/version.rb
163
+ homepage:
160
164
  licenses: []
161
165
  metadata:
162
166
  default_lint_roller_plugin: RuboCop::DevDoc::Plugin
163
167
  rubygems_mfa_required: 'true'
168
+ post_install_message:
164
169
  rdoc_options: []
165
170
  require_paths:
166
171
  - lib
@@ -175,7 +180,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
175
180
  - !ruby/object:Gem::Version
176
181
  version: '0'
177
182
  requirements: []
178
- rubygems_version: 4.0.6
183
+ rubygems_version: 3.4.6
184
+ signing_key:
179
185
  specification_version: 4
180
186
  summary: RuboCop cops enforcing dev-doc best practices
181
187
  test_files: []