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
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
configured_indentation_width + offset
|
28
28
|
@column_delta = expected_column - actual_column
|
29
29
|
|
30
|
-
if @column_delta
|
30
|
+
if @column_delta.zero?
|
31
31
|
# which column was actually used as 'base column' for indentation?
|
32
32
|
# (not the column which we think should be the 'base column',
|
33
33
|
# but the one which has actually been used for that purpose)
|
@@ -28,12 +28,10 @@ module RuboCop
|
|
28
28
|
# the presence OR absence of an empty line
|
29
29
|
# But if style is `no_empty_lines`, there must not be an empty line
|
30
30
|
return unless body || style == :no_empty_lines
|
31
|
+
return if node.single_line?
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
return if start_line == end_line
|
35
|
-
|
36
|
-
check_source(start_line, end_line)
|
33
|
+
check_source(node.loc.expression.first_line,
|
34
|
+
node.loc.expression.last_line)
|
37
35
|
end
|
38
36
|
|
39
37
|
def check_source(start_line, end_line)
|
@@ -60,24 +60,24 @@ module RuboCop
|
|
60
60
|
def handle_new_line(node)
|
61
61
|
return unless closing_brace_on_same_line?(node)
|
62
62
|
|
63
|
-
add_offense(node, :
|
63
|
+
add_offense(node, :end, self.class::ALWAYS_NEW_LINE_MESSAGE)
|
64
64
|
end
|
65
65
|
|
66
66
|
def handle_same_line(node)
|
67
67
|
return if closing_brace_on_same_line?(node)
|
68
68
|
|
69
|
-
add_offense(node, :
|
69
|
+
add_offense(node, :end, self.class::ALWAYS_SAME_LINE_MESSAGE)
|
70
70
|
end
|
71
71
|
|
72
72
|
def handle_symmetrical(node)
|
73
73
|
if opening_brace_on_same_line?(node)
|
74
74
|
return if closing_brace_on_same_line?(node)
|
75
75
|
|
76
|
-
add_offense(node, :
|
76
|
+
add_offense(node, :end, self.class::SAME_LINE_MESSAGE)
|
77
77
|
else
|
78
78
|
return unless closing_brace_on_same_line?(node)
|
79
79
|
|
80
|
-
add_offense(node, :
|
80
|
+
add_offense(node, :end, self.class::NEW_LINE_MESSAGE)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -11,24 +11,39 @@ module RuboCop
|
|
11
11
|
|
12
12
|
def investigate(processed_source)
|
13
13
|
@processed_source = processed_source
|
14
|
+
each_extraneous_space(processed_source.tokens) do |kind, range|
|
15
|
+
add_offense(range, range, format(MSG, kind))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def autocorrect(range)
|
20
|
+
->(corrector) { corrector.remove(range) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def each_extraneous_space(tokens)
|
14
26
|
brackets = Brackets.new(*specifics)
|
15
|
-
|
16
|
-
next unless
|
27
|
+
tokens.each_cons(2) do |t1, t2|
|
28
|
+
next unless matching_brackets?(brackets, t1, t2)
|
17
29
|
|
18
30
|
# If the second token is a comment, that means that a line break
|
19
31
|
# follows, and that the rules for space inside don't apply.
|
20
32
|
next if t2.type == :tCOMMENT
|
21
33
|
next unless t2.pos.line == t1.pos.line && space_between?(t1, t2)
|
22
34
|
|
23
|
-
|
24
|
-
t1.pos.end_pos,
|
25
|
-
t2.pos.begin_pos)
|
26
|
-
add_offense(range, range, format(MSG, brackets.kind))
|
35
|
+
yield brackets.kind, range_between_tokens(t1, t2)
|
27
36
|
end
|
28
37
|
end
|
29
38
|
|
30
|
-
def
|
31
|
-
|
39
|
+
def matching_brackets?(brackets, t1, t2)
|
40
|
+
brackets.left_side?(t1) || brackets.right_side?(t2)
|
41
|
+
end
|
42
|
+
|
43
|
+
def range_between_tokens(t1, t2)
|
44
|
+
Parser::Source::Range.new(processed_source.buffer,
|
45
|
+
t1.pos.end_pos,
|
46
|
+
t2.pos.begin_pos)
|
32
47
|
end
|
33
48
|
|
34
49
|
# Wraps info about the brackets. Makes it easy to check whether a token
|
@@ -15,7 +15,7 @@ module RuboCop
|
|
15
15
|
|
16
16
|
body_length = body_length(body)
|
17
17
|
|
18
|
-
return false if body_length
|
18
|
+
return false if body_length.zero?
|
19
19
|
return false if cond.each_node.any?(&:lvasgn_type?)
|
20
20
|
return false if body_has_comment?(body)
|
21
21
|
return false if end_keyword_has_comment?(node)
|
data/lib/rubocop/cop/offense.rb
CHANGED
@@ -92,15 +92,9 @@ module RuboCop
|
|
92
92
|
# @return [Parser::Source::Range]
|
93
93
|
# the range of the code that is highlighted
|
94
94
|
def highlighted_area
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
location.source_line.length - location.column
|
99
|
-
end
|
100
|
-
|
101
|
-
Parser::Source::Range.new(location.source_line,
|
102
|
-
location.column,
|
103
|
-
location.column + column_length)
|
95
|
+
Parser::Source::Range.new(source_line,
|
96
|
+
column,
|
97
|
+
column + column_length)
|
104
98
|
end
|
105
99
|
|
106
100
|
# @api private
|
@@ -120,6 +114,35 @@ module RuboCop
|
|
120
114
|
location.column
|
121
115
|
end
|
122
116
|
|
117
|
+
# @api private
|
118
|
+
def source_line
|
119
|
+
location.source_line
|
120
|
+
end
|
121
|
+
|
122
|
+
# @api private
|
123
|
+
def column_length
|
124
|
+
if first_line == last_line
|
125
|
+
column_range.count
|
126
|
+
else
|
127
|
+
source_line.length - column
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# @api private
|
132
|
+
def first_line
|
133
|
+
location.first_line
|
134
|
+
end
|
135
|
+
|
136
|
+
# @api private
|
137
|
+
def last_line
|
138
|
+
location.last_line
|
139
|
+
end
|
140
|
+
|
141
|
+
# @api private
|
142
|
+
def column_range
|
143
|
+
location.column_range
|
144
|
+
end
|
145
|
+
|
123
146
|
# @api private
|
124
147
|
#
|
125
148
|
# Internally we use column number that start at 0, but when
|
@@ -157,7 +180,7 @@ module RuboCop
|
|
157
180
|
def <=>(other)
|
158
181
|
COMPARISON_ATTRIBUTES.each do |attribute|
|
159
182
|
result = send(attribute) <=> other.send(attribute)
|
160
|
-
return result unless result
|
183
|
+
return result unless result.zero?
|
161
184
|
end
|
162
185
|
0
|
163
186
|
end
|
@@ -81,29 +81,31 @@ module RuboCop
|
|
81
81
|
def autocorrect(node)
|
82
82
|
*conditions, _body = *node
|
83
83
|
|
84
|
-
new_condition =
|
85
|
-
conditions.each_with_object([]) do |condition, correction|
|
86
|
-
variable, = *condition
|
87
|
-
if variable.respond_to?(:array_type?) && variable.array_type?
|
88
|
-
correction << expand_percent_array(variable)
|
89
|
-
next
|
90
|
-
end
|
91
|
-
|
92
|
-
correction << condition.source
|
93
|
-
end
|
94
|
-
new_condition = new_condition.join(', ')
|
95
|
-
|
96
84
|
lambda do |corrector|
|
97
85
|
if needs_reorder?(conditions)
|
98
|
-
reorder_condition(corrector, node,
|
86
|
+
reorder_condition(corrector, node, replacement(conditions))
|
99
87
|
else
|
100
|
-
inline_fix_branch(corrector, node, conditions,
|
88
|
+
inline_fix_branch(corrector, node, conditions,
|
89
|
+
replacement(conditions))
|
101
90
|
end
|
102
91
|
end
|
103
92
|
end
|
104
93
|
|
105
94
|
private
|
106
95
|
|
96
|
+
def replacement(conditions)
|
97
|
+
new_condition = conditions.map do |condition|
|
98
|
+
variable, = *condition
|
99
|
+
if variable.respond_to?(:array_type?) && variable.array_type?
|
100
|
+
expand_percent_array(variable)
|
101
|
+
else
|
102
|
+
condition.source
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
new_condition.join(', ')
|
107
|
+
end
|
108
|
+
|
107
109
|
def inline_fix_branch(corrector, node, conditions, new_condition)
|
108
110
|
range =
|
109
111
|
Parser::Source::Range.new(node.loc.expression.source_buffer,
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
module Rails
|
7
|
+
# This cop identifies possible cases where Active Record save! or related
|
8
|
+
# should be used instead of save because the model might have failed to
|
9
|
+
# save and an exception is better than unhandled failure.
|
10
|
+
#
|
11
|
+
# This will ignore calls that are assigned to a variable or used as the
|
12
|
+
# condition in an if/unless statement. It will also ignore any call with
|
13
|
+
# more than 2 arguments as that is likely not an Active Record call or
|
14
|
+
# if a Model.update(id, attributes) call.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
#
|
18
|
+
# # bad
|
19
|
+
# user.save
|
20
|
+
# user.update(name: 'Joe')
|
21
|
+
# user.find_or_create_by(name: 'Joe')
|
22
|
+
# user.destroy
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# unless user.save
|
26
|
+
# . . .
|
27
|
+
# end
|
28
|
+
# user.save!
|
29
|
+
# user.update!(name: 'Joe')
|
30
|
+
# user.find_or_create_by!(name: 'Joe')
|
31
|
+
# user.destroy!
|
32
|
+
class SaveBang < Cop
|
33
|
+
MSG = 'Use `%s` instead of `%s` if the return value is not checked.'
|
34
|
+
.freeze
|
35
|
+
|
36
|
+
PERSIST_METHODS = [:save, :create, :update, :destroy,
|
37
|
+
:first_or_create, :find_or_create_by].freeze
|
38
|
+
|
39
|
+
def on_send(node)
|
40
|
+
return unless PERSIST_METHODS.include?(node.method_name)
|
41
|
+
return if return_value_used?(node)
|
42
|
+
return unless expected_signature?(node)
|
43
|
+
|
44
|
+
add_offense(node, node.loc.selector,
|
45
|
+
format(MSG,
|
46
|
+
"#{node.method_name}!",
|
47
|
+
node.method_name.to_s))
|
48
|
+
end
|
49
|
+
|
50
|
+
def autocorrect(node)
|
51
|
+
save_loc = node.loc.selector
|
52
|
+
new_method = "#{node.method_name}!"
|
53
|
+
|
54
|
+
->(corrector) { corrector.replace(save_loc, new_method) }
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Ignore simple assignment or if condition
|
60
|
+
def return_value_used?(node)
|
61
|
+
return false unless node.parent
|
62
|
+
node.parent.lvasgn_type? ||
|
63
|
+
(node.parent.if_type? && node.sibling_index.zero?)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Check argument signature as no arguments or one hash
|
67
|
+
def expected_signature?(node)
|
68
|
+
node.method_args.empty? ||
|
69
|
+
(node.method_args.length == 1 &&
|
70
|
+
node.method_name != :destroy &&
|
71
|
+
(node.method_args.first.hash_type? ||
|
72
|
+
!node.method_args.first.literal?))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -43,23 +43,23 @@ module RuboCop
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def autocorrect(node)
|
46
|
-
_receiver, method_name, *args = *node
|
47
|
-
options = args.find { |arg| arg.type != :sym }
|
48
46
|
lambda do |corrector|
|
49
|
-
validate_type = method_name.to_s.split('_')[1]
|
50
47
|
corrector.replace(node.loc.selector, 'validates')
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
48
|
+
correct_validate_type(corrector, node)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def correct_validate_type(corrector, node)
|
53
|
+
_receiver, method_name, *args = *node
|
54
|
+
options = args.find { |arg| arg.type != :sym }
|
55
|
+
validate_type = method_name.to_s.split('_')[1]
|
56
|
+
|
57
|
+
if options
|
58
|
+
corrector.replace(options.loc.expression,
|
59
|
+
"#{validate_type}: { #{options.source} }")
|
60
|
+
else
|
61
|
+
corrector.insert_after(node.loc.expression,
|
62
|
+
", #{validate_type}: true")
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
@@ -23,15 +23,13 @@ module RuboCop
|
|
23
23
|
|
24
24
|
lambda do |corrector|
|
25
25
|
corrector.remove(eq_begin)
|
26
|
-
|
27
|
-
unless contents.length == 0
|
26
|
+
unless contents.length.zero?
|
28
27
|
corrector.replace(contents,
|
29
28
|
contents.source
|
30
29
|
.gsub(/\A/, '# ')
|
31
30
|
.gsub(/\n\n/, "\n#\n")
|
32
31
|
.gsub(/\n(?=[^\z#])/, "\n# "))
|
33
32
|
end
|
34
|
-
# rubocop:enable Style/ZeroLengthPredicate
|
35
33
|
corrector.remove(eq_end)
|
36
34
|
end
|
37
35
|
end
|
@@ -59,26 +59,21 @@ module RuboCop
|
|
59
59
|
node = args.last
|
60
60
|
lambda do |corrector|
|
61
61
|
if braces?(node)
|
62
|
-
|
62
|
+
remove_braces_with_whitespace(corrector, node)
|
63
63
|
else
|
64
64
|
add_braces(corrector, node)
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
70
|
-
|
71
|
-
right_brace_and_space = range_with_surrounding_space(node.loc.end,
|
72
|
-
:left)
|
73
|
-
right_brace_and_space =
|
74
|
-
range_with_surrounding_comma(right_brace_and_space, :left)
|
69
|
+
def remove_braces_with_whitespace(corrector, node)
|
70
|
+
right_brace_and_space = right_brace_and_space(node.loc.end)
|
75
71
|
|
76
|
-
if
|
72
|
+
if comment_on_line?(right_brace_and_space.line)
|
77
73
|
# Removing a line break between a comment and the closing
|
78
74
|
# parenthesis would cause a syntax error, so we only remove the
|
79
75
|
# braces in that case.
|
80
|
-
corrector
|
81
|
-
corrector.remove(node.loc.end)
|
76
|
+
remove_braces(corrector, node)
|
82
77
|
else
|
83
78
|
left_brace_and_space = range_with_surrounding_space(node.loc.begin,
|
84
79
|
:right)
|
@@ -87,6 +82,20 @@ module RuboCop
|
|
87
82
|
end
|
88
83
|
end
|
89
84
|
|
85
|
+
def right_brace_and_space(loc_end)
|
86
|
+
brace_and_space = range_with_surrounding_space(loc_end, :left)
|
87
|
+
range_with_surrounding_comma(brace_and_space, :left)
|
88
|
+
end
|
89
|
+
|
90
|
+
def comment_on_line?(line)
|
91
|
+
processed_source.comments.any? { |c| c.loc.line == line }
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_braces(corrector, node)
|
95
|
+
corrector.remove(node.loc.begin)
|
96
|
+
corrector.remove(node.loc.end)
|
97
|
+
end
|
98
|
+
|
90
99
|
def add_braces(corrector, node)
|
91
100
|
corrector.insert_before(node.source_range, '{')
|
92
101
|
corrector.insert_after(node.source_range, '}')
|