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 +4 -4
- data/config/default.yml +13 -1
- data/lib/rubocop/cop/dev_doc/rails/enum_must_be_symbolized.rb +33 -43
- data/lib/rubocop/dev_doc/version.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b11d7c80b04d4ef7ecbff606f3920260773ae1767ffcacab78e99663920ca9d7
|
|
4
|
+
data.tar.gz: eaae1ebc845ca76bc72a878916d1f096c5495ce16b9238734c823875b0ba2323
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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: "
|
|
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
|
-
#
|
|
6
|
-
#
|
|
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
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
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
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# enum_symbolize :payment_status
|
|
36
|
+
# enum_symbolize :payment_status, { draft: 0, pending: 1, finalized: 2 }
|
|
27
37
|
# end
|
|
28
38
|
#
|
|
29
|
-
#
|
|
30
|
-
# paired in one call:
|
|
39
|
+
# Enum options pass straight through:
|
|
31
40
|
#
|
|
32
41
|
# ✔
|
|
33
|
-
# enum_symbolize :
|
|
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
|
|
37
|
-
# which is also where it belongs so every includer gets both:
|
|
45
|
+
# same way:
|
|
38
46
|
#
|
|
39
47
|
# ✔
|
|
40
48
|
# included do
|
|
41
|
-
#
|
|
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
|
-
#
|
|
51
|
-
# enum_symbolize :status
|
|
57
|
+
# enum_symbolize :status, { active: 0, archived: 1 }
|
|
52
58
|
class EnumMustBeSymbolized < Base
|
|
53
|
-
MSG = '
|
|
54
|
-
'(
|
|
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
|
-
|
|
89
|
+
statements.each do |stmt|
|
|
90
|
+
next unless stmt.respond_to?(:send_type?) && stmt.send_type?
|
|
87
91
|
|
|
88
|
-
|
|
89
|
-
next
|
|
92
|
+
name = enum_call(stmt)
|
|
93
|
+
next unless name
|
|
90
94
|
|
|
91
|
-
add_offense(
|
|
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
|
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.
|
|
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:
|
|
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.
|
|
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: []
|