rubocop-rails 2.13.0 → 2.13.1
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/LICENSE.txt +1 -1
- data/lib/rubocop/cop/rails/index_by.rb +6 -6
- data/lib/rubocop/cop/rails/index_with.rb +6 -6
- data/lib/rubocop/cop/rails/read_write_attribute.rb +21 -0
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +90 -26
- data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
- data/lib/rubocop/cop/rails/unused_ignored_columns.rb +2 -0
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 624c6bfb8dc9c5db0f6dd6bec835bd71e5e5a7aadc298342c15faae187226079
|
4
|
+
data.tar.gz: 4354d39a8367f0e4cb46b5a890cdd0836bfff6d838b5ae320b3df3a480f529af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19863e8b5b71b4403d66b46e73ed41ceb1953d2a68996fbcc800ab4c06fcf4dfebadf3907f62d2c575b002223a95fa67fce2412c01fa42b6234848c2791b37e9
|
7
|
+
data.tar.gz: 1e3d14e3240f7fdb9182529865ee8257cf19368bac19c33abfba44b0a3b63c54e64457f73725e6c629a5846ea402a96e650f7d6ce0e1943386c857d6a8642d7b
|
data/LICENSE.txt
CHANGED
@@ -23,22 +23,22 @@ module RuboCop
|
|
23
23
|
|
24
24
|
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
25
25
|
(block
|
26
|
-
(
|
26
|
+
(call _ :each_with_object (hash))
|
27
27
|
(args (arg $_el) (arg _memo))
|
28
|
-
(
|
28
|
+
(call (lvar _memo) :[]= $!`_memo (lvar _el)))
|
29
29
|
PATTERN
|
30
30
|
|
31
31
|
def_node_matcher :on_bad_to_h, <<~PATTERN
|
32
32
|
(block
|
33
|
-
(
|
33
|
+
(call _ :to_h)
|
34
34
|
(args (arg $_el))
|
35
35
|
(array $_ (lvar _el)))
|
36
36
|
PATTERN
|
37
37
|
|
38
38
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
39
|
-
(
|
39
|
+
(call
|
40
40
|
(block
|
41
|
-
(
|
41
|
+
(call _ {:map :collect})
|
42
42
|
(args (arg $_el))
|
43
43
|
(array $_ (lvar _el)))
|
44
44
|
:to_h)
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
49
49
|
(const _ :Hash)
|
50
50
|
:[]
|
51
51
|
(block
|
52
|
-
(
|
52
|
+
(call _ {:map :collect})
|
53
53
|
(args (arg $_el))
|
54
54
|
(array $_ (lvar _el))))
|
55
55
|
PATTERN
|
@@ -26,22 +26,22 @@ module RuboCop
|
|
26
26
|
|
27
27
|
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
28
28
|
(block
|
29
|
-
(
|
29
|
+
(call _ :each_with_object (hash))
|
30
30
|
(args (arg $_el) (arg _memo))
|
31
|
-
(
|
31
|
+
(call (lvar _memo) :[]= (lvar _el) $!`_memo))
|
32
32
|
PATTERN
|
33
33
|
|
34
34
|
def_node_matcher :on_bad_to_h, <<~PATTERN
|
35
35
|
(block
|
36
|
-
(
|
36
|
+
(call _ :to_h)
|
37
37
|
(args (arg $_el))
|
38
38
|
(array (lvar _el) $_))
|
39
39
|
PATTERN
|
40
40
|
|
41
41
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
42
|
-
(
|
42
|
+
(call
|
43
43
|
(block
|
44
|
-
(
|
44
|
+
(call _ {:map :collect})
|
45
45
|
(args (arg $_el))
|
46
46
|
(array (lvar _el) $_))
|
47
47
|
:to_h)
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
52
52
|
(const _ :Hash)
|
53
53
|
:[]
|
54
54
|
(block
|
55
|
-
(
|
55
|
+
(call _ {:map :collect})
|
56
56
|
(args (arg $_el))
|
57
57
|
(array (lvar _el) $_)))
|
58
58
|
PATTERN
|
@@ -23,6 +23,17 @@ module RuboCop
|
|
23
23
|
# # good
|
24
24
|
# x = self[:attr]
|
25
25
|
# self[:attr] = val
|
26
|
+
#
|
27
|
+
# When called from within a method with the same name as the attribute,
|
28
|
+
# `read_attribute` and `write_attribute` must be used to prevent an
|
29
|
+
# infinite loop:
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
#
|
33
|
+
# # good
|
34
|
+
# def foo
|
35
|
+
# bar || read_attribute(:foo)
|
36
|
+
# end
|
26
37
|
class ReadWriteAttribute < Base
|
27
38
|
extend AutoCorrector
|
28
39
|
|
@@ -38,6 +49,7 @@ module RuboCop
|
|
38
49
|
|
39
50
|
def on_send(node)
|
40
51
|
return unless read_write_attribute?(node)
|
52
|
+
return if within_shadowing_method?(node)
|
41
53
|
|
42
54
|
add_offense(node.loc.selector, message: message(node)) do |corrector|
|
43
55
|
case node.method_name
|
@@ -53,6 +65,15 @@ module RuboCop
|
|
53
65
|
|
54
66
|
private
|
55
67
|
|
68
|
+
def within_shadowing_method?(node)
|
69
|
+
node.each_ancestor(:def).any? do |enclosing_method|
|
70
|
+
shadowing_method_name = node.first_argument.value.to_s
|
71
|
+
shadowing_method_name << '=' if node.method?(:write_attribute)
|
72
|
+
|
73
|
+
enclosing_method.method_name.to_s == shadowing_method_name
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
56
77
|
def message(node)
|
57
78
|
if node.method?(:read_attribute)
|
58
79
|
format(MSG, prefer: 'self[:attr]', current: 'read_attribute(:attr)')
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
extend AutoCorrector
|
33
33
|
extend TargetRailsVersion
|
34
34
|
|
35
|
-
MSG = 'Remove explicit presence validation for
|
35
|
+
MSG = 'Remove explicit presence validation for %<association>s.'
|
36
36
|
RESTRICT_ON_SEND = %i[validates].freeze
|
37
37
|
|
38
38
|
minimum_target_rails_version 5.0
|
@@ -43,28 +43,39 @@ module RuboCop
|
|
43
43
|
# @example source that matches - by association
|
44
44
|
# validates :user, presence: true
|
45
45
|
#
|
46
|
+
# @example source that matches - by association
|
47
|
+
# validates :name, :user, presence: true
|
48
|
+
#
|
46
49
|
# @example source that matches - with presence options
|
47
50
|
# validates :user, presence: { message: 'duplicate' }
|
48
51
|
#
|
49
52
|
# @example source that matches - by a foreign key
|
50
53
|
# validates :user_id, presence: true
|
54
|
+
#
|
55
|
+
# @example source that DOES NOT match - strict validation
|
56
|
+
# validates :user_id, presence: true, strict: true
|
57
|
+
#
|
58
|
+
# @example source that DOES NOT match - custom strict validation
|
59
|
+
# validates :user_id, presence: true, strict: MissingUserError
|
51
60
|
def_node_matcher :presence_validation?, <<~PATTERN
|
52
|
-
|
61
|
+
(
|
53
62
|
send nil? :validates
|
54
|
-
(sym $_)
|
55
|
-
|
56
|
-
|
63
|
+
(sym $_)+
|
64
|
+
$[
|
65
|
+
(hash <$(pair (sym :presence) {true hash}) ...>) # presence: true
|
66
|
+
!(hash <$(pair (sym :strict) {true const}) ...>) # strict: true
|
67
|
+
]
|
57
68
|
)
|
58
69
|
PATTERN
|
59
70
|
|
60
|
-
# @!method
|
61
|
-
#
|
71
|
+
# @!method optional?(node)
|
72
|
+
# Match a `belongs_to` association with an optional option in a hash
|
62
73
|
def_node_matcher :optional?, <<~PATTERN
|
63
74
|
(send nil? :belongs_to _ ... #optional_option?)
|
64
75
|
PATTERN
|
65
76
|
|
66
77
|
# @!method optional_option?(node)
|
67
|
-
#
|
78
|
+
# Match an optional option in a hash
|
68
79
|
def_node_matcher :optional_option?, <<~PATTERN
|
69
80
|
{
|
70
81
|
(hash <(pair (sym :optional) true) ...>) # optional: true
|
@@ -122,7 +133,7 @@ module RuboCop
|
|
122
133
|
)
|
123
134
|
PATTERN
|
124
135
|
|
125
|
-
# @!method belongs_to_without_fk?(node,
|
136
|
+
# @!method belongs_to_without_fk?(node, key)
|
126
137
|
# Match a matching `belongs_to` association, without an explicit `foreign_key` option
|
127
138
|
#
|
128
139
|
# @param node [RuboCop::AST::Node]
|
@@ -150,21 +161,43 @@ module RuboCop
|
|
150
161
|
PATTERN
|
151
162
|
|
152
163
|
def on_send(node)
|
153
|
-
|
154
|
-
|
164
|
+
presence_validation?(node) do |all_keys, options, presence|
|
165
|
+
keys = non_optional_belongs_to(node.parent, all_keys)
|
166
|
+
return if keys.none?
|
155
167
|
|
156
|
-
|
157
|
-
|
158
|
-
|
168
|
+
add_offense_and_correct(node, all_keys, keys, options, presence)
|
169
|
+
end
|
170
|
+
end
|
159
171
|
|
160
|
-
|
172
|
+
private
|
161
173
|
|
162
|
-
|
163
|
-
|
174
|
+
def add_offense_and_correct(node, all_keys, keys, options, presence)
|
175
|
+
add_offense(presence, message: message_for(keys)) do |corrector|
|
176
|
+
if options.children.one? # `presence: true` is the only option
|
177
|
+
if keys == all_keys
|
178
|
+
remove_validation(corrector, node)
|
179
|
+
else
|
180
|
+
remove_keys_from_validation(corrector, node, keys)
|
181
|
+
end
|
182
|
+
elsif keys == all_keys
|
183
|
+
remove_presence_option(corrector, presence)
|
184
|
+
else
|
185
|
+
extract_validation_for_keys(corrector, node, keys, options)
|
186
|
+
end
|
164
187
|
end
|
165
188
|
end
|
166
189
|
|
167
|
-
|
190
|
+
def message_for(keys)
|
191
|
+
display_keys = keys.map { |key| "`#{key}`" }.join('/')
|
192
|
+
format(MSG, association: display_keys)
|
193
|
+
end
|
194
|
+
|
195
|
+
def non_optional_belongs_to(node, keys)
|
196
|
+
keys.select do |key|
|
197
|
+
belongs_to = belongs_to_for(node, key)
|
198
|
+
belongs_to && !optional?(belongs_to)
|
199
|
+
end
|
200
|
+
end
|
168
201
|
|
169
202
|
def belongs_to_for(model_class_node, key)
|
170
203
|
if key.to_s.end_with?('_id')
|
@@ -175,17 +208,48 @@ module RuboCop
|
|
175
208
|
end
|
176
209
|
end
|
177
210
|
|
178
|
-
def
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
211
|
+
def remove_validation(corrector, node)
|
212
|
+
corrector.remove(validation_range(node))
|
213
|
+
end
|
214
|
+
|
215
|
+
def remove_keys_from_validation(corrector, node, keys)
|
216
|
+
keys.each do |key|
|
217
|
+
key_node = node.arguments.find { |arg| arg.value == key }
|
218
|
+
key_range = range_with_surrounding_space(
|
219
|
+
range: range_with_surrounding_comma(key_node.source_range, :right),
|
220
|
+
side: :right
|
185
221
|
)
|
186
|
-
corrector.remove(
|
222
|
+
corrector.remove(key_range)
|
187
223
|
end
|
188
224
|
end
|
225
|
+
|
226
|
+
def remove_presence_option(corrector, presence)
|
227
|
+
range = range_with_surrounding_comma(
|
228
|
+
range_with_surrounding_space(range: presence.source_range, side: :left),
|
229
|
+
:left
|
230
|
+
)
|
231
|
+
corrector.remove(range)
|
232
|
+
end
|
233
|
+
|
234
|
+
def extract_validation_for_keys(corrector, node, keys, options)
|
235
|
+
indentation = ' ' * node.source_range.column
|
236
|
+
options_without_presence = options.children.reject { |pair| pair.key.value == :presence }
|
237
|
+
source = [
|
238
|
+
indentation,
|
239
|
+
'validates ',
|
240
|
+
keys.map(&:inspect).join(', '),
|
241
|
+
', ',
|
242
|
+
options_without_presence.map(&:source).join(', '),
|
243
|
+
"\n"
|
244
|
+
].join
|
245
|
+
|
246
|
+
remove_keys_from_validation(corrector, node, keys)
|
247
|
+
corrector.insert_after(validation_range(node), source)
|
248
|
+
end
|
249
|
+
|
250
|
+
def validation_range(node)
|
251
|
+
range_by_whole_lines(node.source_range, include_final_newline: true)
|
252
|
+
end
|
189
253
|
end
|
190
254
|
end
|
191
255
|
end
|
@@ -179,7 +179,7 @@ module RuboCop
|
|
179
179
|
MSG = '%<action>s is not reversible.'
|
180
180
|
|
181
181
|
def_node_matcher :irreversible_schema_statement_call, <<~PATTERN
|
182
|
-
(send nil? ${:change_column :execute
|
182
|
+
(send nil? ${:change_column :execute} ...)
|
183
183
|
PATTERN
|
184
184
|
|
185
185
|
def_node_matcher :drop_table_call, <<~PATTERN
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.13.
|
4
|
+
version: 2.13.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2022-01-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -212,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
212
|
- !ruby/object:Gem::Version
|
213
213
|
version: '0'
|
214
214
|
requirements: []
|
215
|
-
rubygems_version: 3.
|
215
|
+
rubygems_version: 3.3.3
|
216
216
|
signing_key:
|
217
217
|
specification_version: 4
|
218
218
|
summary: Automatic Rails code style checking tool.
|