rubocop 0.26.1 → 0.27.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/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +10 -6
- data/.travis.yml +2 -0
- data/CHANGELOG.md +30 -0
- data/README.md +9 -2
- data/assets/logo.png +0 -0
- data/assets/output.html.erb +68 -65
- data/config/default.yml +42 -7
- data/config/disabled.yml +5 -0
- data/config/enabled.yml +32 -7
- data/lib/rubocop.rb +10 -2
- data/lib/rubocop/comment_config.rb +11 -17
- data/lib/rubocop/config.rb +20 -16
- data/lib/rubocop/config_loader.rb +8 -12
- data/lib/rubocop/cop/cop.rb +13 -12
- data/lib/rubocop/cop/lint/block_alignment.rb +4 -6
- data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -2
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -3
- data/lib/rubocop/cop/lint/useless_setter_call.rb +2 -2
- data/lib/rubocop/cop/metrics/abc_size.rb +27 -0
- data/lib/rubocop/cop/metrics/block_nesting.rb +2 -4
- data/lib/rubocop/cop/metrics/class_length.rb +1 -1
- data/lib/rubocop/cop/metrics/line_length.rb +2 -5
- data/lib/rubocop/cop/metrics/method_length.rb +2 -2
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +24 -15
- data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +15 -2
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +63 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/if_node.rb +3 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +3 -3
- data/lib/rubocop/cop/mixin/{on_method.rb → on_method_def.rb} +3 -3
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +2 -2
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
- data/lib/rubocop/cop/mixin/string_literals_help.rb +28 -0
- data/lib/rubocop/cop/rails/delegate.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_indentation.rb +2 -2
- data/lib/rubocop/cop/style/accessor_method_name.rb +2 -2
- data/lib/rubocop/cop/style/align_hash.rb +16 -12
- data/lib/rubocop/cop/style/align_parameters.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +14 -6
- data/lib/rubocop/cop/style/array_join.rb +1 -1
- data/lib/rubocop/cop/style/block_comments.rb +16 -8
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +6 -30
- data/lib/rubocop/cop/style/case_indentation.rb +20 -12
- data/lib/rubocop/cop/style/collection_methods.rb +4 -4
- data/lib/rubocop/cop/style/colon_method_call.rb +9 -0
- data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
- data/lib/rubocop/cop/style/comment_indentation.rb +22 -22
- data/lib/rubocop/cop/style/def_with_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/deprecated_hash_methods.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +6 -1
- data/lib/rubocop/cop/style/else_alignment.rb +93 -0
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/style/empty_lines.rb +1 -1
- data/lib/rubocop/cop/style/empty_lines_around_class_body.rb +34 -0
- data/lib/rubocop/cop/style/empty_lines_around_method_body.rb +37 -0
- data/lib/rubocop/cop/style/empty_lines_around_module_body.rb +30 -0
- data/lib/rubocop/cop/style/encoding.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +4 -4
- data/lib/rubocop/cop/style/indent_array.rb +2 -2
- data/lib/rubocop/cop/style/indent_hash.rb +17 -12
- data/lib/rubocop/cop/style/indentation_width.rb +27 -19
- data/lib/rubocop/cop/style/method_call_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -11
- data/lib/rubocop/cop/style/method_name.rb +1 -1
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +174 -0
- data/lib/rubocop/cop/style/non_nil_check.rb +12 -15
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +12 -17
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/predicate_name.rb +2 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -2
- data/lib/rubocop/cop/style/redundant_return.rb +3 -3
- data/lib/rubocop/cop/style/redundant_self.rb +3 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +17 -13
- data/lib/rubocop/cop/style/rescue_modifier.rb +2 -2
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/space_after_method_name.rb +2 -2
- data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +17 -11
- data/lib/rubocop/cop/style/space_before_block_braces.rb +1 -1
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +17 -14
- data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +10 -6
- data/lib/rubocop/cop/style/string_literals.rb +13 -16
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +41 -0
- data/lib/rubocop/cop/style/trailing_comma.rb +1 -3
- data/lib/rubocop/cop/style/trivial_accessors.rb +3 -3
- data/lib/rubocop/cop/style/unneeded_capital_w.rb +1 -1
- data/lib/rubocop/cop/style/unneeded_percent_q.rb +2 -2
- data/lib/rubocop/cop/style/word_array.rb +23 -19
- data/lib/rubocop/cop/team.rb +13 -26
- data/lib/rubocop/cop/util.rb +5 -0
- data/lib/rubocop/cop/variable_force/locatable.rb +7 -13
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +9 -1
- data/lib/rubocop/formatter/html_formatter.rb +83 -55
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -2
- data/lib/rubocop/formatter/text_util.rb +25 -0
- data/lib/rubocop/options.rb +14 -7
- data/lib/rubocop/path_util.rb +11 -7
- data/lib/rubocop/runner.rb +7 -2
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.27.0.md +77 -0
- data/rubocop.gemspec +1 -1
- data/spec/fixtures/html_formatter/expected.html +495 -0
- data/spec/fixtures/html_formatter/project/app/controllers/application_controller.rb +5 -0
- data/spec/fixtures/html_formatter/project/app/controllers/books_controller.rb +74 -0
- data/spec/fixtures/html_formatter/project/app/models/book.rb +5 -0
- data/spec/rubocop/cli_spec.rb +56 -13
- data/spec/rubocop/cop/lint/invalid_character_literal_spec.rb +1 -1
- data/spec/rubocop/cop/metrics/abc_size_spec.rb +99 -0
- data/spec/rubocop/cop/rails/action_filter_spec.rb +1 -0
- data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +23 -1
- data/spec/rubocop/cop/style/align_hash_spec.rb +13 -0
- data/spec/rubocop/cop/style/align_parameters_spec.rb +44 -33
- data/spec/rubocop/cop/style/blocks_spec.rb +8 -0
- data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +9 -9
- data/spec/rubocop/cop/style/case_indentation_spec.rb +3 -2
- data/spec/rubocop/cop/style/colon_method_call_spec.rb +5 -0
- data/spec/rubocop/cop/style/comment_indentation_spec.rb +6 -1
- data/spec/rubocop/cop/style/else_alignment_spec.rb +437 -0
- data/spec/rubocop/cop/style/empty_lines_around_class_body_spec.rb +75 -0
- data/spec/rubocop/cop/style/{empty_lines_around_body_spec.rb → empty_lines_around_method_body_spec.rb} +9 -50
- data/spec/rubocop/cop/style/empty_lines_around_module_body_spec.rb +79 -0
- data/spec/rubocop/cop/style/file_name_spec.rb +1 -1
- data/spec/rubocop/cop/style/format_string_spec.rb +12 -0
- data/spec/rubocop/cop/style/indent_array_spec.rb +6 -1
- data/spec/rubocop/cop/style/indent_hash_spec.rb +2 -1
- data/spec/rubocop/cop/style/indentation_width_spec.rb +765 -722
- data/spec/rubocop/cop/style/multiline_operation_indentation_spec.rb +414 -0
- data/spec/rubocop/cop/style/non_nil_check_spec.rb +86 -55
- data/spec/rubocop/cop/style/single_line_methods_spec.rb +5 -1
- data/spec/rubocop/cop/style/space_before_block_braces_spec.rb +2 -1
- data/spec/rubocop/cop/style/space_inside_block_braces_spec.rb +2 -1
- data/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb +63 -0
- data/spec/rubocop/cop/style/string_literals_spec.rb +2 -2
- data/spec/rubocop/cop/style/word_array_spec.rb +15 -1
- data/spec/rubocop/formatter/base_formatter_spec.rb +1 -1
- data/spec/rubocop/formatter/disabled_lines_formatter_spec.rb +0 -1
- data/spec/rubocop/formatter/formatter_set_spec.rb +9 -0
- data/spec/rubocop/formatter/html_formatter_spec.rb +25 -122
- data/spec/rubocop/formatter/offense_count_formatter_spec.rb +0 -1
- data/spec/rubocop/runner_spec.rb +1 -1
- data/spec/spec_helper.rb +12 -130
- data/spec/support/cop_helper.rb +72 -0
- data/spec/support/coverage.rb +15 -0
- data/spec/support/{offenses_matcher.rb → custom_matchers.rb} +28 -0
- data/spec/support/jruby_workaround.rb +15 -0
- data/spec/support/{isolated_environment.rb → shared_contexts.rb} +19 -0
- metadata +49 -14
- data/lib/rubocop/cop/style/empty_lines_around_body.rb +0 -75
- data/spec/support/shared_context.rb +0 -20
@@ -11,7 +11,7 @@ module RuboCop
|
|
11
11
|
def on_def(node)
|
12
12
|
if @prev_def_end && (def_start(node) - @prev_def_end) == 1
|
13
13
|
unless @prev_was_single_line && singe_line_def?(node) &&
|
14
|
-
|
14
|
+
cop_config['AllowAdjacentOneLineDefs']
|
15
15
|
add_offense(node, :keyword)
|
16
16
|
end
|
17
17
|
end
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
((prev_line + 1)...cur_line).each do |line|
|
25
25
|
# we check if the prev and current lines are empty
|
26
26
|
next unless processed_source[line - 2].empty? &&
|
27
|
-
|
27
|
+
processed_source[line - 1].empty?
|
28
28
|
|
29
29
|
range = source_range(processed_source.buffer, line, 0)
|
30
30
|
add_offense(range, range)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cops checks if empty lines around the bodies of classes match the
|
7
|
+
# configuration.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# class Test
|
12
|
+
#
|
13
|
+
# def something
|
14
|
+
# ...
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
class EmptyLinesAroundClassBody < Cop
|
20
|
+
include EmptyLinesAroundBody
|
21
|
+
|
22
|
+
KIND = 'class'
|
23
|
+
|
24
|
+
def on_class(node)
|
25
|
+
check(node)
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_sclass(node)
|
29
|
+
check(node)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cops checks if empty lines around the bodies of methods match
|
7
|
+
# the configuration.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# def something(arg)
|
12
|
+
#
|
13
|
+
# ...
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
class EmptyLinesAroundMethodBody < Cop
|
17
|
+
include EmptyLinesAroundBody
|
18
|
+
include OnMethodDef
|
19
|
+
|
20
|
+
KIND = 'method'
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def on_method_def(node, _method_name, _args, _body)
|
25
|
+
check(node)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Override ConfigurableEnforcedStyle#style and hard-code
|
29
|
+
# configuration. It's difficult to imagine that anybody would want
|
30
|
+
# empty lines around a method body, so we don't make it configurable.
|
31
|
+
def style
|
32
|
+
:no_empty_lines
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cops checks if empty lines around the bodies of modules match
|
7
|
+
# the configuration.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# module Test
|
12
|
+
#
|
13
|
+
# def something
|
14
|
+
# ...
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
class EmptyLinesAroundModuleBody < Cop
|
20
|
+
include EmptyLinesAroundBody
|
21
|
+
|
22
|
+
KIND = 'module'
|
23
|
+
|
24
|
+
def on_module(node)
|
25
|
+
check(node)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -33,11 +33,11 @@ module RuboCop
|
|
33
33
|
def format_method?(name, node)
|
34
34
|
receiver, method_name, args = *node
|
35
35
|
|
36
|
-
# we do an argument count check to reduce false positives
|
37
|
-
return false if args && args.children.size < 2
|
38
|
-
|
39
36
|
# commands have no explicit receiver
|
40
|
-
!receiver && method_name == name
|
37
|
+
return false unless !receiver && method_name == name
|
38
|
+
|
39
|
+
# we do an argument count check to reduce false positives
|
40
|
+
args && args.children.size >= 2
|
41
41
|
end
|
42
42
|
|
43
43
|
def format?(node)
|
@@ -28,13 +28,13 @@ module RuboCop
|
|
28
28
|
return if expr.line == left_bracket.line
|
29
29
|
|
30
30
|
base_column = left_bracket.source_line =~ /\S/
|
31
|
-
expected_column = base_column +
|
31
|
+
expected_column = base_column + configured_indentation_width
|
32
32
|
@column_delta = expected_column - expr.column
|
33
33
|
return if @column_delta == 0
|
34
34
|
|
35
35
|
msg = format('Use %d spaces for indentation in an array, relative ' \
|
36
36
|
'to the start of the line where the left bracket is.',
|
37
|
-
|
37
|
+
configured_indentation_width)
|
38
38
|
add_offense(first_pair, :expression, msg)
|
39
39
|
end
|
40
40
|
|
@@ -95,20 +95,26 @@ module RuboCop
|
|
95
95
|
def check_first_pair(first_pair, left_brace, left_parenthesis, offset)
|
96
96
|
column = first_pair.loc.expression.column
|
97
97
|
expected_column = base_column(left_brace, left_parenthesis) +
|
98
|
-
|
98
|
+
configured_indentation_width + offset
|
99
99
|
@column_delta = expected_column - column
|
100
100
|
|
101
101
|
if @column_delta == 0
|
102
102
|
correct_style_detected
|
103
103
|
else
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
104
|
+
incorrect_style_detected(column, offset, first_pair,
|
105
|
+
left_parenthesis, left_brace)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def incorrect_style_detected(column, offset, first_pair,
|
110
|
+
left_parenthesis, left_brace)
|
111
|
+
add_offense(first_pair, :expression,
|
112
|
+
message(base_description(left_parenthesis))) do
|
113
|
+
if column == unexpected_column(left_brace, left_parenthesis,
|
114
|
+
offset)
|
115
|
+
opposite_style_detected
|
116
|
+
else
|
117
|
+
unrecognized_style_detected
|
112
118
|
end
|
113
119
|
end
|
114
120
|
end
|
@@ -146,13 +152,12 @@ module RuboCop
|
|
146
152
|
end
|
147
153
|
end
|
148
154
|
|
149
|
-
unexpected_base_column +
|
150
|
-
offset
|
155
|
+
unexpected_base_column + configured_indentation_width + offset
|
151
156
|
end
|
152
157
|
|
153
158
|
def message(base_description)
|
154
159
|
format('Use %d spaces for indentation in a hash, relative to %s.',
|
155
|
-
|
160
|
+
configured_indentation_width, base_description)
|
156
161
|
end
|
157
162
|
end
|
158
163
|
end
|
@@ -14,13 +14,11 @@ module RuboCop
|
|
14
14
|
# end
|
15
15
|
class IndentationWidth < Cop # rubocop:disable Metrics/ClassLength
|
16
16
|
include AutocorrectAlignment
|
17
|
-
include
|
17
|
+
include OnMethodDef
|
18
18
|
include CheckAssignment
|
19
19
|
include IfNode
|
20
20
|
include AccessModifierNode
|
21
21
|
|
22
|
-
CORRECT_INDENTATION = 2
|
23
|
-
|
24
22
|
def on_rescue(node)
|
25
23
|
_begin_node, *rescue_nodes, else_node = *node
|
26
24
|
rescue_nodes.each do |rescue_node|
|
@@ -72,7 +70,7 @@ module RuboCop
|
|
72
70
|
ignore_node(args.first)
|
73
71
|
end
|
74
72
|
|
75
|
-
def
|
73
|
+
def on_method_def(node, _method_name, _args, body)
|
76
74
|
check_indentation(node.loc.keyword, body) unless ignored_node?(node)
|
77
75
|
end
|
78
76
|
|
@@ -84,7 +82,7 @@ module RuboCop
|
|
84
82
|
def on_while(node, base = node)
|
85
83
|
_condition, body = *node
|
86
84
|
return unless node.loc.keyword.begin_pos ==
|
87
|
-
|
85
|
+
node.loc.expression.begin_pos
|
88
86
|
|
89
87
|
check_indentation(base.loc, body)
|
90
88
|
end
|
@@ -175,20 +173,10 @@ module RuboCop
|
|
175
173
|
end
|
176
174
|
|
177
175
|
def check_indentation(base_loc, body_node)
|
178
|
-
return unless body_node
|
179
|
-
|
180
|
-
# Don't check if expression is on same line as "then" keyword, etc.
|
181
|
-
return if body_node.loc.line == base_loc.line
|
182
|
-
|
183
|
-
return if starts_with_access_modifier?(body_node)
|
184
|
-
|
185
|
-
# Don't check indentation if the line doesn't start with the body.
|
186
|
-
# For example, lines like "else do_something".
|
187
|
-
first_char_pos_on_line = body_node.loc.expression.source_line =~ /\S/
|
188
|
-
return unless body_node.loc.column == first_char_pos_on_line
|
176
|
+
return unless indentation_to_check?(base_loc, body_node)
|
189
177
|
|
190
178
|
indentation = body_node.loc.column - base_loc.column
|
191
|
-
@column_delta =
|
179
|
+
@column_delta = configured_indentation_width - indentation
|
192
180
|
return if @column_delta == 0
|
193
181
|
|
194
182
|
# This cop only auto-corrects the first statement in a def body, for
|
@@ -204,13 +192,33 @@ module RuboCop
|
|
204
192
|
|
205
193
|
r = Parser::Source::Range.new(expr.source_buffer, pos.begin, pos.end)
|
206
194
|
add_offense(body_node, r,
|
207
|
-
format("Use #{
|
208
|
-
'for indentation.', indentation))
|
195
|
+
format("Use #{configured_indentation_width} (not %d) " \
|
196
|
+
'spaces for indentation.', indentation))
|
197
|
+
end
|
198
|
+
|
199
|
+
def indentation_to_check?(base_loc, body_node)
|
200
|
+
return false unless body_node
|
201
|
+
|
202
|
+
# Don't check if expression is on same line as "then" keyword, etc.
|
203
|
+
return false if body_node.loc.line == base_loc.line
|
204
|
+
|
205
|
+
return false if starts_with_access_modifier?(body_node)
|
206
|
+
|
207
|
+
# Don't check indentation if the line doesn't start with the body.
|
208
|
+
# For example, lines like "else do_something".
|
209
|
+
first_char_pos_on_line = body_node.loc.expression.source_line =~ /\S/
|
210
|
+
return false unless body_node.loc.column == first_char_pos_on_line
|
211
|
+
|
212
|
+
true
|
209
213
|
end
|
210
214
|
|
211
215
|
def starts_with_access_modifier?(body_node)
|
212
216
|
body_node.type == :begin && modifier_node?(body_node.children.first)
|
213
217
|
end
|
218
|
+
|
219
|
+
def configured_indentation_width
|
220
|
+
cop_config['Width']
|
221
|
+
end
|
214
222
|
end
|
215
223
|
end
|
216
224
|
end
|
@@ -19,9 +19,9 @@ module RuboCop
|
|
19
19
|
def autocorrect(node)
|
20
20
|
# Bail out if the call is going to be auto-corrected by EmptyLiteral.
|
21
21
|
if config.for_cop('Style/EmptyLiteral')['Enabled'] &&
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
[EmptyLiteral::HASH_NODE,
|
23
|
+
EmptyLiteral::ARRAY_NODE,
|
24
|
+
EmptyLiteral::STR_NODE].include?(node)
|
25
25
|
return
|
26
26
|
end
|
27
27
|
@corrections << lambda do |corrector|
|
@@ -29,7 +29,7 @@ module RuboCop
|
|
29
29
|
return if ignored_node?(node)
|
30
30
|
receiver, _method_name, *_args = *node
|
31
31
|
return unless receiver && receiver.type == :block &&
|
32
|
-
|
32
|
+
receiver.loc.end.is?('end')
|
33
33
|
|
34
34
|
range = Parser::Source::Range.new(receiver.loc.end.source_buffer,
|
35
35
|
receiver.loc.end.begin_pos,
|
@@ -6,25 +6,18 @@ module RuboCop
|
|
6
6
|
# This cops checks for parentheses around the arguments in method
|
7
7
|
# definitions. Both instance and class/singleton methods are checked.
|
8
8
|
class MethodDefParentheses < Cop
|
9
|
-
include
|
9
|
+
include OnMethodDef
|
10
10
|
include ConfigurableEnforcedStyle
|
11
11
|
|
12
|
-
def
|
12
|
+
def on_method_def(node, _method_name, args, _body)
|
13
13
|
if style == :require_parentheses
|
14
14
|
if arguments?(args) && !parentheses?(args)
|
15
|
-
|
16
|
-
args.loc.expression,
|
17
|
-
'Use def with parentheses when there are ' \
|
18
|
-
'parameters.') do
|
19
|
-
opposite_style_detected
|
20
|
-
end
|
15
|
+
missing_parentheses(node, args)
|
21
16
|
else
|
22
17
|
correct_style_detected
|
23
18
|
end
|
24
19
|
elsif parentheses?(args)
|
25
|
-
|
26
|
-
opposite_style_detected
|
27
|
-
end
|
20
|
+
unwanted_parentheses(args)
|
28
21
|
else
|
29
22
|
correct_style_detected
|
30
23
|
end
|
@@ -49,6 +42,19 @@ module RuboCop
|
|
49
42
|
|
50
43
|
private
|
51
44
|
|
45
|
+
def missing_parentheses(node, args)
|
46
|
+
add_offense(node, args.loc.expression,
|
47
|
+
'Use def with parentheses when there are parameters.') do
|
48
|
+
opposite_style_detected
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def unwanted_parentheses(args)
|
53
|
+
add_offense(args, :expression, 'Use def without parentheses.') do
|
54
|
+
opposite_style_detected
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
52
58
|
def args_node(def_node)
|
53
59
|
if def_node.type == :def
|
54
60
|
_method_name, args, _body = *def_node
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cops checks the indentation of the right hand side operand in
|
7
|
+
# binary operations that span more than one line.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# if a +
|
12
|
+
# b
|
13
|
+
# something
|
14
|
+
# end
|
15
|
+
class MultilineOperationIndentation < Cop
|
16
|
+
include ConfigurableEnforcedStyle
|
17
|
+
include AutocorrectAlignment
|
18
|
+
|
19
|
+
def on_and(node)
|
20
|
+
check_and_or(node)
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_or(node)
|
24
|
+
check_and_or(node)
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
receiver, _method_name, *_args = *node
|
29
|
+
return unless receiver
|
30
|
+
|
31
|
+
lhs, rhs = left_hand_side(receiver), right_hand_side(node)
|
32
|
+
range = offending_range(node, lhs, rhs, style)
|
33
|
+
check(range, node, lhs, rhs)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def check_and_or(node)
|
39
|
+
lhs, rhs = *node
|
40
|
+
range = offending_range(node, lhs, rhs.loc.expression, style)
|
41
|
+
check(range, node, lhs, rhs.loc.expression)
|
42
|
+
end
|
43
|
+
|
44
|
+
def check(range, node, lhs, rhs)
|
45
|
+
if range
|
46
|
+
incorrect_style_detected(range, node, lhs, rhs)
|
47
|
+
else
|
48
|
+
correct_style_detected
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def incorrect_style_detected(range, node, lhs, rhs)
|
53
|
+
add_offense(range, range, message(node, lhs, rhs)) do
|
54
|
+
unless offending_range(node, lhs, rhs, alternative_style)
|
55
|
+
opposite_style_detected
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def offending_range(node, lhs, rhs, given_style)
|
61
|
+
return false unless begins_its_line?(rhs)
|
62
|
+
return false if lhs.loc.line == rhs.line # Needed for unary op.
|
63
|
+
return false if not_for_this_cop?(node)
|
64
|
+
|
65
|
+
correct_column = if should_align?(node, given_style)
|
66
|
+
lhs.loc.column
|
67
|
+
else
|
68
|
+
indentation(lhs) + correct_indentation(node)
|
69
|
+
end
|
70
|
+
@column_delta = correct_column - rhs.column
|
71
|
+
rhs if @column_delta != 0
|
72
|
+
end
|
73
|
+
|
74
|
+
def message(node, lhs, rhs)
|
75
|
+
what = operation_description(node)
|
76
|
+
if should_align?(node, style)
|
77
|
+
"Align the operands of #{what} spanning multiple lines."
|
78
|
+
else
|
79
|
+
used_indentation = rhs.column - indentation(lhs)
|
80
|
+
"Use #{correct_indentation(node)} (not #{used_indentation}) " \
|
81
|
+
"spaces for indenting #{what} spanning multiple lines."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def indentation(node)
|
86
|
+
node.loc.expression.source_line =~ /\S/
|
87
|
+
end
|
88
|
+
|
89
|
+
def operation_description(node)
|
90
|
+
ancestor = kw_node_with_special_indentation(node)
|
91
|
+
if ancestor
|
92
|
+
kw = ancestor.loc.keyword.source
|
93
|
+
kind = kw == 'for' ? 'collection' : 'condition'
|
94
|
+
article = kw =~ /^[iu]/ ? 'an' : 'a'
|
95
|
+
"a #{kind} in #{article} `#{kw}` statement"
|
96
|
+
else
|
97
|
+
'an expression' + (assignment?(node) ? ' in an assignment' : '')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# In a chain of method calls, we regard the top send node as the base
|
102
|
+
# for indentation of all lines following the first. For example:
|
103
|
+
# a.
|
104
|
+
# b c { block }. <-- b is indented relative to a
|
105
|
+
# d <-- d is indented relative to a
|
106
|
+
def left_hand_side(receiver)
|
107
|
+
lhs = receiver
|
108
|
+
lhs = lhs.parent while lhs.parent && lhs.parent.type == :send
|
109
|
+
lhs
|
110
|
+
end
|
111
|
+
|
112
|
+
def right_hand_side(send_node)
|
113
|
+
_, method_name, *args = *send_node
|
114
|
+
if operator?(method_name) && args.any?
|
115
|
+
args.first.loc.expression
|
116
|
+
elsif send_node.loc.dot &&
|
117
|
+
send_node.loc.dot.line == send_node.loc.selector.line
|
118
|
+
send_node.loc.dot.join(send_node.loc.selector)
|
119
|
+
else
|
120
|
+
send_node.loc.selector
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def correct_indentation(node)
|
125
|
+
multiplier = kw_node_with_special_indentation(node) ? 2 : 1
|
126
|
+
configured_indentation_width * multiplier
|
127
|
+
end
|
128
|
+
|
129
|
+
def should_align?(node, given_style)
|
130
|
+
given_style == :aligned && (kw_node_with_special_indentation(node) ||
|
131
|
+
assignment?(node))
|
132
|
+
end
|
133
|
+
|
134
|
+
def kw_node_with_special_indentation(node)
|
135
|
+
node.each_ancestor.find do |a|
|
136
|
+
next unless a.loc.respond_to?(:keyword)
|
137
|
+
|
138
|
+
case a.type
|
139
|
+
when :if, :while, :until then condition, = *a
|
140
|
+
when :for then _, collection, _ = *a
|
141
|
+
end
|
142
|
+
|
143
|
+
if condition || collection
|
144
|
+
within_node?(node, condition || collection)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def assignment?(node)
|
150
|
+
node.each_ancestor.find { |a| ASGN_NODES.include?(a.type) }
|
151
|
+
end
|
152
|
+
|
153
|
+
def not_for_this_cop?(node)
|
154
|
+
node.each_ancestor.find do |ancestor|
|
155
|
+
grouped_expression?(ancestor) ||
|
156
|
+
inside_arg_list_parentheses?(node, ancestor)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def grouped_expression?(node)
|
161
|
+
node.type == :begin && node.loc.respond_to?(:begin) && node.loc.begin
|
162
|
+
end
|
163
|
+
|
164
|
+
def inside_arg_list_parentheses?(node, ancestor)
|
165
|
+
a = ancestor.loc
|
166
|
+
return false unless ancestor.type == :send && a.begin &&
|
167
|
+
a.begin.is?('(')
|
168
|
+
n = node.loc.expression
|
169
|
+
n.begin_pos > a.begin.begin_pos && n.end_pos < a.end.end_pos
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|