rubocop 0.41.2 → 0.42.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +2 -3
- data/config/default.yml +13 -0
- data/config/disabled.yml +5 -0
- data/config/enabled.yml +20 -0
- data/lib/rubocop.rb +4 -0
- data/lib/rubocop/ast_node.rb +4 -3
- data/lib/rubocop/config.rb +1 -1
- data/lib/rubocop/config_loader.rb +2 -7
- data/lib/rubocop/cop/cop.rb +3 -3
- data/lib/rubocop/cop/lint/block_alignment.rb +18 -16
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +34 -19
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +9 -1
- data/lib/rubocop/cop/lint/shadowed_exception.rb +23 -3
- data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +41 -4
- data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +3 -5
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +4 -4
- data/lib/rubocop/cop/mixin/space_inside.rb +23 -8
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/offense.rb +33 -10
- data/lib/rubocop/cop/performance/case_when_splat.rb +16 -14
- data/lib/rubocop/cop/performance/sample.rb +0 -1
- data/lib/rubocop/cop/rails/save_bang.rb +77 -0
- data/lib/rubocop/cop/rails/validation.rb +15 -15
- data/lib/rubocop/cop/style/access_modifier_indentation.rb +1 -1
- data/lib/rubocop/cop/style/align_hash.rb +1 -1
- data/lib/rubocop/cop/style/block_comments.rb +1 -3
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +19 -10
- data/lib/rubocop/cop/style/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/style/comment_annotation.rb +14 -14
- data/lib/rubocop/cop/style/comment_indentation.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +25 -26
- data/lib/rubocop/cop/style/dot_position.rb +24 -19
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +22 -8
- data/lib/rubocop/cop/style/each_with_object.rb +11 -1
- data/lib/rubocop/cop/style/else_alignment.rb +1 -1
- data/lib/rubocop/cop/style/empty_lines.rb +22 -11
- data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +9 -6
- data/lib/rubocop/cop/style/empty_lines_around_block_body.rb +14 -14
- data/lib/rubocop/cop/style/empty_lines_around_class_body.rb +8 -5
- data/lib/rubocop/cop/style/empty_lines_around_method_body.rb +12 -8
- data/lib/rubocop/cop/style/empty_lines_around_module_body.rb +17 -4
- data/lib/rubocop/cop/style/empty_literal.rb +12 -7
- data/lib/rubocop/cop/style/for.rb +1 -1
- data/lib/rubocop/cop/style/indent_array.rb +1 -1
- data/lib/rubocop/cop/style/indent_hash.rb +1 -1
- data/lib/rubocop/cop/style/indentation_width.rb +1 -1
- data/lib/rubocop/cop/style/initial_indentation.rb +1 -1
- data/lib/rubocop/cop/style/lambda.rb +2 -3
- data/lib/rubocop/cop/style/method_call_parentheses.rb +6 -4
- data/lib/rubocop/cop/style/method_missing.rb +74 -0
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +1 -1
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +1 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +23 -13
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +142 -0
- data/lib/rubocop/cop/style/op_method.rb +12 -4
- data/lib/rubocop/cop/style/parallel_assignment.rb +11 -3
- data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +9 -6
- data/lib/rubocop/cop/style/single_line_block_params.rb +3 -2
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
- data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/symbol_array.rb +18 -10
- data/lib/rubocop/cop/style/ternary_parentheses.rb +94 -0
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
- data/lib/rubocop/cop/style/unneeded_percent_q.rb +12 -6
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/locatable.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -7
- data/lib/rubocop/formatter/html_formatter.rb +25 -11
- data/lib/rubocop/formatter/text_util.rb +1 -1
- data/lib/rubocop/node_pattern.rb +2 -0
- data/lib/rubocop/processed_source.rb +3 -0
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/runner.rb +18 -7
- data/lib/rubocop/string_util.rb +2 -5
- data/lib/rubocop/version.rb +1 -1
- metadata +7 -3
@@ -4,31 +4,35 @@
|
|
4
4
|
module RuboCop
|
5
5
|
module Cop
|
6
6
|
module Style
|
7
|
-
# This cops checks if empty lines around the bodies of methods
|
8
|
-
# the configuration.
|
7
|
+
# This cops checks if empty lines exist around the bodies of methods.
|
9
8
|
#
|
10
9
|
# @example
|
11
10
|
#
|
12
|
-
#
|
11
|
+
# # good
|
13
12
|
#
|
13
|
+
# def foo
|
14
14
|
# ...
|
15
15
|
# end
|
16
16
|
#
|
17
|
+
# # bad
|
18
|
+
#
|
19
|
+
# def bar
|
20
|
+
#
|
21
|
+
# ...
|
22
|
+
#
|
23
|
+
# end
|
17
24
|
class EmptyLinesAroundMethodBody < Cop
|
18
25
|
include EmptyLinesAroundBody
|
19
26
|
include OnMethodDef
|
20
27
|
|
21
28
|
KIND = 'method'.freeze
|
22
29
|
|
23
|
-
private
|
24
|
-
|
25
30
|
def on_method_def(node, _method_name, _args, body)
|
26
31
|
check(node, body)
|
27
32
|
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
# empty lines around a method body, so we don't make it configurable.
|
34
|
+
private
|
35
|
+
|
32
36
|
def style
|
33
37
|
:no_empty_lines
|
34
38
|
end
|
@@ -9,14 +9,27 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
#
|
12
|
-
#
|
12
|
+
# EnforcedStyle: empty_lines
|
13
13
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
14
|
+
# # good
|
15
|
+
#
|
16
|
+
# module Foo
|
17
|
+
#
|
18
|
+
# def bar
|
19
|
+
# ...
|
20
|
+
# end
|
17
21
|
#
|
18
22
|
# end
|
19
23
|
#
|
24
|
+
# EnforcedStyle: no_empty_lines
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
#
|
28
|
+
# module Foo
|
29
|
+
# def bar
|
30
|
+
# ...
|
31
|
+
# end
|
32
|
+
# end
|
20
33
|
class EmptyLinesAroundModuleBody < Cop
|
21
34
|
include EmptyLinesAroundBody
|
22
35
|
|
@@ -7,9 +7,11 @@ module RuboCop
|
|
7
7
|
# This cop checks for the use of a method, the result of which
|
8
8
|
# would be a literal, like an empty array, hash or string.
|
9
9
|
class EmptyLiteral < Cop
|
10
|
+
include FrozenStringLiteral
|
11
|
+
|
10
12
|
ARR_MSG = 'Use array literal `[]` instead of `Array.new`.'.freeze
|
11
13
|
HASH_MSG = 'Use hash literal `{}` instead of `Hash.new`.'.freeze
|
12
|
-
STR_MSG =
|
14
|
+
STR_MSG = 'Use string literal `%s` instead of `String.new`.'.freeze
|
13
15
|
|
14
16
|
# Empty array node
|
15
17
|
#
|
@@ -39,7 +41,10 @@ module RuboCop
|
|
39
41
|
|
40
42
|
add_offense(node, :expression, HASH_MSG)
|
41
43
|
when STR_NODE
|
42
|
-
|
44
|
+
return if frozen_string_literals_enabled?(processed_source)
|
45
|
+
|
46
|
+
add_offense(node, :expression,
|
47
|
+
format(STR_MSG, preferred_string_literal))
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
@@ -55,17 +60,17 @@ module RuboCop
|
|
55
60
|
return if first_arg_in_method_call_without_parentheses?(node)
|
56
61
|
'{}'
|
57
62
|
when STR_NODE
|
58
|
-
|
59
|
-
'""'
|
60
|
-
else
|
61
|
-
"''"
|
62
|
-
end
|
63
|
+
preferred_string_literal
|
63
64
|
end
|
64
65
|
->(corrector) { corrector.replace(node.source_range, name) }
|
65
66
|
end
|
66
67
|
|
67
68
|
private
|
68
69
|
|
70
|
+
def preferred_string_literal
|
71
|
+
enforce_double_quotes? ? '""' : "''"
|
72
|
+
end
|
73
|
+
|
69
74
|
def enforce_double_quotes?
|
70
75
|
string_literals_config['EnforcedStyle'] == 'double_quotes'
|
71
76
|
end
|
@@ -80,7 +80,7 @@ module RuboCop
|
|
80
80
|
|
81
81
|
expected_column = base_column(left_bracket, left_parenthesis)
|
82
82
|
@column_delta = expected_column - right_bracket.column
|
83
|
-
return if @column_delta
|
83
|
+
return if @column_delta.zero?
|
84
84
|
|
85
85
|
msg = if style == :align_brackets
|
86
86
|
'Indent the right bracket the same as the left bracket.'
|
@@ -85,7 +85,7 @@ module RuboCop
|
|
85
85
|
|
86
86
|
expected_column = base_column(left_brace, left_parenthesis)
|
87
87
|
@column_delta = expected_column - right_brace.column
|
88
|
-
return if @column_delta
|
88
|
+
return if @column_delta.zero?
|
89
89
|
|
90
90
|
msg = if style == :align_braces
|
91
91
|
'Indent the right brace the same as the left brace.'
|
@@ -200,7 +200,7 @@ module RuboCop
|
|
200
200
|
|
201
201
|
indentation = body_node.loc.column - effective_column(base_loc)
|
202
202
|
@column_delta = configured_indentation_width - indentation
|
203
|
-
return if @column_delta
|
203
|
+
return if @column_delta.zero?
|
204
204
|
|
205
205
|
offense(body_node, indentation, style)
|
206
206
|
end
|
@@ -105,7 +105,7 @@ module RuboCop
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def message(node, selector)
|
108
|
-
message =
|
108
|
+
message = selector == '->' ? METHOD_MESSAGE : LITERAL_MESSAGE
|
109
109
|
|
110
110
|
format(message, message_line_modifier(node))
|
111
111
|
end
|
@@ -182,8 +182,7 @@ module RuboCop
|
|
182
182
|
return false unless parent && parent.send_type?
|
183
183
|
return false if parenthesized_call?(parent)
|
184
184
|
|
185
|
-
|
186
|
-
index >= 2
|
185
|
+
node.sibling_index > 1
|
187
186
|
end
|
188
187
|
|
189
188
|
def remove_unparenthesized_whitespaces(corrector, node)
|
@@ -38,10 +38,12 @@ module RuboCop
|
|
38
38
|
|
39
39
|
node.each_ancestor(*ASGN_NODES).any? do |asgn_node|
|
40
40
|
# `obj.method = value` parses as (send ... :method= ...), and will
|
41
|
-
# not be returned as an `asgn_node` here
|
42
|
-
#
|
43
|
-
# which IS an `asgn_node`
|
44
|
-
|
41
|
+
# not be returned as an `asgn_node` here, however,
|
42
|
+
# `obj.method ||= value` parses as (or-asgn (send ...) ...)
|
43
|
+
# which IS an `asgn_node`. Similarly, `obj.method += value` parses
|
44
|
+
# as (op-asgn (send ...) ...), which is also an `asgn_node`.
|
45
|
+
if asgn_node.or_asgn_type? || asgn_node.and_asgn_type? ||
|
46
|
+
asgn_node.op_asgn_type?
|
45
47
|
asgn_node, _value = *asgn_node
|
46
48
|
return false if asgn_node.send_type?
|
47
49
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module Style
|
7
|
+
# This cop checks for the presence of `method_missing` without also
|
8
|
+
# defining `respond_to_missing?` and falling back on `super`.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# #bad
|
12
|
+
# def method_missing(...)
|
13
|
+
# ...
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# #good
|
17
|
+
# def respond_to_missing?(...)
|
18
|
+
# ...
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# def method_missing(...)
|
22
|
+
# ...
|
23
|
+
# super
|
24
|
+
# end
|
25
|
+
class MethodMissing < Cop
|
26
|
+
include OnMethodDef
|
27
|
+
|
28
|
+
MSG = 'When using `method_missing`, %s.'.freeze
|
29
|
+
|
30
|
+
def on_method_def(node, method_name, _args, _body)
|
31
|
+
return unless method_name == :method_missing
|
32
|
+
|
33
|
+
check(node)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def check(node)
|
39
|
+
return if calls_super?(node) && implements_respond_to_missing?(node)
|
40
|
+
|
41
|
+
add_offense(node, :expression)
|
42
|
+
end
|
43
|
+
|
44
|
+
def message(node)
|
45
|
+
instructions = []
|
46
|
+
|
47
|
+
unless implements_respond_to_missing?(node)
|
48
|
+
instructions << 'define `respond_to_missing?`'.freeze
|
49
|
+
end
|
50
|
+
|
51
|
+
unless calls_super?(node)
|
52
|
+
instructions << 'fall back on `super`'.freeze
|
53
|
+
end
|
54
|
+
|
55
|
+
format(MSG, instructions.join(' and '))
|
56
|
+
end
|
57
|
+
|
58
|
+
def calls_super?(node)
|
59
|
+
node.descendants.any?(&:zsuper_type?)
|
60
|
+
end
|
61
|
+
|
62
|
+
def implements_respond_to_missing?(node)
|
63
|
+
node.parent.children.any? do |sibling|
|
64
|
+
respond_to_missing_def?(sibling)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def_node_matcher :respond_to_missing_def?, <<-PATTERN
|
69
|
+
(def :respond_to_missing? (...) ...)
|
70
|
+
PATTERN
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -77,24 +77,34 @@ module RuboCop
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def new_expression(outer_node, inner_node)
|
80
|
-
outer_cond, = *outer_node
|
81
|
-
inner_cond, = *inner_node
|
82
|
-
|
83
80
|
outer_keyword = outer_node.loc.keyword.source
|
84
|
-
|
81
|
+
operator = replacement_operator(outer_keyword)
|
82
|
+
lh_operand = left_hand_operand(outer_node, operator)
|
83
|
+
rh_operand = right_hand_operand(inner_node, outer_keyword)
|
85
84
|
|
86
|
-
|
85
|
+
"#{outer_keyword} #{lh_operand} #{operator} #{rh_operand}"
|
86
|
+
end
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
def replacement_operator(keyword)
|
89
|
+
keyword == 'if'.freeze ? '&&'.freeze : '||'.freeze
|
90
|
+
end
|
91
|
+
|
92
|
+
def left_hand_operand(node, operator)
|
93
|
+
cond, = *node
|
94
|
+
|
95
|
+
expr = cond.source
|
96
|
+
expr = "(#{expr})" if cond.or_type? && operator == '&&'.freeze
|
97
|
+
expr
|
98
|
+
end
|
92
99
|
|
93
|
-
|
94
|
-
|
100
|
+
def right_hand_operand(node, left_hand_keyword)
|
101
|
+
cond, = *node
|
102
|
+
keyword = node.loc.keyword.source
|
95
103
|
|
96
|
-
|
97
|
-
"#{
|
104
|
+
expr = cond.source
|
105
|
+
expr = "(#{expr})" if requires_parens?(cond)
|
106
|
+
expr = "!#{expr}" unless left_hand_keyword == keyword
|
107
|
+
expr
|
98
108
|
end
|
99
109
|
|
100
110
|
def requires_parens?(node)
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module Style
|
7
|
+
# This cop checks for using of comparison operators (`==`, `!=`,
|
8
|
+
# `>`, `<`), to test numbers as zero, nonzero, positive, or negative.
|
9
|
+
# These can be replaced by their respective predicate methods.
|
10
|
+
# The cop can also be configured to do the reverse.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # EnforcedStyle: predicate (default)
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
#
|
18
|
+
# foo == 0
|
19
|
+
# 0 != bar.baz
|
20
|
+
# 0 > foo
|
21
|
+
# bar.baz > 0
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
#
|
25
|
+
# foo.zero?
|
26
|
+
# bar.baz.nonzero?
|
27
|
+
# foo.negative?
|
28
|
+
# bar.baz.positive?
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
#
|
32
|
+
# # EnforcedStyle: comparison
|
33
|
+
#
|
34
|
+
# # bad
|
35
|
+
#
|
36
|
+
# foo.zero?
|
37
|
+
# bar.baz.nonzero?
|
38
|
+
# foo.negative?
|
39
|
+
# bar.baz.positive?
|
40
|
+
#
|
41
|
+
# # good
|
42
|
+
#
|
43
|
+
# foo == 0
|
44
|
+
# 0 != bar.baz
|
45
|
+
# 0 > foo
|
46
|
+
# bar.baz > 0
|
47
|
+
class NumericPredicate < Cop
|
48
|
+
include ConfigurableEnforcedStyle
|
49
|
+
|
50
|
+
MSG = 'Use `%s` instead of `%s`.'.freeze
|
51
|
+
|
52
|
+
REPLACEMENTS = {
|
53
|
+
'zero?' => '==',
|
54
|
+
'nonzero?' => '!=',
|
55
|
+
'positive?' => '>',
|
56
|
+
'negative?' => '<'
|
57
|
+
}.freeze
|
58
|
+
|
59
|
+
def on_send(node)
|
60
|
+
numeric, replacement = check(node)
|
61
|
+
|
62
|
+
if numeric
|
63
|
+
add_offense(node, node.loc.expression,
|
64
|
+
format(MSG, replacement, node.source))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def check(node)
|
71
|
+
numeric, operator =
|
72
|
+
if style == :predicate
|
73
|
+
comparison(node) || inverted_comparison(node, &invert)
|
74
|
+
else
|
75
|
+
predicate(node)
|
76
|
+
end
|
77
|
+
|
78
|
+
if numeric && operator && replacement_supported?(operator)
|
79
|
+
return numeric, replacement(numeric, operator)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def autocorrect(node)
|
84
|
+
_, replacement = check(node)
|
85
|
+
|
86
|
+
lambda do |corrector|
|
87
|
+
corrector.replace(node.loc.expression, replacement)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def replacement(numeric, operation)
|
92
|
+
if style == :predicate
|
93
|
+
[parenthesized_source(numeric),
|
94
|
+
REPLACEMENTS.invert[operation.to_s]].join('.')
|
95
|
+
else
|
96
|
+
[numeric.source, REPLACEMENTS[operation.to_s], 0].join(' ')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def parenthesized_source(node)
|
101
|
+
if require_parentheses?(node)
|
102
|
+
"(#{node.source})"
|
103
|
+
else
|
104
|
+
node.source
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def require_parentheses?(node)
|
109
|
+
node.binary_operation? && node.source !~ /^\(.*\)$/
|
110
|
+
end
|
111
|
+
|
112
|
+
def replacement_supported?(operator)
|
113
|
+
if [:>, :<].include?(operator)
|
114
|
+
target_ruby_version >= 2.3
|
115
|
+
else
|
116
|
+
true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def invert
|
121
|
+
lambda do |comparison, numeric|
|
122
|
+
comparison = { :> => :<, :< => :> }[comparison] || comparison
|
123
|
+
|
124
|
+
[numeric, comparison]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def_node_matcher :predicate, <<-PATTERN
|
129
|
+
(send $(...) ${:zero? :nonzero? :positive? :negative?})
|
130
|
+
PATTERN
|
131
|
+
|
132
|
+
def_node_matcher :comparison, <<-PATTERN
|
133
|
+
(send $(...) ${:== :!= :> :<} (int 0))
|
134
|
+
PATTERN
|
135
|
+
|
136
|
+
def_node_matcher :inverted_comparison, <<-PATTERN
|
137
|
+
(send (int 0) ${:== :!= :> :<} $(...))
|
138
|
+
PATTERN
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|