rubocop-rails 2.13.0 → 2.13.1
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|