sevencop 0.20.1 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/Gemfile.lock +13 -1
  4. data/README.md +19 -4
  5. data/config/default.yml +163 -0
  6. data/lib/rubocop/cop/sevencop/factory_bot_association_option.rb +89 -0
  7. data/lib/rubocop/cop/sevencop/factory_bot_association_style.rb +167 -0
  8. data/lib/rubocop/cop/sevencop/rails_inferred_spec_type.rb +1 -1
  9. data/lib/rubocop/cop/sevencop/rails_migration_add_check_constraint.rb +111 -0
  10. data/lib/rubocop/cop/sevencop/rails_migration_add_column_with_default_value.rb +229 -0
  11. data/lib/rubocop/cop/sevencop/rails_migration_add_foreign_key.rb +166 -0
  12. data/lib/rubocop/cop/sevencop/rails_migration_add_index_concurrently.rb +164 -0
  13. data/lib/rubocop/cop/sevencop/rails_migration_batch_in_batches.rb +95 -0
  14. data/lib/rubocop/cop/sevencop/rails_migration_batch_in_transaction.rb +83 -0
  15. data/lib/rubocop/cop/sevencop/rails_migration_batch_with_throttling.rb +108 -0
  16. data/lib/rubocop/cop/sevencop/rails_migration_change_column.rb +113 -0
  17. data/lib/rubocop/cop/sevencop/rails_migration_change_column_null.rb +128 -0
  18. data/lib/rubocop/cop/sevencop/rails_migration_create_table_force.rb +89 -0
  19. data/lib/rubocop/cop/sevencop/rails_migration_jsonb.rb +131 -0
  20. data/lib/rubocop/cop/sevencop/rails_migration_remove_column.rb +258 -0
  21. data/lib/rubocop/cop/sevencop/rails_migration_rename_column.rb +81 -0
  22. data/lib/rubocop/cop/sevencop/rails_migration_rename_table.rb +79 -0
  23. data/lib/rubocop/cop/sevencop/rails_migration_reserved_word_mysql.rb +2 -19
  24. data/lib/rubocop/cop/sevencop/rails_migration_unique_index_columns_count.rb +92 -0
  25. data/lib/sevencop/config_loader.rb +11 -10
  26. data/lib/sevencop/cop_concerns/batch_processing.rb +32 -0
  27. data/lib/sevencop/cop_concerns/column_type_method.rb +26 -0
  28. data/lib/sevencop/cop_concerns/disable_ddl_transaction.rb +49 -0
  29. data/lib/sevencop/cop_concerns.rb +3 -0
  30. data/lib/sevencop/rubocop_extension.rb +6 -1
  31. data/lib/sevencop/version.rb +1 -1
  32. data/lib/sevencop.rb +17 -0
  33. data/sevencop.gemspec +1 -0
  34. metadata +36 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22e21f2ba7c484fc1fd0d23b9b7d4dcf70d3e0f2f5f764e95e6dc65d10c419e9
4
- data.tar.gz: b689a364af2f7728c3947575d4edcc5f79a9ce3767fa769acf4829587fa9e63c
3
+ metadata.gz: e2aff4e0e776ef3fa5b3f71ece7b7c83013caadaf829fc86827ab246f5f80382
4
+ data.tar.gz: 1889785ce282e4d530c7eef4a54afaa948181b1557e788425e9b30e831935b77
5
5
  SHA512:
6
- metadata.gz: 9cab7cab01a11e6c9ea1de15a97ae4ea6c8315dc4c4a2304d4ee1178775dd8526cccd2a42cdca9d30069936e816bde32cd58451e157fa85b737bb2bfa5368465
7
- data.tar.gz: 0040a81647501bcb03ee0f0bd0f97722b2483c202751debc7a530d58677a4d822e73039803a6066d1d6085e2dcd7c9a06fead8c06991e2b14afdc927ebd8b07b
6
+ metadata.gz: 386a275378516b205cbd1dc4d50226776d106dc98eb8c534973ff7379c39b59f0e49ae4985058f79254d2256a09ac459b6357e1c5d0f03a8e2d780ec8b1fc990
7
+ data.tar.gz: 91adea811d280655577fd88cdb4b861b3a9e04f4c89d9542a4ce38281f325cfe0be590cb45ce8937375b4d13e67970518e6381531f46087689e58f3b8d0c5156
data/.rubocop.yml CHANGED
@@ -13,6 +13,9 @@ AllCops:
13
13
  Gemspec/RequireMFA:
