rubocop 0.60.0 → 0.61.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/config/default.yml +573 -560
- data/lib/rubocop.rb +5 -0
- data/lib/rubocop/ast/node.rb +1 -1
- data/lib/rubocop/ast/sexp.rb +1 -1
- data/lib/rubocop/cli.rb +9 -14
- data/lib/rubocop/config.rb +4 -3
- data/lib/rubocop/config_loader.rb +25 -22
- data/lib/rubocop/config_loader_resolver.rb +3 -2
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +53 -0
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +73 -0
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +138 -0
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +52 -46
- data/lib/rubocop/cop/generator.rb +13 -17
- data/lib/rubocop/cop/generator/configuration_injector.rb +60 -0
- data/lib/rubocop/cop/layout/align_hash.rb +3 -0
- data/lib/rubocop/cop/layout/comment_indentation.rb +32 -2
- data/lib/rubocop/cop/layout/indent_heredoc.rb +11 -5
- data/lib/rubocop/cop/layout/indentation_width.rb +7 -1
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +11 -11
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +30 -17
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -5
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
- data/lib/rubocop/cop/metrics/line_length.rb +2 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +11 -15
- data/lib/rubocop/cop/offense.rb +1 -1
- data/lib/rubocop/cop/performance/open_struct.rb +46 -0
- data/lib/rubocop/cop/performance/redundant_merge.rb +18 -4
- data/lib/rubocop/cop/rails/bulk_change_table.rb +2 -2
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +15 -8
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +17 -14
- data/lib/rubocop/cop/rails/http_status.rb +4 -4
- data/lib/rubocop/cop/rails/inverse_of.rb +2 -2
- data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
- data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
- data/lib/rubocop/cop/rails/validation.rb +4 -4
- data/lib/rubocop/cop/security/open.rb +31 -11
- data/lib/rubocop/cop/style/begin_block.rb +6 -0
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +13 -7
- data/lib/rubocop/cop/style/for.rb +9 -78
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -4
- data/lib/rubocop/cop/style/global_vars.rb +1 -1
- data/lib/rubocop/cop/style/infinite_loop.rb +42 -6
- data/lib/rubocop/cop/style/lambda.rb +4 -87
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +221 -16
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/regexp_literal.rb +62 -10
- data/lib/rubocop/cop/style/unneeded_condition.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +4 -2
- data/lib/rubocop/cop/variable_force/variable.rb +2 -0
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/remote_config.rb +13 -4
- data/lib/rubocop/rspec/expect_offense.rb +1 -1
- data/lib/rubocop/runner.rb +15 -4
- data/lib/rubocop/version.rb +1 -1
- metadata +7 -2
@@ -3,11 +3,26 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# This cop enforces the presence (default) or absence of parentheses in
|
7
|
+
# method calls containing parameters.
|
8
|
+
#
|
9
|
+
# In the default style (require_parentheses), macro methods are ignored.
|
10
|
+
# Additional methods can be added to the `IgnoredMethods` list. This
|
11
|
+
# option is valid only in the default style.
|
12
|
+
#
|
13
|
+
# In the alternative style (omit_parentheses), there are two additional
|
14
|
+
# options.
|
15
|
+
#
|
16
|
+
# 1. `AllowParenthesesInChaining` is `false` by default. Setting it to
|
17
|
+
# `true` allows the presence of parentheses in the last call during
|
18
|
+
# method chaining.
|
19
|
+
#
|
20
|
+
# 2. `AllowParenthesesInMultilineCall` is `false` by default. Setting it
|
21
|
+
# to `true` allows the presence of parentheses in multi-line method
|
22
|
+
# calls.
|
23
|
+
#
|
24
|
+
# @example EnforcedStyle: require_parentheses
|
9
25
|
#
|
10
|
-
# @example
|
11
26
|
#
|
12
27
|
# # bad
|
13
28
|
# array.delete e
|
@@ -39,21 +54,114 @@ module RuboCop
|
|
39
54
|
# class Foo
|
40
55
|
# bar :baz
|
41
56
|
# end
|
57
|
+
#
|
58
|
+
# @example EnforcedStyle: omit_parentheses
|
59
|
+
#
|
60
|
+
# # bad
|
61
|
+
# array.delete(e)
|
62
|
+
#
|
63
|
+
# # good
|
64
|
+
# array.delete e
|
65
|
+
#
|
66
|
+
# # bad
|
67
|
+
# foo.enforce(strict: true)
|
68
|
+
#
|
69
|
+
# # good
|
70
|
+
# foo.enforce strict: true
|
71
|
+
#
|
72
|
+
# # AllowParenthesesInMultilineCall: false (default)
|
73
|
+
#
|
74
|
+
# # bad
|
75
|
+
# foo.enforce(
|
76
|
+
# strict: true
|
77
|
+
# )
|
78
|
+
#
|
79
|
+
# # good
|
80
|
+
# foo.enforce \
|
81
|
+
# strict: true
|
82
|
+
#
|
83
|
+
# # AllowParenthesesInMultilineCall: true
|
84
|
+
#
|
85
|
+
# # good
|
86
|
+
# foo.enforce(
|
87
|
+
# strict: true
|
88
|
+
# )
|
89
|
+
#
|
90
|
+
# # good
|
91
|
+
# foo.enforce \
|
92
|
+
# strict: true
|
93
|
+
#
|
94
|
+
# # AllowParenthesesInChaining: false (default)
|
95
|
+
#
|
96
|
+
# # bad
|
97
|
+
# foo().bar(1)
|
98
|
+
#
|
99
|
+
# # good
|
100
|
+
# foo().bar 1
|
101
|
+
#
|
102
|
+
# # AllowParenthesesInChaining: true
|
103
|
+
#
|
104
|
+
# # good
|
105
|
+
# foo().bar(1)
|
106
|
+
#
|
107
|
+
# # good
|
108
|
+
# foo().bar 1
|
42
109
|
class MethodCallWithArgsParentheses < Cop
|
110
|
+
include ConfigurableEnforcedStyle
|
43
111
|
include IgnoredMethods
|
44
112
|
|
45
|
-
|
113
|
+
TRAILING_WHITESPACE_REGEX = /\s+\Z/.freeze
|
46
114
|
|
47
115
|
def on_send(node)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
116
|
+
case style
|
117
|
+
when :require_parentheses
|
118
|
+
add_offense_for_require_parentheses(node)
|
119
|
+
when :omit_parentheses
|
120
|
+
add_offense_for_omit_parentheses(node)
|
121
|
+
end
|
52
122
|
end
|
53
123
|
alias on_super on_send
|
54
124
|
alias on_yield on_send
|
55
125
|
|
56
126
|
def autocorrect(node)
|
127
|
+
case style
|
128
|
+
when :require_parentheses
|
129
|
+
autocorrect_for_require_parentheses(node)
|
130
|
+
when :omit_parentheses
|
131
|
+
autocorrect_for_omit_parentheses(node)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def message(_node = nil)
|
136
|
+
case style
|
137
|
+
when :require_parentheses
|
138
|
+
'Use parentheses for method calls with arguments.'.freeze
|
139
|
+
when :omit_parentheses
|
140
|
+
'Omit parentheses for method calls with arguments.'.freeze
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def add_offense_for_require_parentheses(node)
|
147
|
+
return if ignored_method?(node.method_name)
|
148
|
+
return if eligible_for_parentheses_omission?(node)
|
149
|
+
return unless node.arguments? && !node.parenthesized?
|
150
|
+
|
151
|
+
add_offense(node)
|
152
|
+
end
|
153
|
+
|
154
|
+
def add_offense_for_omit_parentheses(node)
|
155
|
+
return unless node.parenthesized?
|
156
|
+
return if node.implicit_call?
|
157
|
+
return if super_call_without_arguments?(node)
|
158
|
+
return if camel_case_method_call_without_arguments?(node)
|
159
|
+
return if eligible_for_parentheses_presence?(node)
|
160
|
+
|
161
|
+
add_offense(node, location: node.loc.begin.join(node.loc.end))
|
162
|
+
end
|
163
|
+
|
164
|
+
def autocorrect_for_require_parentheses(node)
|
57
165
|
lambda do |corrector|
|
58
166
|
corrector.replace(args_begin(node), '(')
|
59
167
|
|
@@ -63,16 +171,23 @@ module RuboCop
|
|
63
171
|
end
|
64
172
|
end
|
65
173
|
|
66
|
-
|
174
|
+
def autocorrect_for_omit_parentheses(node)
|
175
|
+
lambda do |corrector|
|
176
|
+
if parentheses_at_the_end_of_multiline_call?(node)
|
177
|
+
corrector.replace(args_begin(node), ' \\')
|
178
|
+
else
|
179
|
+
corrector.replace(args_begin(node), ' ')
|
180
|
+
end
|
181
|
+
corrector.remove(node.loc.end)
|
182
|
+
end
|
183
|
+
end
|
67
184
|
|
68
|
-
def
|
69
|
-
node.operator_method? || node.setter_method? ||
|
70
|
-
ignore_macros? && node.macro? ||
|
71
|
-
super(node.method_name)
|
185
|
+
def eligible_for_parentheses_omission?(node)
|
186
|
+
node.operator_method? || node.setter_method? || ignore_macros?(node)
|
72
187
|
end
|
73
188
|
|
74
|
-
def ignore_macros?
|
75
|
-
cop_config['IgnoreMacros']
|
189
|
+
def ignore_macros?(node)
|
190
|
+
cop_config['IgnoreMacros'] && node.macro?
|
76
191
|
end
|
77
192
|
|
78
193
|
def args_begin(node)
|
@@ -94,6 +209,96 @@ module RuboCop
|
|
94
209
|
first_node = node.arguments.first
|
95
210
|
first_node.begin_type? && first_node.parenthesized_call?
|
96
211
|
end
|
212
|
+
|
213
|
+
def parentheses_at_the_end_of_multiline_call?(node)
|
214
|
+
node.multiline? &&
|
215
|
+
node.loc.begin.source_line
|
216
|
+
.gsub(TRAILING_WHITESPACE_REGEX, '')
|
217
|
+
.end_with?('(')
|
218
|
+
end
|
219
|
+
|
220
|
+
def super_call_without_arguments?(node)
|
221
|
+
node.super_type? && node.arguments.none?
|
222
|
+
end
|
223
|
+
|
224
|
+
def camel_case_method_call_without_arguments?(node)
|
225
|
+
node.camel_case_method? && node.arguments.none?
|
226
|
+
end
|
227
|
+
|
228
|
+
def eligible_for_parentheses_presence?(node)
|
229
|
+
call_in_literals?(node) ||
|
230
|
+
call_with_ambiguous_arguments?(node) ||
|
231
|
+
call_in_logical_operators?(node) ||
|
232
|
+
allowed_multiline_call_with_parentheses?(node) ||
|
233
|
+
allowed_chained_call_with_parentheses?(node)
|
234
|
+
end
|
235
|
+
|
236
|
+
def call_in_literals?(node)
|
237
|
+
node.parent &&
|
238
|
+
(node.parent.pair_type? ||
|
239
|
+
node.parent.array_type? ||
|
240
|
+
ternary_if?(node.parent))
|
241
|
+
end
|
242
|
+
|
243
|
+
def call_in_logical_operators?(node)
|
244
|
+
node.parent &&
|
245
|
+
(logical_operator?(node.parent) ||
|
246
|
+
node.parent.descendants.any?(&method(:logical_operator?)))
|
247
|
+
end
|
248
|
+
|
249
|
+
def call_with_ambiguous_arguments?(node)
|
250
|
+
call_with_braced_block?(node) ||
|
251
|
+
call_as_argument?(node) ||
|
252
|
+
hash_literal_in_arguments?(node) ||
|
253
|
+
node.descendants.any? do |n|
|
254
|
+
splat?(n) || ternary_if?(n) || logical_operator?(n)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def call_with_braced_block?(node)
|
259
|
+
node.block_node && node.block_node.braces?
|
260
|
+
end
|
261
|
+
|
262
|
+
def call_as_argument?(node)
|
263
|
+
node.parent && node.parent.send_type?
|
264
|
+
end
|
265
|
+
|
266
|
+
def hash_literal_in_arguments?(node)
|
267
|
+
node.arguments.any? do |n|
|
268
|
+
hash_literal?(n) ||
|
269
|
+
n.send_type? && node.descendants.any?(&method(:hash_literal?))
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def allowed_multiline_call_with_parentheses?(node)
|
274
|
+
cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
|
275
|
+
end
|
276
|
+
|
277
|
+
def allowed_chained_call_with_parentheses?(node)
|
278
|
+
return unless cop_config['AllowParenthesesInChaining']
|
279
|
+
|
280
|
+
previous = node.descendants.first
|
281
|
+
return false unless previous && previous.send_type?
|
282
|
+
|
283
|
+
previous.parenthesized? ||
|
284
|
+
allowed_chained_call_with_parentheses?(previous)
|
285
|
+
end
|
286
|
+
|
287
|
+
def splat?(node)
|
288
|
+
node.splat_type? || node.kwsplat_type? || node.block_pass_type?
|
289
|
+
end
|
290
|
+
|
291
|
+
def ternary_if?(node)
|
292
|
+
node.if_type? && node.ternary?
|
293
|
+
end
|
294
|
+
|
295
|
+
def logical_operator?(node)
|
296
|
+
(node.and_type? || node.or_type?) && node.logical_operator?
|
297
|
+
end
|
298
|
+
|
299
|
+
def hash_literal?(node)
|
300
|
+
node.hash_type? && node.braces?
|
301
|
+
end
|
97
302
|
end
|
98
303
|
end
|
99
304
|
end
|
@@ -83,6 +83,7 @@ module RuboCop
|
|
83
83
|
# x =~ /home\//
|
84
84
|
class RegexpLiteral < Cop
|
85
85
|
include ConfigurableEnforcedStyle
|
86
|
+
include RangeHelp
|
86
87
|
|
87
88
|
MSG_USE_SLASHES = 'Use `//` around regular expression.'.freeze
|
88
89
|
MSG_USE_PERCENT_R = 'Use `%r` around regular expression.'.freeze
|
@@ -96,17 +97,9 @@ module RuboCop
|
|
96
97
|
end
|
97
98
|
|
98
99
|
def autocorrect(node)
|
99
|
-
return if contains_slash?(node)
|
100
|
-
|
101
|
-
replacement = if slash_literal?(node)
|
102
|
-
['%r', ''].zip(preferred_delimiters).map(&:join)
|
103
|
-
else
|
104
|
-
%w[/ /]
|
105
|
-
end
|
106
|
-
|
107
100
|
lambda do |corrector|
|
108
|
-
|
109
|
-
|
101
|
+
correct_delimiters(node, corrector)
|
102
|
+
correct_inner_slashes(node, corrector)
|
110
103
|
end
|
111
104
|
end
|
112
105
|
|
@@ -169,6 +162,65 @@ module RuboCop
|
|
169
162
|
config.for_cop('Style/PercentLiteralDelimiters') \
|
170
163
|
['PreferredDelimiters']['%r'].split(//)
|
171
164
|
end
|
165
|
+
|
166
|
+
def correct_delimiters(node, corrector)
|
167
|
+
replacement = calculate_replacement(node)
|
168
|
+
corrector.replace(node.loc.begin, replacement.first)
|
169
|
+
corrector.replace(node.loc.end, replacement.last)
|
170
|
+
end
|
171
|
+
|
172
|
+
def correct_inner_slashes(node, corrector)
|
173
|
+
regexp_begin = node.loc.begin.end_pos
|
174
|
+
|
175
|
+
inner_slash_indices(node).each do |index|
|
176
|
+
start = regexp_begin + index
|
177
|
+
|
178
|
+
corrector.replace(
|
179
|
+
range_between(
|
180
|
+
start,
|
181
|
+
start + inner_slash_before_correction(node).length
|
182
|
+
),
|
183
|
+
inner_slash_after_correction(node)
|
184
|
+
)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def inner_slash_indices(node)
|
189
|
+
text = node_body(node)
|
190
|
+
pattern = inner_slash_before_correction(node)
|
191
|
+
index = -1
|
192
|
+
indices = []
|
193
|
+
|
194
|
+
while (index = text.index(pattern, index + 1))
|
195
|
+
indices << index
|
196
|
+
end
|
197
|
+
|
198
|
+
indices
|
199
|
+
end
|
200
|
+
|
201
|
+
def inner_slash_before_correction(node)
|
202
|
+
inner_slash_for(node.loc.begin.source)
|
203
|
+
end
|
204
|
+
|
205
|
+
def inner_slash_after_correction(node)
|
206
|
+
inner_slash_for(calculate_replacement(node).first)
|
207
|
+
end
|
208
|
+
|
209
|
+
def inner_slash_for(opening_delimiter)
|
210
|
+
if ['/', '%r/'].include?(opening_delimiter)
|
211
|
+
'\/'
|
212
|
+
else
|
213
|
+
'/'
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def calculate_replacement(node)
|
218
|
+
if slash_literal?(node)
|
219
|
+
['%r', ''].zip(preferred_delimiters).map(&:join)
|
220
|
+
else
|
221
|
+
%w[/ /]
|
222
|
+
end
|
223
|
+
end
|
172
224
|
end
|
173
225
|
end
|
174
226
|
end
|
@@ -47,7 +47,7 @@ module RuboCop
|
|
47
47
|
lambda do |corrector|
|
48
48
|
if node.ternary?
|
49
49
|
corrector.replace(range_of_offense(node), '||')
|
50
|
-
elsif node.modifier_form?
|
50
|
+
elsif node.modifier_form? || !node.else_branch
|
51
51
|
corrector.replace(node.source_range, node.if_branch.source)
|
52
52
|
else
|
53
53
|
corrected = make_ternary_form(node)
|
@@ -60,7 +60,7 @@ module RuboCop
|
|
60
60
|
private
|
61
61
|
|
62
62
|
def message(node)
|
63
|
-
if node.modifier_form?
|
63
|
+
if node.modifier_form? || !node.else_branch
|
64
64
|
UNNEEDED_CONDITION
|
65
65
|
else
|
66
66
|
MSG
|
@@ -50,8 +50,8 @@ module RuboCop
|
|
50
50
|
|
51
51
|
ZERO_ARITY_SUPER_TYPE = :zsuper
|
52
52
|
|
53
|
-
TWISTED_SCOPE_TYPES = %i[block class sclass defs].freeze
|
54
|
-
SCOPE_TYPES = (TWISTED_SCOPE_TYPES +
|
53
|
+
TWISTED_SCOPE_TYPES = %i[block class sclass defs module].freeze
|
54
|
+
SCOPE_TYPES = (TWISTED_SCOPE_TYPES + [:def]).freeze
|
55
55
|
|
56
56
|
SEND_TYPE = :send
|
57
57
|
|
@@ -196,6 +196,7 @@ module RuboCop
|
|
196
196
|
regexp.named_captures.keys
|
197
197
|
end
|
198
198
|
|
199
|
+
# rubocop:disable Metrics/AbcSize
|
199
200
|
def process_variable_operator_assignment(node)
|
200
201
|
if LOGICAL_OPERATOR_ASSIGNMENT_TYPES.include?(node.type)
|
201
202
|
asgn_node, rhs_node = *node
|
@@ -232,6 +233,7 @@ module RuboCop
|
|
232
233
|
|
233
234
|
skip_children!
|
234
235
|
end
|
236
|
+
# rubocop:enable Metrics/AbcSize
|
235
237
|
|
236
238
|
def process_variable_multiple_assignment(node)
|
237
239
|
lhs_node, rhs_node = *node
|
@@ -37,6 +37,7 @@ module RuboCop
|
|
37
37
|
!@references.empty?
|
38
38
|
end
|
39
39
|
|
40
|
+
# rubocop:disable Metrics/AbcSize
|
40
41
|
def reference!(node)
|
41
42
|
reference = Reference.new(node, @scope)
|
42
43
|
@references << reference
|
@@ -56,6 +57,7 @@ module RuboCop
|
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
60
|
+
# rubocop:enable Metrics/AbcSize
|
59
61
|
|
60
62
|
def capture_with_block!
|
61
63
|
@captured_by_block = true
|