rubocop-dev_doc 0.10.1 → 0.10.2

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: f669dc6f7e91c7e3aaac4e42e680df95fc24acbf6b467e7831387866cc2dc0d4
4
- data.tar.gz: 41f06d6d2b20efd95b60389aae5f6803d206ad8f844d8de9daf04d87369ebf8f
3
+ metadata.gz: 6516cd758b54f702561cfd1ce43130ccf46bcfd04d8955bbdf065218019f374a
4
+ data.tar.gz: f246347aeb2054e19c26844f38057f795a1ee721a30c3c40b8f955d06b6f843a
5
5
  SHA512:
6
- metadata.gz: 7cdef60287b7ef58701aab3c5e025416b2033d93c3a09d06b6addc3636daaf169010584df484ec6377caa192d74d901ee52a0abf56473490c3f4e289cf6895ba
7
- data.tar.gz: 84a55b7ffaf35e17e8ee436c7f696c176659c30394fa7ed6a50a7bc46fa64ecbb2b5728a5df6547d457ba0006154e9279409b7fc2f6075f4937d0a0406a37ee6
6
+ metadata.gz: b30977f9056fd77d2a58227e98b2fc6860ad1333a52fb4bb9bf7ea636ab20ebca1ad9187a84a4ca3e14c8f442861ec3c779ddb88d9d940c459483bcf204726e0
7
+ data.tar.gz: 93ae91781dd10664b18b8e304e9b336485a572bd9a32822af81df3e399fb742420ed1d41612e21e4249eb79cbc53569082468091c8994470f552bf43dd7c7b8d
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
@@ -0,0 +1,5 @@
1
+ # Cop renames across rubocop-dev_doc versions. RuboCop surfaces these as
2
+ # actionable "has been renamed" errors when a project's config or inline
3
+ # directives use the old name.
4
+ renamed:
5
+ DevDoc/Migration/AvoidBypassingValidation: DevDoc/Rails/AvoidBypassingValidation
@@ -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.1".freeze
3
+ VERSION = "0.10.2".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +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.1
4
+ version: 0.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - dev-doc contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-07 00:00:00.000000000 Z
11
+ date: 2026-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -87,6 +87,7 @@ extensions: []
87
87
  extra_rdoc_files: []
88
88
  files:
89
89
  - config/default.yml
90
+ - config/obsoletion.yml
90
91
  - lib/dev_doc/test/best_practice_lints.rb
91
92
  - lib/dev_doc/test/lints/cron_schedule.rb
92
93
  - lib/dev_doc/test/lints/duplicate_snapshot.rb