14
14
  Enabled: false
15
15
 
16
+ Layout/LineLength:
17
+ Enabled: false
18
+
16
19
  Metrics:
17
20
  Enabled: false
18
21
 
@@ -49,6 +52,9 @@ Sevencop/MethodDefinitionKeywordArgumentOrdered:
49
52
  Sevencop/MethodDefinitionOrdered:
50
53
  Enabled: true
51
54
 
55
+ Sevencop/RequireOrdered:
56
+ Enabled: true
57
+
52
58
  Style/Documentation:
53
59
  Enabled: false
54
60
 
data/Gemfile.lock CHANGED
@@ -1,15 +1,25 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sevencop (0.20.1)
4
+ sevencop (0.22.0)
5
+ activesupport
5
6
  rubocop
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
11
+ activesupport (7.0.4)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
10
16
  ast (2.4.2)
17
+ concurrent-ruby (1.1.10)
11
18
  diff-lcs (1.5.0)
19
+ i18n (1.12.0)
20
+ concurrent-ruby (~> 1.0)
12
21
  json (2.6.2)
22
+ minitest (5.16.3)
13
23
  parallel (1.22.1)
14
24
  parser (3.1.2.1)
15
25
  ast (~> 2.4.1)
@@ -50,6 +60,8 @@ GEM
50
60
  rubocop-rspec (2.13.1)
51
61
  rubocop (~> 1.33)
52
62
  ruby-progressbar (1.11.0)
63
+ tzinfo (2.0.5)
64
+ concurrent-ruby (~> 1.0)
53
65
  unicode-display_width (2.3.0)
54
66
 
55
67
  PLATFORMS
data/README.md CHANGED
@@ -24,11 +24,13 @@ Sevencop/MethodDefinitionOrdered:
24
24
  Enabled: true
