rubocop 0.31.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +315 -0
- data/README.md +199 -38
- data/config/default.yml +91 -12
- data/config/disabled.yml +45 -4
- data/config/enabled.yml +107 -9
- data/lib/rubocop/ast_node.rb +48 -0
- data/lib/rubocop/cli.rb +11 -1
- data/lib/rubocop/comment_config.rb +4 -1
- data/lib/rubocop/config.rb +26 -17
- data/lib/rubocop/config_loader.rb +61 -14
- data/lib/rubocop/cop/commissioner.rb +7 -12
- data/lib/rubocop/cop/cop.rb +43 -20
- data/lib/rubocop/cop/lint/block_alignment.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +69 -0
- data/lib/rubocop/cop/lint/debugger.rb +9 -48
- data/lib/rubocop/cop/lint/def_end_alignment.rb +8 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +42 -23
- data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -2
- data/lib/rubocop/cop/lint/duplicated_key.rb +37 -0
- data/lib/rubocop/cop/lint/end_alignment.rb +33 -13
- data/lib/rubocop/cop/lint/eval.rb +6 -2
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +175 -0
- data/lib/rubocop/cop/lint/literal_in_condition.rb +0 -5
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +10 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +31 -0
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +19 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/space_before_first_arg.rb +1 -1
- data/lib/rubocop/cop/lint/unneeded_disable.rb +72 -0
- data/lib/rubocop/cop/lint/unused_block_argument.rb +6 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +8 -0
- data/lib/rubocop/cop/metrics/abc_size.rb +17 -6
- data/lib/rubocop/cop/metrics/class_length.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -3
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/metrics/parameter_lists.rb +1 -1
- data/lib/rubocop/cop/mixin/access_modifier_node.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -2
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +28 -4
- data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +26 -3
- data/lib/rubocop/cop/mixin/check_assignment.rb +2 -3
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +59 -12
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_naming.rb +14 -3
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -3
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +10 -1
- data/lib/rubocop/cop/mixin/first_element_line_break.rb +41 -0
- data/lib/rubocop/cop/mixin/if_node.rb +10 -0
- data/lib/rubocop/cop/mixin/method_preference.rb +28 -0
- data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -1
- data/lib/rubocop/cop/mixin/on_method_def.rb +4 -5
- data/lib/rubocop/cop/mixin/safe_assignment.rb +3 -14
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +8 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +8 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +4 -7
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +5 -4
- data/lib/rubocop/cop/offense.rb +16 -3
- data/lib/rubocop/cop/performance/case_when_splat.rb +160 -0
- data/lib/rubocop/cop/performance/count.rb +35 -30
- data/lib/rubocop/cop/performance/detect.rb +16 -3
- data/lib/rubocop/cop/performance/fixed_size.rb +50 -0
- data/lib/rubocop/cop/performance/flat_map.rb +3 -3
- data/lib/rubocop/cop/performance/sample.rb +103 -59
- data/lib/rubocop/cop/performance/size.rb +2 -1
- data/lib/rubocop/cop/performance/string_replacement.rb +187 -0
- data/lib/rubocop/cop/rails/action_filter.rb +31 -5
- data/lib/rubocop/cop/rails/date.rb +15 -14
- data/lib/rubocop/cop/rails/pluralization_grammar.rb +97 -0
- data/lib/rubocop/cop/rails/read_write_attribute.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +46 -18
- data/lib/rubocop/cop/style/alias.rb +1 -0
- data/lib/rubocop/cop/style/align_hash.rb +8 -15
- data/lib/rubocop/cop/style/align_parameters.rb +19 -7
- data/lib/rubocop/cop/style/and_or.rb +42 -13
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +2 -1
- data/lib/rubocop/cop/style/block_comments.rb +4 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +69 -24
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +40 -12
- data/lib/rubocop/cop/style/case_indentation.rb +18 -4
- data/lib/rubocop/cop/style/collection_methods.rb +2 -20
- data/lib/rubocop/cop/style/command_literal.rb +2 -10
- data/lib/rubocop/cop/style/comment_annotation.rb +29 -8
- data/lib/rubocop/cop/style/copyright.rb +5 -3
- data/lib/rubocop/cop/style/documentation.rb +21 -12
- data/lib/rubocop/cop/style/dot_position.rb +6 -0
- data/lib/rubocop/cop/style/double_negation.rb +4 -15
- data/lib/rubocop/cop/style/each_with_object.rb +17 -4
- data/lib/rubocop/cop/style/else_alignment.rb +2 -1
- data/lib/rubocop/cop/style/empty_else.rb +25 -0
- data/lib/rubocop/cop/style/empty_line_between_defs.rb +39 -14
- data/lib/rubocop/cop/style/encoding.rb +10 -4
- data/lib/rubocop/cop/style/extra_spacing.rb +126 -5
- data/lib/rubocop/cop/style/first_array_element_line_break.rb +41 -0
- data/lib/rubocop/cop/style/first_hash_element_line_break.rb +35 -0
- data/lib/rubocop/cop/style/first_method_argument_line_break.rb +37 -0
- data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +42 -0
- data/lib/rubocop/cop/style/first_parameter_indentation.rb +5 -3
- data/lib/rubocop/cop/style/for.rb +2 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +5 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -5
- data/lib/rubocop/cop/style/indent_hash.rb +67 -37
- data/lib/rubocop/cop/style/indentation_width.rb +36 -10
- data/lib/rubocop/cop/style/initial_indentation.rb +37 -0
- data/lib/rubocop/cop/style/leading_comment_space.rb +3 -2
- data/lib/rubocop/cop/style/method_call_parentheses.rb +28 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -7
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +21 -24
- data/lib/rubocop/cop/style/mutable_constant.rb +35 -0
- data/lib/rubocop/cop/style/nested_modifier.rb +97 -0
- data/lib/rubocop/cop/style/next.rb +50 -15
- data/lib/rubocop/cop/style/non_nil_check.rb +12 -8
- data/lib/rubocop/cop/style/one_line_conditional.rb +8 -4
- data/lib/rubocop/cop/style/option_hash.rb +64 -0
- data/lib/rubocop/cop/style/optional_arguments.rb +49 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +218 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -66
- data/lib/rubocop/cop/style/predicate_name.rb +7 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -13
- data/lib/rubocop/cop/style/redundant_freeze.rb +37 -0
- data/lib/rubocop/cop/style/redundant_return.rb +32 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +2 -10
- data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +81 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +30 -22
- data/lib/rubocop/cop/style/send.rb +18 -0
- data/lib/rubocop/cop/style/signal_exception.rb +24 -11
- data/lib/rubocop/cop/style/single_line_methods.rb +8 -9
- data/lib/rubocop/cop/style/single_space_before_first_arg.rb +1 -1
- data/lib/rubocop/cop/style/space_around_operators.rb +2 -0
- data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +61 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +108 -0
- data/lib/rubocop/cop/style/string_methods.rb +32 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +11 -10
- data/lib/rubocop/cop/style/symbol_literal.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +62 -13
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +9 -1
- data/lib/rubocop/cop/style/trailing_comma.rb +17 -7
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -2
- data/lib/rubocop/cop/style/trivial_accessors.rb +10 -1
- data/lib/rubocop/cop/style/unneeded_percent_q.rb +31 -20
- data/lib/rubocop/cop/style/variable_name.rb +5 -0
- data/lib/rubocop/cop/style/while_until_do.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +15 -2
- data/lib/rubocop/cop/team.rb +25 -5
- data/lib/rubocop/cop/util.rb +7 -2
- data/lib/rubocop/cop/variable_force/locatable.rb +6 -6
- data/lib/rubocop/cop/variable_force.rb +10 -10
- data/lib/rubocop/formatter/base_formatter.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +70 -8
- data/lib/rubocop/formatter/formatter_set.rb +27 -1
- data/lib/rubocop/formatter/progress_formatter.rb +10 -2
- data/lib/rubocop/formatter/simple_text_formatter.rb +1 -1
- data/lib/rubocop/node_pattern.rb +390 -0
- data/lib/rubocop/options.rb +148 -81
- data/lib/rubocop/processed_source.rb +7 -2
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +60 -0
- data/lib/rubocop/result_cache.rb +123 -0
- data/lib/rubocop/runner.rb +85 -22
- data/lib/rubocop/target_finder.rb +4 -4
- data/lib/rubocop/token.rb +2 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop/warning.rb +11 -0
- data/lib/rubocop.rb +32 -3
- data/relnotes/v0.32.0.md +139 -0
- data/relnotes/v0.32.1.md +122 -0
- data/relnotes/v0.33.0.md +157 -0
- data/relnotes/v0.34.0.md +182 -0
- data/relnotes/v0.34.1.md +129 -0
- data/relnotes/v0.34.2.md +139 -0
- data/relnotes/v0.35.0.md +210 -0
- data/rubocop.gemspec +4 -4
- metadata +50 -12
- data/lib/rubocop/cop/performance/parallel_assignment.rb +0 -79
|
@@ -7,14 +7,37 @@ module RuboCop
|
|
|
7
7
|
# where the opening brace and the first key are on separate lines. The
|
|
8
8
|
# other keys' indentations are handled by the AlignHash cop.
|
|
9
9
|
#
|
|
10
|
-
# Hash literals that are arguments in a method call with
|
|
11
|
-
# where the opening curly brace of the hash is on the
|
|
12
|
-
# opening parenthesis of the method call, shall have
|
|
13
|
-
# indented one step (two spaces) more than the position
|
|
14
|
-
# opening parenthesis.
|
|
10
|
+
# By default, Hash literals that are arguments in a method call with
|
|
11
|
+
# parentheses, and where the opening curly brace of the hash is on the
|
|
12
|
+
# same line as the opening parenthesis of the method call, shall have
|
|
13
|
+
# their first key indented one step (two spaces) more than the position
|
|
14
|
+
# inside the opening parenthesis.
|
|
15
15
|
#
|
|
16
16
|
# Other hash literals shall have their first key indented one step more
|
|
17
17
|
# than the start of the line where the opening curly brace is.
|
|
18
|
+
#
|
|
19
|
+
# This default style is called 'special_inside_parentheses'. Alternative
|
|
20
|
+
# styles are 'consistent' and 'align_braces'. Here are examples:
|
|
21
|
+
#
|
|
22
|
+
# # special_inside_parentheses
|
|
23
|
+
# hash = {
|
|
24
|
+
# key: :value
|
|
25
|
+
# }
|
|
26
|
+
# but_in_a_method_call({
|
|
27
|
+
# its_like: :this
|
|
28
|
+
# })
|
|
29
|
+
# # consistent
|
|
30
|
+
# hash = {
|
|
31
|
+
# key: :value
|
|
32
|
+
# }
|
|
33
|
+
# and_in_a_method_call({
|
|
34
|
+
# no: :difference
|
|
35
|
+
# })
|
|
36
|
+
# # align_braces
|
|
37
|
+
# and_now_for_something = {
|
|
38
|
+
# completely: :different
|
|
39
|
+
# }
|
|
40
|
+
#
|
|
18
41
|
class IndentHash < Cop
|
|
19
42
|
include AutocorrectAlignment
|
|
20
43
|
include ConfigurableEnforcedStyle
|
|
@@ -62,13 +85,16 @@ module RuboCop
|
|
|
62
85
|
end
|
|
63
86
|
|
|
64
87
|
def check_right_brace(right_brace, left_brace, left_parenthesis)
|
|
88
|
+
# if the right brace is on the same line as the last value, accept
|
|
65
89
|
return if right_brace.source_line[0...right_brace.column] =~ /\S/
|
|
66
90
|
|
|
67
91
|
expected_column = base_column(left_brace, left_parenthesis)
|
|
68
92
|
@column_delta = expected_column - right_brace.column
|
|
69
93
|
return if @column_delta == 0
|
|
70
94
|
|
|
71
|
-
msg = if style == :
|
|
95
|
+
msg = if style == :align_braces
|
|
96
|
+
'Indent the right brace the same as the left brace.'
|
|
97
|
+
elsif style == :special_inside_parentheses && left_parenthesis
|
|
72
98
|
'Indent the right brace the same as the first position ' \
|
|
73
99
|
'after the preceding left parenthesis.'
|
|
74
100
|
else
|
|
@@ -93,15 +119,24 @@ module RuboCop
|
|
|
93
119
|
end
|
|
94
120
|
|
|
95
121
|
def check_first_pair(first_pair, left_brace, left_parenthesis, offset)
|
|
96
|
-
|
|
122
|
+
actual_column = first_pair.loc.expression.column
|
|
97
123
|
expected_column = base_column(left_brace, left_parenthesis) +
|
|
98
124
|
configured_indentation_width + offset
|
|
99
|
-
@column_delta = expected_column -
|
|
125
|
+
@column_delta = expected_column - actual_column
|
|
100
126
|
|
|
101
127
|
if @column_delta == 0
|
|
102
|
-
|
|
128
|
+
# which column was actually used as 'base column' for indentation?
|
|
129
|
+
# (not the column which we think should be the 'base column',
|
|
130
|
+
# but the one which has actually been used for that purpose)
|
|
131
|
+
base_column = actual_column - configured_indentation_width - offset
|
|
132
|
+
styles = detected_styles(base_column, left_parenthesis, left_brace)
|
|
133
|
+
if styles.size > 1
|
|
134
|
+
ambiguous_style_detected(*styles)
|
|
135
|
+
else
|
|
136
|
+
correct_style_detected
|
|
137
|
+
end
|
|
103
138
|
else
|
|
104
|
-
incorrect_style_detected(
|
|
139
|
+
incorrect_style_detected(actual_column, offset, first_pair,
|
|
105
140
|
left_parenthesis, left_brace)
|
|
106
141
|
end
|
|
107
142
|
end
|
|
@@ -110,17 +145,29 @@ module RuboCop
|
|
|
110
145
|
left_parenthesis, left_brace)
|
|
111
146
|
add_offense(first_pair, :expression,
|
|
112
147
|
message(base_description(left_parenthesis))) do
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
else
|
|
117
|
-
unrecognized_style_detected
|
|
118
|
-
end
|
|
148
|
+
base_column = column - configured_indentation_width - offset
|
|
149
|
+
styles = detected_styles(base_column, left_parenthesis, left_brace)
|
|
150
|
+
ambiguous_style_detected(*styles)
|
|
119
151
|
end
|
|
120
152
|
end
|
|
121
153
|
|
|
154
|
+
def detected_styles(column, left_parenthesis, left_brace)
|
|
155
|
+
styles = []
|
|
156
|
+
if column == (left_brace.source_line =~ /\S/)
|
|
157
|
+
styles << :consistent
|
|
158
|
+
styles << :special_inside_parentheses unless left_parenthesis
|
|
159
|
+
end
|
|
160
|
+
if left_parenthesis && column == left_parenthesis.column + 1
|
|
161
|
+
styles << :special_inside_parentheses
|
|
162
|
+
end
|
|
163
|
+
styles << :align_braces if column == left_brace.column
|
|
164
|
+
styles
|
|
165
|
+
end
|
|
166
|
+
|
|
122
167
|
def base_column(left_brace, left_parenthesis)
|
|
123
|
-
if
|
|
168
|
+
if style == :align_braces
|
|
169
|
+
left_brace.column
|
|
170
|
+
elsif left_parenthesis && style == :special_inside_parentheses
|
|
124
171
|
left_parenthesis.column + 1
|
|
125
172
|
else
|
|
126
173
|
left_brace.source_line =~ /\S/
|
|
@@ -129,32 +176,15 @@ module RuboCop
|
|
|
129
176
|
|
|
130
177
|
# Returns the description of what the correct indentation is based on.
|
|
131
178
|
def base_description(left_parenthesis)
|
|
132
|
-
if
|
|
179
|
+
if style == :align_braces
|
|
180
|
+
'the position of the opening brace'
|
|
181
|
+
elsif left_parenthesis && style == :special_inside_parentheses
|
|
133
182
|
'the first position after the preceding left parenthesis'
|
|
134
183
|
else
|
|
135
184
|
'the start of the line where the left curly brace is'
|
|
136
185
|
end
|
|
137
186
|
end
|
|
138
187
|
|
|
139
|
-
# Returns the "unexpected column", which is the column that would be
|
|
140
|
-
# correct if the configuration was changed.
|
|
141
|
-
def unexpected_column(left_brace, left_parenthesis, offset)
|
|
142
|
-
# Set a crazy value by default, indicating that there's no other
|
|
143
|
-
# configuration that can be chosen to make the used indentation
|
|
144
|
-
# accepted.
|
|
145
|
-
unexpected_base_column = -1000
|
|
146
|
-
|
|
147
|
-
if left_parenthesis
|
|
148
|
-
unexpected_base_column = if style == :special_inside_parentheses
|
|
149
|
-
left_brace.source_line =~ /\S/
|
|
150
|
-
else
|
|
151
|
-
left_parenthesis.column + 1
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
unexpected_base_column + configured_indentation_width + offset
|
|
156
|
-
end
|
|
157
|
-
|
|
158
188
|
def message(base_description)
|
|
159
189
|
format('Use %d spaces for indentation in a hash, relative to %s.',
|
|
160
190
|
configured_indentation_width, base_description)
|
|
@@ -13,6 +13,7 @@ module RuboCop
|
|
|
13
13
|
# end
|
|
14
14
|
# end
|
|
15
15
|
class IndentationWidth < Cop # rubocop:disable Metrics/ClassLength
|
|
16
|
+
include EndKeywordAlignment
|
|
16
17
|
include AutocorrectAlignment
|
|
17
18
|
include OnMethodDef
|
|
18
19
|
include CheckAssignment
|
|
@@ -82,10 +83,11 @@ module RuboCop
|
|
|
82
83
|
def on_send(node)
|
|
83
84
|
super
|
|
84
85
|
receiver, method_name, *args = *node
|
|
85
|
-
return unless
|
|
86
|
-
|
|
86
|
+
return unless modifier_and_def_on_same_line?(receiver, method_name,
|
|
87
|
+
args)
|
|
88
|
+
|
|
89
|
+
*_, body = *args.first
|
|
87
90
|
|
|
88
|
-
_method_name, _args, body = *args.first
|
|
89
91
|
def_end_config = config.for_cop('Lint/DefEndAlignment')
|
|
90
92
|
style = if def_end_config['Enabled']
|
|
91
93
|
def_end_config['AlignWith']
|
|
@@ -157,11 +159,7 @@ module RuboCop
|
|
|
157
159
|
return if ternary_op?(node)
|
|
158
160
|
return if modifier_if?(node)
|
|
159
161
|
|
|
160
|
-
|
|
161
|
-
when 'if', 'elsif' then _condition, body, else_clause = *node
|
|
162
|
-
when 'unless' then _condition, else_clause, body = *node
|
|
163
|
-
else _condition, body = *node
|
|
164
|
-
end
|
|
162
|
+
_condition, body, else_clause = if_node_parts(node)
|
|
165
163
|
|
|
166
164
|
check_if(node, body, else_clause, base.loc) if body
|
|
167
165
|
end
|
|
@@ -177,7 +175,7 @@ module RuboCop
|
|
|
177
175
|
|
|
178
176
|
end_config = config.for_cop('Lint/EndAlignment')
|
|
179
177
|
style = end_config['Enabled'] ? end_config['AlignWith'] : 'keyword'
|
|
180
|
-
base =
|
|
178
|
+
base = variable_alignment?(node.loc, rhs, style.to_sym) ? node : rhs
|
|
181
179
|
|
|
182
180
|
case rhs.type
|
|
183
181
|
when :if then on_if(rhs, base)
|
|
@@ -215,13 +213,36 @@ module RuboCop
|
|
|
215
213
|
body_node = body_node.children.first
|
|
216
214
|
end
|
|
217
215
|
|
|
216
|
+
# Since autocorrect changes a number of lines, and not only the line
|
|
217
|
+
# where the reported offending range is, we avoid auto-correction if
|
|
218
|
+
# this cop has already found other offenses is the same
|
|
219
|
+
# range. Otherwise, two corrections can interfere with each other,
|
|
220
|
+
# resulting in corrupted code.
|
|
221
|
+
node = if autocorrect? && other_offense_in_same_range?(body_node)
|
|
222
|
+
nil
|
|
223
|
+
else
|
|
224
|
+
body_node
|
|
225
|
+
end
|
|
226
|
+
|
|
218
227
|
indentation_name = style == 'normal' ? '' : "#{style} "
|
|
219
|
-
add_offense(
|
|
228
|
+
add_offense(node, offending_range(body_node, indentation),
|
|
220
229
|
format("Use #{configured_indentation_width} (not %d) " \
|
|
221
230
|
"spaces for #{indentation_name}indentation.",
|
|
222
231
|
indentation))
|
|
223
232
|
end
|
|
224
233
|
|
|
234
|
+
# Returns true if the given node is within another node that has
|
|
235
|
+
# already been marked for auto-correction by this cop.
|
|
236
|
+
def other_offense_in_same_range?(node)
|
|
237
|
+
expr = node.loc.expression
|
|
238
|
+
@offense_ranges ||= []
|
|
239
|
+
|
|
240
|
+
return true if @offense_ranges.any? { |r| within?(expr, r) }
|
|
241
|
+
|
|
242
|
+
@offense_ranges << expr
|
|
243
|
+
false
|
|
244
|
+
end
|
|
245
|
+
|
|
225
246
|
def indentation_to_check?(base_loc, body_node)
|
|
226
247
|
return false unless body_node
|
|
227
248
|
|
|
@@ -235,6 +256,11 @@ module RuboCop
|
|
|
235
256
|
first_char_pos_on_line = body_node.loc.expression.source_line =~ /\S/
|
|
236
257
|
return false unless body_node.loc.column == first_char_pos_on_line
|
|
237
258
|
|
|
259
|
+
if [:rescue, :ensure].include?(body_node.type)
|
|
260
|
+
block_body, = *body_node
|
|
261
|
+
return unless block_body
|
|
262
|
+
end
|
|
263
|
+
|
|
238
264
|
true
|
|
239
265
|
end
|
|
240
266
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# This cops checks for indentation of the first non-blank non-comment
|
|
7
|
+
# line in a file.
|
|
8
|
+
class InitialIndentation < Cop
|
|
9
|
+
MSG = 'Indentation of first line in file detected.'
|
|
10
|
+
|
|
11
|
+
def investigate(processed_source)
|
|
12
|
+
first_token = processed_source.tokens.find do |t|
|
|
13
|
+
!t.text.start_with?('#')
|
|
14
|
+
end
|
|
15
|
+
return unless first_token
|
|
16
|
+
return if first_token.pos.column == 0
|
|
17
|
+
|
|
18
|
+
with_space = range_with_surrounding_space(first_token.pos, :left,
|
|
19
|
+
nil, !:with_newline)
|
|
20
|
+
# If the file starts with a byte order mark (BOM), the column can be
|
|
21
|
+
# non-zero, but then we find out here if there's no space to the left
|
|
22
|
+
# of the first token.
|
|
23
|
+
return if with_space == first_token.pos
|
|
24
|
+
|
|
25
|
+
space = Parser::Source::Range.new(processed_source.buffer,
|
|
26
|
+
with_space.begin_pos,
|
|
27
|
+
first_token.pos.begin_pos)
|
|
28
|
+
add_offense(space, first_token.pos)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def autocorrect(range)
|
|
32
|
+
->(corrector) { corrector.remove(range) }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -6,13 +6,14 @@ module RuboCop
|
|
|
6
6
|
# This cop checks whether comments have a leading space
|
|
7
7
|
# after the # denoting the start of the comment. The
|
|
8
8
|
# leading space is not required for some RDoc special syntax,
|
|
9
|
-
# like #++, #--, #:nodoc, etc.
|
|
9
|
+
# like #++, #--, #:nodoc, etc. Neither is it required for
|
|
10
|
+
# =begin/=end comments.
|
|
10
11
|
class LeadingCommentSpace < Cop
|
|
11
12
|
MSG = 'Missing space after #.'
|
|
12
13
|
|
|
13
14
|
def investigate(processed_source)
|
|
14
15
|
processed_source.comments.each do |comment|
|
|
15
|
-
next unless comment.text =~
|
|
16
|
+
next unless comment.text =~ /\A#+[^#\s=:+-]/
|
|
16
17
|
next if comment.text.start_with?('#!') && comment.loc.line == 1
|
|
17
18
|
|
|
18
19
|
add_offense(comment, :expression)
|
|
@@ -7,13 +7,17 @@ module RuboCop
|
|
|
7
7
|
class MethodCallParentheses < Cop
|
|
8
8
|
MSG = 'Do not use parentheses for method calls with no arguments.'
|
|
9
9
|
|
|
10
|
+
ASGN_NODES = [:lvasgn, :masgn] + Util::SHORTHAND_ASGN_NODES
|
|
11
|
+
|
|
10
12
|
def on_send(node)
|
|
11
13
|
_receiver, method_name, *args = *node
|
|
12
14
|
|
|
13
15
|
# methods starting with a capital letter should be skipped
|
|
14
16
|
return if method_name =~ /\A[A-Z]/
|
|
17
|
+
return unless args.empty? && node.loc.begin
|
|
18
|
+
return if same_name_assignment?(node)
|
|
15
19
|
|
|
16
|
-
add_offense(node, :begin)
|
|
20
|
+
add_offense(node, :begin)
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
def autocorrect(node)
|
|
@@ -22,6 +26,29 @@ module RuboCop
|
|
|
22
26
|
corrector.remove(node.loc.end)
|
|
23
27
|
end
|
|
24
28
|
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def same_name_assignment?(node)
|
|
33
|
+
_receiver, method_name, *_args = *node
|
|
34
|
+
|
|
35
|
+
node.each_ancestor(ASGN_NODES).any? do |asgn_node|
|
|
36
|
+
if asgn_node.masgn_type?
|
|
37
|
+
mlhs_node, _mrhs_node = *asgn_node
|
|
38
|
+
asgn_node = mlhs_node.children[node.sibling_index]
|
|
39
|
+
end
|
|
40
|
+
# `obj.method = value` parses as (send ... :method= ...), and will
|
|
41
|
+
# not be returned as an `asgn_node` here
|
|
42
|
+
# however, `obj.method ||= value` parses as (or-asgn (send ...) ...)
|
|
43
|
+
# which IS an `asgn_node`
|
|
44
|
+
if asgn_node.or_asgn_type? || asgn_node.and_asgn_type?
|
|
45
|
+
asgn_node, _value = *asgn_node
|
|
46
|
+
return false if asgn_node.send_type?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
asgn_node.loc.name.source == method_name.to_s
|
|
50
|
+
end
|
|
51
|
+
end
|
|
25
52
|
end
|
|
26
53
|
end
|
|
27
54
|
end
|
|
@@ -10,7 +10,9 @@ module RuboCop
|
|
|
10
10
|
include ConfigurableEnforcedStyle
|
|
11
11
|
|
|
12
12
|
def on_method_def(node, _method_name, args, _body)
|
|
13
|
-
if style == :require_parentheses
|
|
13
|
+
if style == :require_parentheses ||
|
|
14
|
+
(style == :require_no_parentheses_except_multiline &&
|
|
15
|
+
args.multiline?)
|
|
14
16
|
if arguments?(args) && !parentheses?(args)
|
|
15
17
|
missing_parentheses(node, args)
|
|
16
18
|
else
|
|
@@ -25,7 +27,11 @@ module RuboCop
|
|
|
25
27
|
|
|
26
28
|
def autocorrect(node)
|
|
27
29
|
lambda do |corrector|
|
|
28
|
-
if
|
|
30
|
+
if node.args_type?
|
|
31
|
+
# offense is registered on args node when parentheses are unwanted
|
|
32
|
+
corrector.replace(node.loc.begin, ' ')
|
|
33
|
+
corrector.remove(node.loc.end)
|
|
34
|
+
else
|
|
29
35
|
args_expr = args_node(node).loc.expression
|
|
30
36
|
args_with_space = range_with_surrounding_space(args_expr, :left)
|
|
31
37
|
just_space = Parser::Source::Range.new(args_expr.source_buffer,
|
|
@@ -33,9 +39,6 @@ module RuboCop
|
|
|
33
39
|
args_expr.begin_pos)
|
|
34
40
|
corrector.replace(just_space, '(')
|
|
35
41
|
corrector.insert_after(args_expr, ')')
|
|
36
|
-
elsif style == :require_no_parentheses
|
|
37
|
-
corrector.replace(node.loc.begin, ' ')
|
|
38
|
-
corrector.remove(node.loc.end)
|
|
39
42
|
end
|
|
40
43
|
end
|
|
41
44
|
end
|
|
@@ -45,13 +48,13 @@ module RuboCop
|
|
|
45
48
|
def missing_parentheses(node, args)
|
|
46
49
|
add_offense(node, args.loc.expression,
|
|
47
50
|
'Use def with parentheses when there are parameters.') do
|
|
48
|
-
|
|
51
|
+
unexpected_style_detected(:require_no_parentheses)
|
|
49
52
|
end
|
|
50
53
|
end
|
|
51
54
|
|
|
52
55
|
def unwanted_parentheses(args)
|
|
53
56
|
add_offense(args, :expression, 'Use def without parentheses.') do
|
|
54
|
-
|
|
57
|
+
unexpected_style_detected(:require_parentheses)
|
|
55
58
|
end
|
|
56
59
|
end
|
|
57
60
|
|
|
@@ -12,7 +12,7 @@ module RuboCop
|
|
|
12
12
|
# b
|
|
13
13
|
# something
|
|
14
14
|
# end
|
|
15
|
-
class MultilineOperationIndentation < Cop
|
|
15
|
+
class MultilineOperationIndentation < Cop
|
|
16
16
|
include ConfigurableEnforcedStyle
|
|
17
17
|
include AutocorrectAlignment
|
|
18
18
|
|
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
|
98
98
|
article = kw =~ /^[iu]/ ? 'an' : 'a'
|
|
99
99
|
"a #{kind} in #{article} `#{kw}` statement"
|
|
100
100
|
else
|
|
101
|
-
'an expression' + (
|
|
101
|
+
'an expression' + (assignment_rhs?(node) ? ' in an assignment' : '')
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
104
|
|
|
@@ -121,15 +121,17 @@ module RuboCop
|
|
|
121
121
|
_, method_name, *args = *send_node
|
|
122
122
|
if operator?(method_name) && args.any?
|
|
123
123
|
args.first.loc.expression
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
else
|
|
125
|
+
dot = send_node.loc.dot
|
|
126
|
+
selector = send_node.loc.selector
|
|
127
|
+
if dot && selector && dot.line == selector.line
|
|
128
|
+
dot.join(selector)
|
|
129
|
+
elsif selector
|
|
130
|
+
selector
|
|
131
|
+
elsif dot.line == send_node.loc.begin.line
|
|
132
|
+
# lambda.(args)
|
|
133
|
+
dot.join(send_node.loc.begin)
|
|
134
|
+
end
|
|
133
135
|
end
|
|
134
136
|
end
|
|
135
137
|
|
|
@@ -140,7 +142,7 @@ module RuboCop
|
|
|
140
142
|
|
|
141
143
|
def should_align?(node, given_style)
|
|
142
144
|
given_style == :aligned && (kw_node_with_special_indentation(node) ||
|
|
143
|
-
|
|
145
|
+
assignment_rhs?(node))
|
|
144
146
|
end
|
|
145
147
|
|
|
146
148
|
def kw_node_with_special_indentation(node)
|
|
@@ -158,22 +160,17 @@ module RuboCop
|
|
|
158
160
|
end
|
|
159
161
|
end
|
|
160
162
|
|
|
161
|
-
def
|
|
162
|
-
node.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
# as a :send node.
|
|
168
|
-
method_name == :[]=
|
|
169
|
-
when *ASGN_NODES
|
|
170
|
-
true
|
|
171
|
-
end
|
|
163
|
+
def assignment_rhs?(node)
|
|
164
|
+
node.ancestors.unshift(node).each_cons(2).any? do |child, parent|
|
|
165
|
+
return true if parent.asgn_rhs.equal?(child)
|
|
166
|
+
grandparent = parent.parent
|
|
167
|
+
return true if grandparent && grandparent.masgn_type? &&
|
|
168
|
+
grandparent.asgn_rhs.equal?(parent)
|
|
172
169
|
end
|
|
173
170
|
end
|
|
174
171
|
|
|
175
172
|
def not_for_this_cop?(node)
|
|
176
|
-
node.each_ancestor.
|
|
173
|
+
node.each_ancestor.any? do |ancestor|
|
|
177
174
|
grouped_expression?(ancestor) ||
|
|
178
175
|
inside_arg_list_parentheses?(node, ancestor)
|
|
179
176
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# This cop checks whether some constant value isn't a
|
|
7
|
+
# mutable literal (e.g. array or hash).
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# # bad
|
|
11
|
+
# CONST = [1, 2, 3]
|
|
12
|
+
#
|
|
13
|
+
# # good
|
|
14
|
+
# CONST = [1, 2, 3].freeze
|
|
15
|
+
class MutableConstant < Cop
|
|
16
|
+
MSG = 'Freeze mutable objects assigned to constants.'
|
|
17
|
+
|
|
18
|
+
MUTABLE_TYPES = [:array, :hash, :str, :dstr].freeze
|
|
19
|
+
|
|
20
|
+
def on_casgn(node)
|
|
21
|
+
_scope, _const_name, value = *node
|
|
22
|
+
|
|
23
|
+
return if value && !MUTABLE_TYPES.include?(value.type)
|
|
24
|
+
|
|
25
|
+
add_offense(value, :expression)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def autocorrect(node)
|
|
29
|
+
expr = node.loc.expression
|
|
30
|
+
->(corrector) { corrector.replace(expr, "#{expr.source}.freeze") }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# This cop checks for nested use of if, unless, while and until in their
|
|
7
|
+
# modifier form.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
#
|
|
11
|
+
# # bad
|
|
12
|
+
# something if a if b
|
|
13
|
+
#
|
|
14
|
+
# # good
|
|
15
|
+
# something if b && a
|
|
16
|
+
class NestedModifier < Cop
|
|
17
|
+
include IfNode
|
|
18
|
+
|
|
19
|
+
MSG = 'Avoid using nested modifiers.'
|
|
20
|
+
|
|
21
|
+
def on_while(node)
|
|
22
|
+
check(node)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def on_until(node)
|
|
26
|
+
check(node)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def on_if(node)
|
|
30
|
+
check(node)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def check(node)
|
|
34
|
+
return if part_of_ignored_node?(node)
|
|
35
|
+
return unless modifier?(node)
|
|
36
|
+
|
|
37
|
+
ancestor = node.ancestors.first
|
|
38
|
+
return unless ancestor &&
|
|
39
|
+
[:if, :while, :until].include?(ancestor.type) &&
|
|
40
|
+
modifier?(ancestor)
|
|
41
|
+
|
|
42
|
+
add_offense(node, :keyword)
|
|
43
|
+
ignore_node(node)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def modifier?(node)
|
|
47
|
+
modifier_if?(node) || modifier_while_or_until?(node)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def modifier_while_or_until?(node)
|
|
51
|
+
node.loc.respond_to?(:keyword) &&
|
|
52
|
+
%w(while until).include?(node.loc.keyword.source) &&
|
|
53
|
+
node.loc.respond_to?(:end) && node.loc.end.nil?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def autocorrect(node)
|
|
57
|
+
return unless node.if_type?
|
|
58
|
+
|
|
59
|
+
ancestor = node.ancestors.first
|
|
60
|
+
return unless ancestor.if_type?
|
|
61
|
+
|
|
62
|
+
autocorrect_if_unless(ancestor, node)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def autocorrect_if_unless(outer_node, inner_node)
|
|
66
|
+
outer_cond, = *outer_node
|
|
67
|
+
|
|
68
|
+
range =
|
|
69
|
+
Parser::Source::Range.new(inner_node.loc.expression.source_buffer,
|
|
70
|
+
inner_node.loc.keyword.begin_pos,
|
|
71
|
+
outer_cond.loc.expression.end_pos)
|
|
72
|
+
|
|
73
|
+
lambda do |corrector|
|
|
74
|
+
corrector.replace(range, new_expression(outer_node, inner_node))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def new_expression(outer_node, inner_node)
|
|
79
|
+
outer_cond, = *outer_node
|
|
80
|
+
inner_cond, = *inner_node
|
|
81
|
+
|
|
82
|
+
outer_keyword = outer_node.loc.keyword.source
|
|
83
|
+
inner_keyword = inner_node.loc.keyword.source
|
|
84
|
+
|
|
85
|
+
operator = outer_keyword == 'if' ? '&&' : '||'
|
|
86
|
+
|
|
87
|
+
inner_expr = inner_cond.loc.expression.source
|
|
88
|
+
inner_expr = "(#{inner_expr})" if inner_cond.or_type?
|
|
89
|
+
inner_expr = "!#{inner_expr}" unless outer_keyword == inner_keyword
|
|
90
|
+
|
|
91
|
+
"#{outer_node.loc.keyword.source} " \
|
|
92
|
+
"#{outer_cond.loc.expression.source} #{operator} #{inner_expr}"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|