rubocop 1.6.1 → 1.7.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 +1 -1
- data/config/default.yml +48 -6
- data/lib/rubocop.rb +4 -0
- data/lib/rubocop/config.rb +8 -5
- data/lib/rubocop/config_loader.rb +10 -6
- data/lib/rubocop/config_loader_resolver.rb +21 -4
- data/lib/rubocop/config_obsoletion.rb +5 -3
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +3 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +145 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +19 -3
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +14 -0
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -10
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +64 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +13 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +59 -0
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +7 -2
- data/lib/rubocop/cop/lint/duplicate_branch.rb +64 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +50 -17
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
- data/lib/rubocop/cop/lint/unreachable_loop.rb +17 -0
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +59 -5
- data/lib/rubocop/cop/registry.rb +10 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -1
- data/lib/rubocop/cop/style/collection_methods.rb +14 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +22 -5
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/hash_except.rb +95 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -2
- data/lib/rubocop/cop/style/lambda_call.rb +2 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +16 -6
- data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +26 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +13 -3
- data/lib/rubocop/cop/style/raise_args.rb +2 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +7 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +8 -4
- data/lib/rubocop/cop/style/single_line_methods.rb +4 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
- data/lib/rubocop/cop/util.rb +3 -1
- data/lib/rubocop/options.rb +9 -9
- data/lib/rubocop/rspec/cop_helper.rb +0 -4
- data/lib/rubocop/rspec/expect_offense.rb +34 -22
- data/lib/rubocop/runner.rb +16 -1
- data/lib/rubocop/target_finder.rb +4 -2
- data/lib/rubocop/util.rb +16 -0
- data/lib/rubocop/version.rb +8 -2
- metadata +8 -3
@@ -76,6 +76,14 @@ module RuboCop
|
|
76
76
|
#
|
77
77
|
# def b
|
78
78
|
# end
|
79
|
+
#
|
80
|
+
# @example AllowAdjacentOneLineDefs: true
|
81
|
+
#
|
82
|
+
# # good
|
83
|
+
# class ErrorA < BaseError; end
|
84
|
+
# class ErrorB < BaseError; end
|
85
|
+
# class ErrorC < BaseError; end
|
86
|
+
#
|
79
87
|
class EmptyLineBetweenDefs < Base
|
80
88
|
include RangeHelp
|
81
89
|
extend AutoCorrector
|
@@ -113,8 +121,8 @@ module RuboCop
|
|
113
121
|
|
114
122
|
def autocorrect(corrector, prev_def, node)
|
115
123
|
# finds position of first newline
|
116
|
-
end_pos = prev_def.
|
117
|
-
source_buffer = prev_def.
|
124
|
+
end_pos = end_loc(prev_def).end_pos
|
125
|
+
source_buffer = end_loc(prev_def).source_buffer
|
118
126
|
newline_pos = source_buffer.source.index("\n", end_pos)
|
119
127
|
|
120
128
|
# Handle the case when multiple one-liners are on the same line.
|
@@ -198,7 +206,15 @@ module RuboCop
|
|
198
206
|
end
|
199
207
|
|
200
208
|
def def_end(node)
|
201
|
-
node.
|
209
|
+
end_loc(node).line
|
210
|
+
end
|
211
|
+
|
212
|
+
def end_loc(node)
|
213
|
+
if node.def_type? && node.endless?
|
214
|
+
node.loc.expression.end
|
215
|
+
else
|
216
|
+
node.loc.end
|
217
|
+
end
|
202
218
|
end
|
203
219
|
|
204
220
|
def autocorrect_remove_lines(corrector, newline_pos, count)
|
@@ -70,6 +70,7 @@ module RuboCop
|
|
70
70
|
return unless outermost_send.loc.end
|
71
71
|
return unless heredoc_arg.first_line != outermost_send.loc.end.line
|
72
72
|
return if subsequent_closing_parentheses_in_same_line?(outermost_send)
|
73
|
+
return if exist_argument_between_heredoc_end_and_closing_parentheses?(node)
|
73
74
|
|
74
75
|
add_offense(outermost_send.loc.end) do |corrector|
|
75
76
|
autocorrect(corrector, outermost_send)
|
@@ -215,6 +216,19 @@ module RuboCop
|
|
215
216
|
end
|
216
217
|
end
|
217
218
|
|
219
|
+
def exist_argument_between_heredoc_end_and_closing_parentheses?(node)
|
220
|
+
return false unless (heredoc_end = find_most_bottom_of_heredoc_end(node.arguments))
|
221
|
+
|
222
|
+
heredoc_end < node.loc.end.begin_pos &&
|
223
|
+
range_between(heredoc_end, node.loc.end.begin_pos).source.strip != ''
|
224
|
+
end
|
225
|
+
|
226
|
+
def find_most_bottom_of_heredoc_end(arguments)
|
227
|
+
arguments.map do |argument|
|
228
|
+
argument.loc.heredoc_end.end_pos if argument.loc.respond_to?(:heredoc_end)
|
229
|
+
end.compact.max
|
230
|
+
end
|
231
|
+
|
218
232
|
# Internal trailing comma helpers.
|
219
233
|
|
220
234
|
def remove_internal_trailing_comma(node, corrector)
|
@@ -191,16 +191,9 @@ module RuboCop
|
|
191
191
|
end
|
192
192
|
|
193
193
|
def begin_end_alignment_style
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
# config.for_cop('Layout/BeginEndAlignment')['Enabled'] &&
|
198
|
-
# config.for_cop('Layout/BeginEndAlignment')['EnforcedStyleAlignWith']
|
199
|
-
if config.for_all_cops['NewCops'] == 'enable' ||
|
200
|
-
config.for_cop('Layout/BeginEndAlignment')['Enabled'] &&
|
201
|
-
config.for_cop('Layout/BeginEndAlignment')['Enabled'] != 'pending'
|
202
|
-
config.for_cop('Layout/BeginEndAlignment')['EnforcedStyleAlignWith']
|
203
|
-
end
|
194
|
+
begin_end_alignment_conf = config.for_cop('Layout/BeginEndAlignment')
|
195
|
+
|
196
|
+
begin_end_alignment_conf['Enabled'] && begin_end_alignment_conf['EnforcedStyleAlignWith']
|
204
197
|
end
|
205
198
|
end
|
206
199
|
end
|
@@ -106,6 +106,7 @@ module RuboCop
|
|
106
106
|
def space_missing(left_brace)
|
107
107
|
add_offense(left_brace, message: MISSING_MSG) do |corrector|
|
108
108
|
autocorrect(corrector, left_brace)
|
109
|
+
opposite_style_detected
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
@@ -114,6 +115,7 @@ module RuboCop
|
|
114
115
|
|
115
116
|
add_offense(space, message: DETECTED_MSG) do |corrector|
|
116
117
|
autocorrect(corrector, space)
|
118
|
+
opposite_style_detected
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Layout
|
6
|
+
# Checks for space between the name of a receiver and a left
|
7
|
+
# brackets.
|
8
|
+
#
|
9
|
+
# This cop is marked as unsafe because it can occur false positives
|
10
|
+
# for `do_something [this_is_an_array_literal_argument]` that take
|
11
|
+
# an array without parentheses as an argument.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# collection [index_or_key]
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# collection[index_or_key]
|
20
|
+
#
|
21
|
+
class SpaceBeforeBrackets < Base
|
22
|
+
include RangeHelp
|
23
|
+
extend AutoCorrector
|
24
|
+
|
25
|
+
MSG = 'Remove the space before the opening brackets.'
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
return if node.parenthesized? || node.parent&.send_type?
|
29
|
+
return unless (first_argument = node.first_argument)
|
30
|
+
|
31
|
+
begin_pos = first_argument.source_range.begin_pos
|
32
|
+
|
33
|
+
return unless (range = offense_range(node, first_argument, begin_pos))
|
34
|
+
|
35
|
+
register_offense(range)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def offense_range(node, first_argument, begin_pos)
|
41
|
+
if space_before_brackets?(node, first_argument)
|
42
|
+
range_between(node.loc.selector.end_pos, begin_pos)
|
43
|
+
elsif node.method?(:[]=)
|
44
|
+
end_pos = node.receiver.source_range.end_pos
|
45
|
+
|
46
|
+
return if begin_pos - end_pos == 1
|
47
|
+
|
48
|
+
range_between(end_pos, begin_pos - 1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def register_offense(range)
|
53
|
+
add_offense(range) do |corrector|
|
54
|
+
corrector.remove(range)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def space_before_brackets?(node, first_argument)
|
59
|
+
node.receiver.nil? && first_argument.array_type? && node.arguments.size == 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -111,7 +111,8 @@ module RuboCop
|
|
111
111
|
braces_with_contents_inside(node, inner)
|
112
112
|
elsif style_for_empty_braces == :no_space
|
113
113
|
offense(range.begin_pos, range.end_pos,
|
114
|
-
'Space inside empty braces detected.'
|
114
|
+
'Space inside empty braces detected.',
|
115
|
+
'EnforcedStyleForEmptyBraces')
|
115
116
|
end
|
116
117
|
end
|
117
118
|
end
|
@@ -120,7 +121,8 @@ module RuboCop
|
|
120
121
|
return if style_for_empty_braces != :space
|
121
122
|
|
122
123
|
offense(left_brace.begin_pos, right_brace.end_pos,
|
123
|
-
'Space missing inside empty braces.'
|
124
|
+
'Space missing inside empty braces.',
|
125
|
+
'EnforcedStyleForEmptyBraces')
|
124
126
|
end
|
125
127
|
|
126
128
|
def braces_with_contents_inside(node, inner)
|
@@ -164,9 +166,9 @@ module RuboCop
|
|
164
166
|
if left_brace.end_pos == args_delimiter.begin_pos &&
|
165
167
|
cop_config['SpaceBeforeBlockParameters']
|
166
168
|
offense(left_brace.begin_pos, args_delimiter.end_pos,
|
167
|
-
'Space between { and | missing.')
|
168
|
-
|
169
|
-
|
169
|
+
'Space between { and | missing.')
|
170
|
+
else
|
171
|
+
correct_style_detected
|
170
172
|
end
|
171
173
|
else
|
172
174
|
# We indicate the position after the left brace. Otherwise it's
|
@@ -179,11 +181,11 @@ module RuboCop
|
|
179
181
|
|
180
182
|
def space_inside_left_brace(left_brace, args_delimiter)
|
181
183
|
if pipe?(args_delimiter)
|
182
|
-
|
184
|
+
if cop_config['SpaceBeforeBlockParameters']
|
185
|
+
correct_style_detected
|
186
|
+
else
|
183
187
|
offense(left_brace.end_pos, args_delimiter.begin_pos,
|
184
|
-
'Space between { and | detected.')
|
185
|
-
opposite_style_detected
|
186
|
-
end
|
188
|
+
'Space between { and | detected.')
|
187
189
|
end
|
188
190
|
else
|
189
191
|
brace_with_space = range_with_surrounding_space(range: left_brace,
|
@@ -220,7 +222,7 @@ module RuboCop
|
|
220
222
|
end
|
221
223
|
end
|
222
224
|
|
223
|
-
def offense(begin_pos, end_pos, msg)
|
225
|
+
def offense(begin_pos, end_pos, msg, style_param = 'EnforcedStyle')
|
224
226
|
range = range_between(begin_pos, end_pos)
|
225
227
|
add_offense(range, message: msg) do |corrector|
|
226
228
|
case range.source
|
@@ -229,6 +231,7 @@ module RuboCop
|
|
229
231
|
when '{|' then corrector.replace(range, '{ |')
|
230
232
|
else corrector.insert_before(range, ' ')
|
231
233
|
end
|
234
|
+
opposite_style_detected if style_param == 'EnforcedStyle'
|
232
235
|
end
|
233
236
|
end
|
234
237
|
|
@@ -112,13 +112,13 @@ module RuboCop
|
|
112
112
|
|
113
113
|
def incorrect_style_detected(token1, token2,
|
114
114
|
expect_space, is_empty_braces)
|
115
|
-
return unless ambiguous_or_unexpected_style_detected(style, token1.text == token2.text)
|
116
|
-
|
117
115
|
brace = (token1.text == '{' ? token1 : token2).pos
|
118
116
|
range = expect_space ? brace : space_range(brace)
|
117
|
+
detected_style = expect_space ? 'no_space' : 'space'
|
119
118
|
|
120
119
|
add_offense(range, message: message(brace, is_empty_braces, expect_space)) do |corrector|
|
121
120
|
autocorrect(corrector, range)
|
121
|
+
ambiguous_or_unexpected_style_detected(detected_style, token1.text == token2.text)
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for mistyped shorthand assignments.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# x =- y
|
11
|
+
# x =+ y
|
12
|
+
# x =* y
|
13
|
+
# x =! y
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# x -= y # or x = -y
|
17
|
+
# x += y # or x = +y
|
18
|
+
# x *= y # or x = *y
|
19
|
+
# x != y # or x = !y
|
20
|
+
#
|
21
|
+
class AmbiguousAssignment < Base
|
22
|
+
include RangeHelp
|
23
|
+
|
24
|
+
MSG = 'Suspicious assignment detected. Did you mean `%<op>s`?'
|
25
|
+
|
26
|
+
SIMPLE_ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn casgn].freeze
|
27
|
+
|
28
|
+
MISTAKES = {
|
29
|
+
'=-' => '-=',
|
30
|
+
'=+' => '+=',
|
31
|
+
'=*' => '*=',
|
32
|
+
'=!' => '!='
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
def on_asgn(node)
|
36
|
+
return unless (rhs = rhs(node))
|
37
|
+
|
38
|
+
range = range_between(node.loc.operator.end_pos - 1, rhs.source_range.begin_pos + 1)
|
39
|
+
source = range.source
|
40
|
+
return unless MISTAKES.key?(source)
|
41
|
+
|
42
|
+
add_offense(range, message: format(MSG, op: MISTAKES[source]))
|
43
|
+
end
|
44
|
+
|
45
|
+
SIMPLE_ASSIGNMENT_TYPES.each { |asgn_type| alias_method :"on_#{asgn_type}", :on_asgn }
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def rhs(node)
|
50
|
+
if node.casgn_type?
|
51
|
+
node.children[2]
|
52
|
+
else
|
53
|
+
node.children[1]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -17,6 +17,7 @@ module RuboCop
|
|
17
17
|
#
|
18
18
|
# @example
|
19
19
|
# # bad
|
20
|
+
# x / x
|
20
21
|
# x.top >= x.top
|
21
22
|
#
|
22
23
|
# if a.x != 0 && a.x != 0
|
@@ -27,15 +28,19 @@ module RuboCop
|
|
27
28
|
# left_child || left_child
|
28
29
|
# end
|
29
30
|
#
|
31
|
+
# # good
|
32
|
+
# x + x
|
33
|
+
# 1 << 1
|
34
|
+
#
|
30
35
|
class BinaryOperatorWithIdenticalOperands < Base
|
31
36
|
MSG = 'Binary operator `%<op>s` has identical operands.'
|
32
|
-
|
37
|
+
ALLOWED_MATH_OPERATORS = %i[+ * ** << >>].to_set.freeze
|
33
38
|
|
34
39
|
def on_send(node)
|
35
40
|
return unless node.binary_operation?
|
36
41
|
|
37
42
|
lhs, operation, rhs = *node
|
38
|
-
return if
|
43
|
+
return if ALLOWED_MATH_OPERATORS.include?(node.method_name)
|
39
44
|
|
40
45
|
add_offense(node, message: format(MSG, op: operation)) if lhs == rhs
|
41
46
|
end
|
@@ -6,6 +6,15 @@ module RuboCop
|
|
6
6
|
# This cop checks that there are no repeated bodies
|
7
7
|
# within `if/unless`, `case-when` and `rescue` constructs.
|
8
8
|
#
|
9
|
+
# With `IgnoreLiteralBranches: true`, branches are not registered
|
10
|
+
# as offenses if they return a basic literal value (string, symbol,
|
11
|
+
# integer, float, rational, complex, `true`, `false`, or `nil`), or
|
12
|
+
# return an array, hash, regexp or range that only contains one of
|
13
|
+
# the above basic literal values.
|
14
|
+
#
|
15
|
+
# With `IgnoreConstantBranches: true`, branches are not registered
|
16
|
+
# as offenses if they return a constant value.
|
17
|
+
#
|
9
18
|
# @example
|
10
19
|
# # bad
|
11
20
|
# if foo
|
@@ -56,14 +65,33 @@ module RuboCop
|
|
56
65
|
# handle_error
|
57
66
|
# end
|
58
67
|
#
|
68
|
+
# @example IgnoreLiteralBranches: true
|
69
|
+
# # good
|
70
|
+
# case size
|
71
|
+
# when "small" then 100
|
72
|
+
# when "medium" then 250
|
73
|
+
# when "large" then 1000
|
74
|
+
# else 250
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# @example IgnoreLiteralBranches: true
|
78
|
+
# # good
|
79
|
+
# case size
|
80
|
+
# when "small" then SMALL_SIZE
|
81
|
+
# when "medium" then MEDIUM_SIZE
|
82
|
+
# when "large" then LARGE_SIZE
|
83
|
+
# else MEDIUM_SIZE
|
84
|
+
# end
|
85
|
+
#
|
59
86
|
class DuplicateBranch < Base
|
60
87
|
include RescueNode
|
61
88
|
|
62
89
|
MSG = 'Duplicate branch body detected.'
|
63
90
|
|
64
91
|
def on_branching_statement(node)
|
65
|
-
branches
|
66
|
-
|
92
|
+
branches(node).each_with_object(Set.new) do |branch, previous|
|
93
|
+
next unless consider_branch?(branch)
|
94
|
+
|
67
95
|
add_offense(offense_range(branch)) unless previous.add?(branch)
|
68
96
|
end
|
69
97
|
end
|
@@ -87,6 +115,40 @@ module RuboCop
|
|
87
115
|
parent.source_range
|
88
116
|
end
|
89
117
|
end
|
118
|
+
|
119
|
+
def branches(node)
|
120
|
+
node.branches.compact
|
121
|
+
end
|
122
|
+
|
123
|
+
def consider_branch?(branch)
|
124
|
+
return false if ignore_literal_branches? && literal_branch?(branch)
|
125
|
+
return false if ignore_constant_branches? && const_branch?(branch)
|
126
|
+
|
127
|
+
true
|
128
|
+
end
|
129
|
+
|
130
|
+
def ignore_literal_branches?
|
131
|
+
cop_config.fetch('IgnoreLiteralBranches', false)
|
132
|
+
end
|
133
|
+
|
134
|
+
def ignore_constant_branches?
|
135
|
+
cop_config.fetch('IgnoreConstantBranches', false)
|
136
|
+
end
|
137
|
+
|
138
|
+
def literal_branch?(branch) # rubocop:disable Metrics/CyclomaticComplexity
|
139
|
+
return false if !branch.literal? || branch.xstr_type?
|
140
|
+
return true if branch.basic_literal?
|
141
|
+
|
142
|
+
branch.each_descendant.all? do |node|
|
143
|
+
node.basic_literal? ||
|
144
|
+
node.pair_type? || # hash keys and values are contained within a `pair` node
|
145
|
+
(node.const_type? && ignore_constant_branches?)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def const_branch?(branch)
|
150
|
+
branch.const_type?
|
151
|
+
end
|
90
152
|
end
|
91
153
|
end
|
92
154
|
end
|
@@ -8,47 +8,66 @@ module RuboCop
|
|
8
8
|
# @example
|
9
9
|
#
|
10
10
|
# # bad
|
11
|
-
#
|
12
11
|
# a = *[1, 2, 3]
|
13
12
|
# a = *'a'
|
14
13
|
# a = *1
|
15
|
-
#
|
16
|
-
# begin
|
17
|
-
# foo
|
18
|
-
# rescue *[StandardError, ApplicationError]
|
19
|
-
# bar
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# case foo
|
23
|
-
# when *[1, 2, 3]
|
24
|
-
# bar
|
25
|
-
# else
|
26
|
-
# baz
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# @example
|
14
|
+
# ['a', 'b', *%w(c d e), 'f', 'g']
|
30
15
|
#
|
31
16
|
# # good
|
32
|
-
#
|
33
17
|
# c = [1, 2, 3]
|
34
18
|
# a = *c
|
35
19
|
# a, b = *c
|
36
20
|
# a, *b = *c
|
37
21
|
# a = *1..10
|
38
22
|
# a = ['a']
|
23
|
+
# ['a', 'b', 'c', 'd', 'e', 'f', 'g']
|
39
24
|
#
|
25
|
+
# # bad
|
26
|
+
# do_something(*['foo', 'bar', 'baz'])
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# do_something('foo', 'bar', 'baz')
|
30
|
+
#
|
31
|
+
# # bad
|
32
|
+
# begin
|
33
|
+
# foo
|
34
|
+
# rescue *[StandardError, ApplicationError]
|
35
|
+
# bar
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # good
|
40
39
|
# begin
|
41
40
|
# foo
|
42
41
|
# rescue StandardError, ApplicationError
|
43
42
|
# bar
|
44
43
|
# end
|
45
44
|
#
|
45
|
+
# # bad
|
46
|
+
# case foo
|
47
|
+
# when *[1, 2, 3]
|
48
|
+
# bar
|
49
|
+
# else
|
50
|
+
# baz
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# # good
|
46
54
|
# case foo
|
47
55
|
# when 1, 2, 3
|
48
56
|
# bar
|
49
57
|
# else
|
50
58
|
# baz
|
51
59
|
# end
|
60
|
+
#
|
61
|
+
# @example AllowPercentLiteralArrayArgument: true (default)
|
62
|
+
#
|
63
|
+
# # good
|
64
|
+
# do_something(*%w[foo bar baz])
|
65
|
+
#
|
66
|
+
# @example AllowPercentLiteralArrayArgument: false
|
67
|
+
#
|
68
|
+
# # bad
|
69
|
+
# do_something(*%w[foo bar baz])
|
70
|
+
#
|
52
71
|
class RedundantSplatExpansion < Base
|
53
72
|
extend AutoCorrector
|
54
73
|
|
@@ -75,6 +94,9 @@ module RuboCop
|
|
75
94
|
redundant_splat_expansion(node) do
|
76
95
|
if array_splat?(node) &&
|
77
96
|
(method_argument?(node) || part_of_an_array?(node))
|
97
|
+
return if allow_percent_literal_array_argument? &&
|
98
|
+
use_percent_literal_array_argument?(node)
|
99
|
+
|
78
100
|
add_offense(node, message: ARRAY_PARAM_MSG) do |corrector|
|
79
101
|
autocorrect(corrector, node)
|
80
102
|
end
|
@@ -170,6 +192,17 @@ module RuboCop
|
|
170
192
|
elements.join(', ')
|
171
193
|
end
|
172
194
|
end
|
195
|
+
|
196
|
+
def use_percent_literal_array_argument?(node)
|
197
|
+
argument = node.children.first
|
198
|
+
|
199
|
+
node.parent.send_type? &&
|
200
|
+
(argument.percent_literal?(:string) || argument.percent_literal?(:symbol))
|
201
|
+
end
|
202
|
+
|
203
|
+
def allow_percent_literal_array_argument?
|
204
|
+
cop_config.fetch('AllowPercentLiteralArrayArgument', true)
|
205
|
+
end
|
173
206
|
end
|
174
207
|
end
|
175
208
|
end
|