rubocop 1.13.0 → 1.17.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 +3 -1
- data/config/default.yml +68 -8
- data/lib/rubocop.rb +9 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +99 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +29 -11
- data/lib/rubocop/cop/layout/case_indentation.rb +57 -9
- data/lib/rubocop/cop/layout/dot_position.rb +7 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +12 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +34 -9
- data/lib/rubocop/cop/layout/indentation_width.rb +13 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +24 -10
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +53 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +28 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +6 -0
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +83 -39
- data/lib/rubocop/cop/lint/empty_block.rb +18 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +62 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +105 -74
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +2 -12
- data/lib/rubocop/cop/lint/unreachable_loop.rb +12 -2
- data/lib/rubocop/cop/lint/unused_block_argument.rb +7 -1
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +3 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +19 -3
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
- data/lib/rubocop/cop/mixin/gem_declaration.rb +13 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +14 -3
- data/lib/rubocop/cop/mixin/string_literals_help.rb +3 -5
- data/lib/rubocop/cop/mixin/symbol_help.rb +13 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +17 -5
- data/lib/rubocop/cop/style/empty_literal.rb +8 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +18 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +58 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -4
- data/lib/rubocop/cop/style/in_pattern_then.rb +56 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +62 -0
- data/lib/rubocop/cop/style/multiline_when_then.rb +2 -11
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +17 -9
- data/lib/rubocop/cop/style/nil_lambda.rb +29 -12
- data/lib/rubocop/cop/style/quoted_symbols.rb +110 -0
- data/lib/rubocop/cop/style/raise_args.rb +2 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +24 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +9 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +8 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
- data/lib/rubocop/cop/style/string_literals.rb +1 -0
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +1 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +83 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +65 -0
- data/lib/rubocop/cop/style/when_then.rb +6 -2
- data/lib/rubocop/cop/variable_force/branch.rb +15 -0
- data/lib/rubocop/directive_comment.rb +58 -6
- data/lib/rubocop/formatter/junit_formatter.rb +21 -6
- data/lib/rubocop/options.rb +14 -20
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +10 -2
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/target_finder.rb +9 -2
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +18 -9
@@ -35,17 +35,7 @@ module RuboCop
|
|
35
35
|
MSG = 'Do not use `then` for multiline `when` statement.'
|
36
36
|
|
37
37
|
def on_when(node)
|
38
|
-
|
39
|
-
return unless node.then?
|
40
|
-
|
41
|
-
# Single line usage of `then` is not an offense
|
42
|
-
return if !node.children.last.nil? && !node.multiline?
|
43
|
-
|
44
|
-
# Requires `then` for write `when` and its body on the same line.
|
45
|
-
return if require_then?(node)
|
46
|
-
|
47
|
-
# For arrays and hashes there's no offense
|
48
|
-
return if accept_node_type?(node.body)
|
38
|
+
return if !node.then? || require_then?(node)
|
49
39
|
|
50
40
|
range = node.loc.begin
|
51
41
|
add_offense(range) do |corrector|
|
@@ -57,6 +47,7 @@ module RuboCop
|
|
57
47
|
|
58
48
|
private
|
59
49
|
|
50
|
+
# Requires `then` for write `when` and its body on the same line.
|
60
51
|
def require_then?(when_node)
|
61
52
|
unless when_node.conditions.first.first_line == when_node.conditions.last.last_line
|
62
53
|
return true
|
@@ -29,7 +29,6 @@ module RuboCop
|
|
29
29
|
#
|
30
30
|
class NegatedIfElseCondition < Base
|
31
31
|
include RangeHelp
|
32
|
-
include CommentsHelp
|
33
32
|
extend AutoCorrector
|
34
33
|
|
35
34
|
MSG = 'Invert the negated condition and swap the %<type>s branches.'
|
@@ -98,21 +97,30 @@ module RuboCop
|
|
98
97
|
if node.if_branch.nil?
|
99
98
|
corrector.remove(range_by_whole_lines(node.loc.else, include_final_newline: true))
|
100
99
|
else
|
101
|
-
if_range =
|
102
|
-
else_range =
|
100
|
+
if_range = if_range(node)
|
101
|
+
else_range = else_range(node)
|
103
102
|
|
104
103
|
corrector.replace(if_range, else_range.source)
|
105
104
|
corrector.replace(else_range, if_range.source)
|
106
105
|
end
|
107
106
|
end
|
108
107
|
|
109
|
-
|
110
|
-
|
111
|
-
|
108
|
+
# Collect the entire if branch, including whitespace and comments
|
109
|
+
def if_range(node)
|
110
|
+
if node.ternary?
|
111
|
+
node.if_branch
|
112
|
+
else
|
113
|
+
range_between(node.condition.loc.expression.end_pos, node.loc.else.begin_pos)
|
114
|
+
end
|
115
|
+
end
|
112
116
|
|
113
|
-
|
114
|
-
|
115
|
-
|
117
|
+
# Collect the entire else branch, including whitespace and comments
|
118
|
+
def else_range(node)
|
119
|
+
if node.ternary?
|
120
|
+
node.else_branch
|
121
|
+
else
|
122
|
+
range_between(node.loc.else.end_pos, node.loc.end.begin_pos)
|
123
|
+
end
|
116
124
|
end
|
117
125
|
end
|
118
126
|
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop checks for lambdas that always return nil,
|
7
|
-
# with an empty lambda instead.
|
6
|
+
# This cop checks for lambdas and procs that always return nil,
|
7
|
+
# which can be replaced with an empty lambda or proc instead.
|
8
8
|
#
|
9
9
|
# @example
|
10
10
|
# # bad
|
@@ -14,6 +14,12 @@ module RuboCop
|
|
14
14
|
# next nil
|
15
15
|
# end
|
16
16
|
#
|
17
|
+
# proc { nil }
|
18
|
+
#
|
19
|
+
# Proc.new do
|
20
|
+
# break nil
|
21
|
+
# end
|
22
|
+
#
|
17
23
|
# # good
|
18
24
|
# -> {}
|
19
25
|
#
|
@@ -22,11 +28,15 @@ module RuboCop
|
|
22
28
|
#
|
23
29
|
# -> (x) { nil if x }
|
24
30
|
#
|
31
|
+
# proc {}
|
32
|
+
#
|
33
|
+
# Proc.new { nil if x }
|
34
|
+
#
|
25
35
|
class NilLambda < Base
|
26
36
|
extend AutoCorrector
|
27
37
|
include RangeHelp
|
28
38
|
|
29
|
-
MSG = 'Use an empty
|
39
|
+
MSG = 'Use an empty %<type>s instead of always returning nil.'
|
30
40
|
|
31
41
|
# @!method nil_return?(node)
|
32
42
|
def_node_matcher :nil_return?, <<~PATTERN
|
@@ -34,19 +44,26 @@ module RuboCop
|
|
34
44
|
PATTERN
|
35
45
|
|
36
46
|
def on_block(node)
|
37
|
-
return unless node.lambda?
|
47
|
+
return unless node.lambda? || node.proc?
|
38
48
|
return unless nil_return?(node.body)
|
39
49
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
else
|
44
|
-
range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
|
45
|
-
end
|
46
|
-
|
47
|
-
corrector.remove(range)
|
50
|
+
message = format(MSG, type: node.lambda? ? 'lambda' : 'proc')
|
51
|
+
add_offense(node, message: message) do |corrector|
|
52
|
+
autocorrect(corrector, node)
|
48
53
|
end
|
49
54
|
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def autocorrect(corrector, node)
|
59
|
+
range = if node.single_line?
|
60
|
+
range_with_surrounding_space(range: node.body.loc.expression)
|
61
|
+
else
|
62
|
+
range_by_whole_lines(node.body.loc.expression, include_final_newline: true)
|
63
|
+
end
|
64
|
+
|
65
|
+
corrector.remove(range)
|
66
|
+
end
|
50
67
|
end
|
51
68
|
end
|
52
69
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks if the quotes used for quoted symbols match the configured defaults.
|
7
|
+
# By default uses the same configuration as `Style/StringLiterals`.
|
8
|
+
#
|
9
|
+
# String interpolation is always kept in double quotes.
|
10
|
+
#
|
11
|
+
# Note: `Lint/SymbolConversion` can be used in parallel to ensure that symbols
|
12
|
+
# are not quoted that don't need to be. This cop is for configuring the quoting
|
13
|
+
# style to use for symbols that require quotes.
|
14
|
+
#
|
15
|
+
# @example EnforcedStyle: same_as_string_literals (default) / single_quotes
|
16
|
+
# # bad
|
17
|
+
# :"abc-def"
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# :'abc-def'
|
21
|
+
# :"#{str}"
|
22
|
+
# :"a\'b"
|
23
|
+
#
|
24
|
+
# @example EnforcedStyle: double_quotes
|
25
|
+
# # bad
|
26
|
+
# :'abc-def'
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# :"abc-def"
|
30
|
+
# :"#{str}"
|
31
|
+
# :"a\'b"
|
32
|
+
class QuotedSymbols < Base
|
33
|
+
include ConfigurableEnforcedStyle
|
34
|
+
include SymbolHelp
|
35
|
+
include StringLiteralsHelp
|
36
|
+
extend AutoCorrector
|
37
|
+
|
38
|
+
MSG_SINGLE = "Prefer single-quoted symbols when you don't need string interpolation " \
|
39
|
+
'or special symbols.'
|
40
|
+
MSG_DOUBLE = 'Prefer double-quoted symbols unless you need single quotes to ' \
|
41
|
+
'avoid extra backslashes for escaping.'
|
42
|
+
|
43
|
+
def on_sym(node)
|
44
|
+
return unless quoted?(node)
|
45
|
+
|
46
|
+
message = style == :single_quotes ? MSG_SINGLE : MSG_DOUBLE
|
47
|
+
|
48
|
+
if wrong_quotes?(node)
|
49
|
+
add_offense(node, message: message) do |corrector|
|
50
|
+
opposite_style_detected
|
51
|
+
autocorrect(corrector, node)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
correct_style_detected
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def autocorrect(corrector, node)
|
61
|
+
str = if hash_colon_key?(node)
|
62
|
+
# strip quotes
|
63
|
+
correct_quotes(node.source[1..-2])
|
64
|
+
else
|
65
|
+
# strip leading `:` and quotes
|
66
|
+
":#{correct_quotes(node.source[2..-2])}"
|
67
|
+
end
|
68
|
+
|
69
|
+
corrector.replace(node, str)
|
70
|
+
end
|
71
|
+
|
72
|
+
def hash_colon_key?(node)
|
73
|
+
# Is the node a hash key with the colon style?
|
74
|
+
hash_key?(node) && node.parent.colon?
|
75
|
+
end
|
76
|
+
|
77
|
+
def correct_quotes(str)
|
78
|
+
if style == :single_quotes
|
79
|
+
to_string_literal(str)
|
80
|
+
else
|
81
|
+
str.inspect
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def style
|
86
|
+
return super unless super == :same_as_string_literals
|
87
|
+
|
88
|
+
string_literals_config = config.for_cop('Style/StringLiterals')
|
89
|
+
return :single_quotes unless string_literals_config['Enabled']
|
90
|
+
|
91
|
+
string_literals_config['EnforcedStyle'].to_sym
|
92
|
+
end
|
93
|
+
|
94
|
+
def alternative_style
|
95
|
+
(supported_styles - [style, :same_as_string_literals]).first
|
96
|
+
end
|
97
|
+
|
98
|
+
def quoted?(sym_node)
|
99
|
+
sym_node.source.match?(/\A:?(['"]).*?\1\z/m)
|
100
|
+
end
|
101
|
+
|
102
|
+
def wrong_quotes?(node)
|
103
|
+
return super if hash_key?(node)
|
104
|
+
|
105
|
+
super(node.source[1..-1])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -23,6 +23,7 @@ module RuboCop
|
|
23
23
|
# # good
|
24
24
|
# raise StandardError, 'message'
|
25
25
|
# fail 'message'
|
26
|
+
# raise MyCustomError
|
26
27
|
# raise MyCustomError.new(arg1, arg2, arg3)
|
27
28
|
# raise MyKwArgError.new(key1: val1, key2: val2)
|
28
29
|
#
|
@@ -37,6 +38,7 @@ module RuboCop
|
|
37
38
|
#
|
38
39
|
# # good
|
39
40
|
# raise StandardError.new('message')
|
41
|
+
# raise MyCustomError
|
40
42
|
# raise MyCustomError.new(arg1, arg2, arg3)
|
41
43
|
# fail 'message'
|
42
44
|
class RaiseArgs < Base
|
@@ -110,7 +110,7 @@ module RuboCop
|
|
110
110
|
first_child = node.children.first
|
111
111
|
|
112
112
|
source = first_child.source
|
113
|
-
source = "(#{source})" if first_child.if_type?
|
113
|
+
source = "(#{source})" if first_child.if_type? && first_child.modifier_form?
|
114
114
|
|
115
115
|
corrector.replace(offense_range, source)
|
116
116
|
corrector.remove(range_between(offense_range.end_pos, first_child.source_range.end_pos))
|
@@ -92,7 +92,7 @@ module RuboCop
|
|
92
92
|
|
93
93
|
def on_masgn(node)
|
94
94
|
lhs, rhs = *node
|
95
|
-
|
95
|
+
add_masgn_lhs_variables(rhs, lhs)
|
96
96
|
end
|
97
97
|
|
98
98
|
def on_lvasgn(node)
|
@@ -106,7 +106,7 @@ module RuboCop
|
|
106
106
|
|
107
107
|
return if allowed_send_node?(node)
|
108
108
|
|
109
|
-
add_offense(node) do |corrector|
|
109
|
+
add_offense(node.receiver) do |corrector|
|
110
110
|
corrector.remove(node.receiver)
|
111
111
|
corrector.remove(node.loc.dot)
|
112
112
|
end
|
@@ -116,6 +116,22 @@ module RuboCop
|
|
116
116
|
add_scope(node, @local_variables_scopes[node])
|
117
117
|
end
|
118
118
|
|
119
|
+
def on_if(node)
|
120
|
+
# Allow conditional nodes to use `self` in the condition if that variable
|
121
|
+
# name is used in an `lvasgn` or `masgn` within the `if`.
|
122
|
+
node.child_nodes.each do |child_node|
|
123
|
+
lhs, _rhs = *child_node
|
124
|
+
|
125
|
+
if child_node.lvasgn_type?
|
126
|
+
add_lhs_to_local_variables_scopes(node.condition, lhs)
|
127
|
+
elsif child_node.masgn_type?
|
128
|
+
add_masgn_lhs_variables(node.condition, lhs)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
alias on_while on_if
|
133
|
+
alias on_until on_if
|
134
|
+
|
119
135
|
private
|
120
136
|
|
121
137
|
def add_scope(node, local_variables = [])
|
@@ -163,6 +179,12 @@ module RuboCop
|
|
163
179
|
@local_variables_scopes[rhs] << lhs
|
164
180
|
end
|
165
181
|
end
|
182
|
+
|
183
|
+
def add_masgn_lhs_variables(rhs, lhs)
|
184
|
+
lhs.children.each do |child|
|
185
|
+
add_lhs_to_local_variables_scopes(rhs, child.to_a.first)
|
186
|
+
end
|
187
|
+
end
|
166
188
|
end
|
167
189
|
end
|
168
190
|
end
|
@@ -117,7 +117,7 @@ module RuboCop
|
|
117
117
|
def allowed_percent_r_literal?(node)
|
118
118
|
style == :slashes && contains_disallowed_slash?(node) ||
|
119
119
|
style == :percent_r ||
|
120
|
-
allowed_mixed_percent_r?(node)
|
120
|
+
allowed_mixed_percent_r?(node) || omit_parentheses_style?(node)
|
121
121
|
end
|
122
122
|
|
123
123
|
def allowed_mixed_percent_r?(node)
|
@@ -149,6 +149,14 @@ module RuboCop
|
|
149
149
|
config.for_cop('Style/PercentLiteralDelimiters') ['PreferredDelimiters']['%r'].chars
|
150
150
|
end
|
151
151
|
|
152
|
+
def omit_parentheses_style?(node)
|
153
|
+
return false unless node.parent&.call_type?
|
154
|
+
|
155
|
+
enforced_style = config.for_cop('Style/MethodCallWithArgsParentheses')['EnforcedStyle']
|
156
|
+
|
157
|
+
enforced_style == 'omit_parentheses'
|
158
|
+
end
|
159
|
+
|
152
160
|
def correct_delimiters(node, corrector)
|
153
161
|
replacement = calculate_replacement(node)
|
154
162
|
corrector.replace(node.loc.begin, replacement.first)
|
@@ -68,6 +68,7 @@ module RuboCop
|
|
68
68
|
return false unless endless_method_config['Enabled']
|
69
69
|
return false if endless_method_config['EnforcedStyle'] == 'disallow'
|
70
70
|
return false unless body_node
|
71
|
+
return false if body_node.parent.assignment_method?
|
71
72
|
|
72
73
|
!(body_node.begin_type? || body_node.kwbegin_type?)
|
73
74
|
end
|
@@ -115,15 +116,19 @@ module RuboCop
|
|
115
116
|
end
|
116
117
|
|
117
118
|
def method_body_source(method_body)
|
118
|
-
if
|
119
|
-
method_body.source
|
120
|
-
else
|
119
|
+
if require_parentheses?(method_body)
|
121
120
|
arguments_source = method_body.arguments.map(&:source).join(', ')
|
122
121
|
body_source = "#{method_body.method_name}(#{arguments_source})"
|
123
122
|
|
124
123
|
method_body.receiver ? "#{method_body.receiver.source}.#{body_source}" : body_source
|
124
|
+
else
|
125
|
+
method_body.source
|
125
126
|
end
|
126
127
|
end
|
128
|
+
|
129
|
+
def require_parentheses?(method_body)
|
130
|
+
method_body.send_type? && !method_body.arguments.empty? && !method_body.comparison_method?
|
131
|
+
end
|
127
132
|
end
|
128
133
|
end
|
129
134
|
end
|
@@ -80,10 +80,7 @@ module RuboCop
|
|
80
80
|
def autocorrect(corrector, node, if_branch)
|
81
81
|
corrector.wrap(node.condition, '(', ')') if node.condition.or_type?
|
82
82
|
|
83
|
-
if node.unless?
|
84
|
-
corrector.replace(node.loc.keyword, 'if')
|
85
|
-
corrector.insert_before(node.condition, '!')
|
86
|
-
end
|
83
|
+
correct_from_unless_to_if(corrector, node) if node.unless?
|
87
84
|
|
88
85
|
and_operator = if_branch.unless? ? ' && !' : ' && '
|
89
86
|
if if_branch.modifier_form?
|
@@ -94,6 +91,17 @@ module RuboCop
|
|
94
91
|
end
|
95
92
|
end
|
96
93
|
|
94
|
+
def correct_from_unless_to_if(corrector, node)
|
95
|
+
corrector.replace(node.loc.keyword, 'if')
|
96
|
+
|
97
|
+
condition = node.condition
|
98
|
+
if condition.send_type? && condition.comparison_method? && !condition.parenthesized?
|
99
|
+
corrector.wrap(node.condition, '!(', ')')
|
100
|
+
else
|
101
|
+
corrector.insert_before(node.condition, '!')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
97
105
|
def correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
|
98
106
|
outer_condition = node.condition
|
99
107
|
correct_outer_condition(corrector, outer_condition)
|
@@ -136,7 +144,8 @@ module RuboCop
|
|
136
144
|
end
|
137
145
|
|
138
146
|
def requrie_parentheses?(condition)
|
139
|
-
condition.send_type? && !condition.arguments.empty? && !condition.parenthesized?
|
147
|
+
condition.send_type? && !condition.arguments.empty? && !condition.parenthesized? &&
|
148
|
+
!condition.comparison_method?
|
140
149
|
end
|
141
150
|
|
142
151
|
def arguments_range(node)
|