25
25
  ```
26
26
 
27
- ## Cops
27
+ Note that all cops are `Enabled: false` by default.
28
28
 
29
- Choose the cops you want to use and enable them on your .rubocop.yml.
29
+ ## Cops
30
30
 
31
31
  - [Sevencop/AutoloadOrdered](lib/rubocop/cop/sevencop/autoload_ordered.rb)
32
+ - [Sevencop/FactoryBotAssociationOption](lib/rubocop/cop/sevencop/factory_bot_association_option.rb)
33
+ - [Sevencop/FactoryBotAssociationStyle](lib/rubocop/cop/sevencop/factory_bot_association_style.rb)
32
34
  - [Sevencop/HashElementOrdered](lib/rubocop/cop/sevencop/hash_element_ordered.rb)
33
35
  - [Sevencop/MethodDefinitionArgumentsMultiline](lib/rubocop/cop/sevencop/method_definition_arguments_multiline.rb)
34
36
  - [Sevencop/MethodDefinitionInIncluded](lib/rubocop/cop/sevencop/method_definition_in_included.rb)
@@ -36,12 +38,25 @@ Choose the cops you want to use and enable them on your .rubocop.yml.
36
38
  - [Sevencop/MethodDefinitionOrdered](lib/rubocop/cop/sevencop/method_definition_ordered.rb)
37
39
  - [Sevencop/RailsBelongsToOptional](lib/rubocop/cop/sevencop/rails_belongs_to_optional.rb)
38
40
  - [Sevencop/RailsInferredSpecType](lib/rubocop/cop/sevencop/rails_inferred_spec_type.rb)
41
+ - [Sevencop/RailsMigrationAddCheckConstraint](lib/rubocop/cop/sevencop/rails_migration_add_check_constraint.rb)
42
+ - [Sevencop/RailsMigrationAddColumnWithDefaultValue](lib/rubocop/cop/sevencop/rails_migration_add_column_with_default_value.rb)
43
+ - [Sevencop/RailsMigrationAddForeignKey](lib/rubocop/cop/sevencop/rails_migration_add_foreign_key.rb)
44
+ - [Sevencop/RailsMigrationAddIndexConcurrently](lib/rubocop/cop/sevencop/rails_migration_add_index_concurrently.rb)
45
+ - [Sevencop/RailsMigrationBatchInBatches](lib/rubocop/cop/sevencop/rails_migration_batch_in_batches.rb)
46
+ - [Sevencop/RailsMigrationBatchInTransaction](lib/rubocop/cop/sevencop/rails_migration_batch_in_transaction.rb)
47
+ - [Sevencop/RailsMigrationBatchWithThrottling](lib/rubocop/cop/sevencop/rails_migration_batch_with_throttling.rb)
48
+ - [Sevencop/RailsMigrationChangeColumn](lib/rubocop/cop/sevencop/rails_migration_change_column.rb)
49
+ - [Sevencop/RailsMigrationChangeColumnNull](lib/rubocop/cop/sevencop/rails_migration_change_column_null.rb)
50
+ - [Sevencop/RailsMigrationCreateTableForce](lib/rubocop/cop/sevencop/rails_migration_create_table_force.rb)
51
+ - [Sevencop/RailsMigrationJsonb](lib/rubocop/cop/sevencop/rails_migration_jsonb.rb)
52
+ - [Sevencop/RailsMigrationRemoveColumn](lib/rubocop/cop/sevencop/rails_migration_remove_column.rb)
53
+ - [Sevencop/RailsMigrationRenameColumn](lib/rubocop/cop/sevencop/rails_migration_rename_column.rb)
54
+ - [Sevencop/RailsMigrationRenameTable](lib/rubocop/cop/sevencop/rails_migration_rename_table.rb)
39
55
  - [Sevencop/RailsMigrationReservedWordMysql](lib/rubocop/cop/sevencop/rails_migration_reserved_word_mysql.rb)
56
+ - [Sevencop/RailsMigrationUniqueIndexColumnsCount](lib/rubocop/cop/sevencop/rails_migration_unique_index_columns_count.rb)
40
57
  - [Sevencop/RailsOrderField](lib/rubocop/cop/sevencop/rails_order_field.rb)
41
58
  - [Sevencop/RailsUniquenessValidatorExplicitCaseSensitivity](lib/rubocop/cop/sevencop/rails_uniqueness_validator_explicit_case_sensitivity.rb)
42
59
  - [Sevencop/RailsWhereNot](lib/rubocop/cop/sevencop/rails_where_not.rb)
43
60
  - [Sevencop/RequireOrdered](lib/rubocop/cop/sevencop/require_ordered.rb)
44
61
  - [Sevencop/RSpecDescribeHttpEndpoint](lib/rubocop/cop/sevencop/rspec_describe_http_endpoint.rb)
45
62
  - [Sevencop/RSpecExamplesInSameGroup](lib/rubocop/cop/sevencop/rspec_examples_in_same_group.rb)
46
-
47
- Note that all cops are `Enabled: false` by default.
data/config/default.yml CHANGED
@@ -5,6 +5,35 @@ Sevencop/AutoloadOrdered:
5
5
  Safe: false
6
6
  VersionAdded: '0.12'
7
7
 
8
+ Sevencop/FactoryBotAssociationOptions:
9
+ Description: |
10
+ Remove redundant options from FactoryBot associations.
11
+ Enabled: false
12
+ VersionAdded: '0.21'
13
+
14
+ Sevencop/FactoryBotAssociationStyle:
15
+ Description: |
16
+ Use consistent style in FactoryBot associations.
17
+ Enabled: false
18
+ Safe: false
19
+ VersionAdded: '0.21'
20
+ EnforcedStyle: implicit
21
+ SupportedStyles:
22
+ - explicit
23
+ - implicit
24
+ inherit_mode:
25
+ merge:
26
+ - NonImplicitAssociationMethodNames
27
+ NonImplicitAssociationMethodNames:
28
+ - skip_create
29
+ Include:
30
+ - factories.rb
31
+ - factories/*.rb
32
+ - spec/factories.rb
33
+ - spec/factories/*.rb
34
+ - test/factories.rb
35
+ - test/factories/*.rb
36
+
8
37
  Sevencop/HashElementOrdered:
9
38
  Description: |
10
39
  Sort Hash elements by key.
@@ -53,6 +82,131 @@ Sevencop/RailsInferredSpecType:
53
82
  Safe: false
54
83
  VersionAdded: '0.9'
55
84
 
85
+ Sevencop/RailsMigrationAddCheckConstraint:
86
+ Description: |
87
+ Activate a check constraint in a separate migration in PostgreSQL.
88
+ Enabled: false
89
+ Safe: false
90
+ VersionAdded: '0.22'
91
+ Include:
92
+ - db/migrate/**/*.rb
93
+
94
+ Sevencop/RailsMigrationAddColumnWithDefaultValue:
95
+ Description: |
96
+ Add the column without a default value then change the default.
97
+ Enabled: false
98
+ Safe: false
99
+ VersionAdded: '0.22'
100
+ Include:
101
+ - db/migrate/**/*.rb
102
+
103
+ Sevencop/RailsMigrationAddForeignKey:
104
+ Description: |
105
+ Activate a foreign key validation in a separate migration in PostgreSQL.
106
+ Enabled: false
107
+ Safe: false
108
+ VersionAdded: '0.22'
109
+ Include:
110
+ - db/migrate/**/*.rb
111
+
112
+ Sevencop/RailsMigrationAddIndexConcurrently:
113
+ Description: |
114
+ Use `algorithm: :concurrently` on adding indexes to existing tables in PostgreSQL.
115
+ Enabled: false
116
+ Safe: false
117
+ VersionAdded: '0.22'
118
+ Include:
119
+ - db/migrate/**/*.rb
120
+
121
+ Sevencop/RailsMigrationBatchInBatches:
122
+ Description: |
123
+ Use `in_batches` in batch processing.
124
+ Enabled: false
125
+ Safe: false
126
+ VersionAdded: '0.22'
127
+ Include:
128
+ - db/migrate/**/*.rb
129
+
130
+ Sevencop/RailsMigrationBatchInTransaction:
131
+ Description: |
132
+ Disable transaction in batch processing.
133
+ Enabled: false
134
+ Safe: false
135
+ VersionAdded: '0.22'
136
+ Include:
137
+ - db/migrate/**/*.rb
138
+
139
+ Sevencop/RailsMigrationBatchWithThrottling:
140
+ Description: |
141
+ Use throttling in batch processing.
142
+ Enabled: false
143
+ Safe: false
144
+ VersionAdded: '0.22'
145
+ Include:
146
+ - db/migrate/**/*.rb
147
+
148
+ Sevencop/RailsMigrationCreateTableForce:
149
+ Description: |
150
+ Create tables without `force: true` option.
151
+ Enabled: false
152
+ VersionAdded: '0.22'
153
+ Include:
154
+ - db/migrate/**/*.rb
155
+
156
+ Sevencop/RailsMigrationJsonb:
157
+ Description: |
158
+ Prefer `jsonb` to `json`.
159
+ Enabled: false
160
+ Safe: false
161
+ VersionAdded: '0.22'
162
+ Include:
163
+ - db/migrate/**/*.rb
164
+
165
+ Sevencop/RailsMigrationChangeColumn:
166
+ Description: |
167
+ Avoid changing column type that is in use.
168
+ Enabled: false
169
+ Safe: false
170
+ VersionAdded: '0.22'
171
+ Include:
172
+ - db/migrate/**/*.rb
173
+
174
+ Sevencop/RailsMigrationChangeColumnNull:
175
+ Description: |
176
+ Avoid simply setting `NOT NULL` constraint on an existing column in PostgreSQL.
177
+ Enabled: false
178
+ Safe: false
179
+ VersionAdded: '0.22'
180
+ Include:
181
+ - db/migrate/**/*.rb
182
+
183
+ Sevencop/RailsMigrationRemoveColumn:
184
+ Description: |
185
+ Add to `ignored_columns` and then remove the column.
186
+ Enabled: false
187
+ Safe: false
188
+ VersionAdded: '0.22'
189
+ Include:
190
+ - db/migrate/**/*.rb
191
+
192
+ Sevencop/RailsMigrationRenameColumn:
193
+ Description: |
194
+ Avoid renaming columns that are in use.
195
+ Enabled: false
196
+ Safe: false
197
+ VersionAdded: '0.22'
198
+ Include:
199
+ - db/migrate/**/*.rb
200
+
201
+ Sevencop/RailsMigrationRenameTable:
202
+ Description: |
203
+ Avoid removing tables that are in use.
204
+ Enabled: false
205
+ Safe: false
206
+ VersionAdded: '0.22'
207
+ Include:
208
+ - db/migrate/**/*.rb
209
+
56
210
  Sevencop/RailsMigrationReservedWordMysql:
57
211
  Description: |
58
212
  Avoid using MySQL reserved words as identifiers.
@@ -62,6 +216,15 @@ Sevencop/RailsMigrationReservedWordMysql:
62
216
  Include:
63
217
  - db/migrate/**/*.rb
64
218
 
219
+ Sevencop/RailsMigrationUniqueIndexColumnsCount:
220
+ Description: |
221
+ Keep unique index columns count less than a specified number.
222
+ Enabled: false
223
+ VersionAdded: '0.22'
224
+ MaxColumnsCount: 3
225
+ Include:
226
+ - db/migrate/**/*.rb
227
+
65
228
  Sevencop/RailsOrderField:
66
229
  Description: |
67
230
  Wrap safe SQL String by `Arel.sql`.
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sevencop
6
+ # Remove redundant options from FactoryBot associations.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # association :user, factory: :user
11
+ #
12
+ # # good
13
+ # association :user
14
+ class FactoryBotAssociationOption < RuboCop::Cop::Base
15
+ extend AutoCorrector
16
+
17
+ include RangeHelp
18
+
19
+ MSG = 'Remove redundant options from FactoryBot associations.'
20
+
21
+ RESTRICT_ON_SEND = %i[association].freeze
22
+
23
+ # @param node [RuboCop::AST::SendNode]
24
+ # @return [void]
25
+ def on_send(node)
26
+ association_name = association_name_from(node)
27
+ factory_option = factory_option_from(node)
28
+ return if !factory_option || association_name != factory_option.value.value
29
+
30
+ add_offense(factory_option) do |corrector|
31
+ autocorrect(corrector, factory_option)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # @!method association_name_from(node)
38
+ # @param node [RuboCop::AST::SendNode]
39
+ # @return [Symbol, nil]
40
+ def_node_matcher :association_name_from, <<~PATTERN
41
+ (send
42
+ nil?
43
+ _
44
+ (sym $_)
45
+ ...
46
+ )
47
+ PATTERN
48
+
49
+ # @!method factory_option_from(node)
50
+ # @param node [RuboCop::AST::SendNode]
51
+ # @return [RuboCop::AST::PairNode, nil]
52
+ def_node_matcher :factory_option_from, <<~PATTERN
53
+ (send
54
+ nil?
55
+ _
56
+ _
57
+ (hash
58
+ <
59
+ $(pair
60
+ (sym :factory)
61
+ sym
62
+ )
63
+ ...
64
+ >
65
+ )
66
+ )
67
+ PATTERN
68
+
69
+ # @param corrector [RuboCop::Cop::Corrector]
70
+ # @param node [RuboCop::AST::PairNode]
71
+ # @return [void]
72
+ def autocorrect(
73
+ corrector,
74
+ node
75
+ )
76
+ corrector.remove(
77
+ range_with_surrounding_comma(
78
+ range_with_surrounding_space(
79
+ node.location.expression,
80
+ side: :left
81
+ ),
82
+ :left
83
+ )
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sevencop
6
+ # Use consistent style in FactoryBot associations.
7
+ #
8
+ # @safety
9
+ # This cop may cause false-positives in `EnforcedStyle: explicit` case.
10
+ # It recognizes any method call that has no arguments as an implicit association
11
+ # but it might be a user-defined trait call.
12
+ #
13
+ # @example EnforcedStyle: implicit (default)
14
+ # # bad
15
+ # association :user
16
+ #
17
+ # # good
18
+ # user
19
+ #
20
+ # # good
21
+ # association :author, factory: user
22
+ #
23
+ # @example EnforcedStyle: explicit
24
+ # # bad
25
+ # user
26
+ #
27
+ # # good
28
+ # association :user
29
+ #
30
+ # # good (defined in NonImplicitAssociationMethodNames)
31
+ # skip_create
32
+ class FactoryBotAssociationStyle < RuboCop::Cop::Base
33
+ extend AutoCorrector
34
+
35
+ include ConfigurableEnforcedStyle
36
+
37
+ MSG = 'Use consistent style in FactoryBot associations.'
38
+
39
+ RESTRICT_ON_SEND = %i[factory].freeze
40
+
41
+ # @param node [RuboCop::AST::SendNode]
42
+ # @return [void]
43
+ def on_send(node)
44
+ bad_associations_in(node).each do |association|
45
+ add_offense(association) do |corrector|
46
+ autocorrect(corrector, association)
47
+ end
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ # @!method explicit_association?(node)
54
+ # @param node [RuboCop::AST::SendNode]
55
+ # @return [Boolean]
56
+ def_node_matcher :explicit_association?, <<~PATTERN
57
+ (send
58
+ nil?
59
+ :association
60
+ ...
61
+ )
62
+ PATTERN
63
+
64
+ # @!method implicit_association?(node)
65
+ # @param node [RuboCop::AST::SendNode]
66
+ # @return [Boolean]
67
+ def_node_matcher :implicit_association?, <<~PATTERN
68
+ (send
69
+ nil?
70
+ !#non_implicit_association_method_name?
71
+ )
72
+ PATTERN
73
+
74
+ # @param corrector [RuboCop::Cop::Corrector]
75
+ # @param node [RuboCop::AST::SendNode]
76
+ def autocorrect(
77
+ corrector,
78
+ node
79
+ )
80
+ case style
81
+ when :explicit
82
+ autocorrect_to_explicit_style(corrector, node)
83
+ when :implicit
84
+ autocorrect_to_implicit_style(corrector, node)
85
+ end
86
+ end
87
+
88
+ # @param corrector [RuboCop::Cop::Corrector]
89
+ # @param node [RuboCop::AST::SendNode]
90
+ # @return [void]
91
+ def autocorrect_to_explicit_style(
92
+ corrector,
93
+ node
94
+ )
95
+ corrector.replace(node, "association :#{node.method_name}")
96
+ end
97
+
98
+ # @param corrector [RuboCop::Cop::Corrector]
99
+ # @param node [RuboCop::AST::SendNode]
100
+ # @return [void]
101
+ def autocorrect_to_implicit_style(
102
+ corrector,
103
+ node
104
+ )
105
+ corrector.replace(node, node.first_argument.value.to_s)
106
+ end
107
+
108
+ # @param node [RuboCop::AST::SendNode]
109
+ # @return [Boolean]
110
+ def autocorrectable_to_implicit_style?(node)
111
+ node.arguments.one?
112
+ end
113
+
114
+ # @param node [RuboCop::AST::SendNode]
115
+ # @return [Boolean]
116
+ def bad?(node)
117
+ case style
118
+ when :explicit
119
+ bad_to_explicit_style?(node)
120
+ when :implicit
121
+ bad_to_implicit_style?(node)
122
+ end
123
+ end
124
+
125
+ # @param node [RuboCop::AST::SendNode]
126
+ # @return [Array<RuboCop::AST::SendNode>]
127
+ def bad_associations_in(node)
128
+ children_of_factory_block(node).select do |child|
129
+ bad?(child)
130
+ end
131
+ end
132
+
133
+ # @param node [RuboCop::AST::SendNode]
134
+ # @return [Boolean]
135
+ def bad_to_explicit_style?(node)
136
+ implicit_association?(node)
137
+ end
138
+
139
+ # @param node [RuboCop::AST::SendNode]
140
+ # @return [Boolean]
141
+ def bad_to_implicit_style?(node)
142
+ explicit_association?(node) && autocorrectable_to_implicit_style?(node)
143
+ end
144
+
145
+ # @param node [RuboCop::AST::SendNode]
146
+ # @return [Array<RuboCop::AST::Node>]
147
+ def children_of_factory_block(node)
148
+ block = node.parent
149
+ return [] unless block
150
+ return [] unless block.block_type?
151
+
152
+ if block.body.begin_type?
153
+ block.body.children
154
+ else
155
+ [block.body]
156
+ end
157
+ end
158
+
159
+ # @param method_name [Symbol]
160
+ # @return [Boolean]
161
+ def non_implicit_association_method_name?(method_name)
162
+ cop_config['NonImplicitAssociationMethodNames'].include?(method_name.to_s)
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -73,7 +73,7 @@ module RuboCop
73
73
  _*
74
74
  ({ hash | kwargs }
75
75
  (pair ...)*
76
- $(pair (sym :type) (sym _))
76
+ $(pair (sym :type) sym)
77
77
  (pair ...)*
78
78
  )
79
79
  )
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sevencop
6
+ # Activate a check constraint in a separate migration in PostgreSQL.
7
+ #
8
+ # Adding a check constraint without `NOT VALID` blocks reads and writes in Postgres and
9
+ # blocks writes in MySQL and MariaDB while every row is checked.
10
+ #
11
+ # @safety
12
+ # Only meaningful in PostgreSQL.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # class AddCheckConstraintToOrdersPrice < ActiveRecord::Migration[7.0]
17
+ # def change
18
+ # add_check_constraint :orders, 'price > 0', name: 'orders_price_positive'
19
+ # end
20
+ # end
21
+ #
22
+ # # good
23
+ # class AddCheckConstraintToOrdersPriceWithoutValidation < ActiveRecord::Migration[7.0]
24
+ # def change
25
+ # add_check_constraint :orders, 'price > 0', name: 'orders_price_positive', validate: false
26
+ # end
27
+ # end
28
+ #
29
+ # class ActivateCheckConstraintOnOrdersPrice < ActiveRecord::Migration[7.0]
30
+ # def change
31
+ # validate_check_constraint :orders, name: 'orders_price_positive'
32
+ # end
33
+ # end
34
+ class RailsMigrationAddCheckConstraint < RuboCop::Cop::Base
35
+ extend AutoCorrector
36
+
37
+ MSG = 'Activate a check constraint in a separate migration in PostgreSQL.'
38
+
39
+ RESTRICT_ON_SEND = %i[
40
+ add_check_constraint
41
+ ].freeze
42
+
43
+ # @param node [RuboCop::AST::SendNode]
44
+ # @return [void]
45
+ def on_send(node)
46
+ return unless bad?(node)
47
+
48
+ add_offense(node) do |corrector|
49
+ autocorrect(corrector, node)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ # @!method add_check_constraint?(node)
56
+ # @param node [RuboCop::AST::SendNode]
57
+ # @return [Boolean]
58
+ def_node_matcher :add_check_constraint?, <<~PATTERN
59
+ (send
60
+ nil?
61
+ :add_check_constraint
62
+ ...
63
+ )
64
+ PATTERN
65
+
66
+ # @!method add_check_constraint_with_validate_false?(node)
67
+ # @param node [RuboCop::AST::SendNode]
68
+ # @return [Boolean]
69
+ def_node_matcher :add_check_constraint_with_validate_false?, <<~PATTERN
70
+ (send
71
+ nil?
72
+ :add_check_constraint
73
+ _
74
+ _
75
+ (hash
76
+ <
77
+ (pair
78
+ (sym :validate)
79
+ false
80
+ )
81
+ ...
82
+ >
83
+ )
84
+ )
85
+ PATTERN
86
+
87
+ # @param corrector [RuboCop::Cop::Corrector]
88
+ # @param node [RuboCop::AST::SendNode]
89
+ # @return [void]
90
+ def autocorrect(
91
+ corrector,
92
+ node
93
+ )
94
+ target = node.last_argument
95
+ target = target.pairs.last if target.hash_type?
96
+ corrector.insert_after(
97
+ target,
98
+ ', validate: false'
99
+ )
100
+ end
101
+
102
+ # @param node [RuboCop::AST::SendNode]
103
+ # @return [Boolean]
104
+ def bad?(node)
105
+ add_check_constraint?(node) &&
106
+ !add_check_constraint_with_validate_false?(node)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end