rubocop 1.92.0 → 1.92.2
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/config/default.yml +1 -0
- data/lib/rubocop/config.rb +0 -4
- data/lib/rubocop/config_obsoletion.rb +9 -0
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +16 -1
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/class_structure.rb +21 -7
- data/lib/rubocop/cop/layout/dot_position.rb +25 -15
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +11 -7
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
- data/lib/rubocop/cop/layout/end_alignment.rb +5 -15
- data/lib/rubocop/cop/layout/extra_spacing.rb +18 -7
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +26 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +11 -5
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +5 -3
- data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
- data/lib/rubocop/cop/layout/line_length.rb +127 -11
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +6 -4
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +16 -5
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +3 -3
- data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +12 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +2 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
- data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -8
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
- data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -6
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +36 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -5
- data/lib/rubocop/cop/mixin/statement_modifier.rb +17 -3
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +30 -2
- data/lib/rubocop/cop/style/and_or.rb +34 -11
- data/lib/rubocop/cop/style/arguments_forwarding.rb +28 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +6 -0
- data/lib/rubocop/cop/style/case_equality.rb +14 -3
- data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
- data/lib/rubocop/cop/style/class_methods_definitions.rb +7 -0
- data/lib/rubocop/cop/style/collection_querying.rb +79 -46
- data/lib/rubocop/cop/style/combinable_loops.rb +4 -0
- data/lib/rubocop/cop/style/concat_array_literals.rb +13 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
- data/lib/rubocop/cop/style/endless_method.rb +38 -6
- data/lib/rubocop/cop/style/float_division.rb +16 -1
- data/lib/rubocop/cop/style/for.rb +14 -1
- data/lib/rubocop/cop/style/guard_clause.rb +22 -21
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
- data/lib/rubocop/cop/style/hash_lookup_method.rb +10 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +63 -2
- data/lib/rubocop/cop/style/lambda.rb +16 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +36 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +9 -1
- data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
- data/lib/rubocop/cop/style/mutable_constant.rb +25 -7
- data/lib/rubocop/cop/style/numeric_predicate.rb +7 -0
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
- data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
- data/lib/rubocop/cop/style/raise_args.rb +80 -11
- data/lib/rubocop/cop/style/reduce_to_hash.rb +32 -34
- data/lib/rubocop/cop/style/redundant_begin.rb +26 -3
- data/lib/rubocop/cop/style/redundant_exception.rb +13 -9
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -2
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
- data/lib/rubocop/cop/style/redundant_self.rb +9 -1
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
- data/lib/rubocop/cop/style/require_order.rb +16 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +6 -0
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +26 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +12 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +23 -23
- data/lib/rubocop/plugin/configuration_integrator.rb +24 -3
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/server/cache.rb +4 -4
- data/lib/rubocop/target_ruby.rb +21 -9
- data/lib/rubocop/version.rb +1 -1
- metadata +2 -2
|
@@ -9,6 +9,11 @@ module RuboCop
|
|
|
9
9
|
# example, mistranslating an array of literals to percent string notation)
|
|
10
10
|
# rather than meant to be part of the resulting strings.
|
|
11
11
|
#
|
|
12
|
+
# When a quoted string contains whitespace, `%w` splits it into separate values,
|
|
13
|
+
# so removing the quotes would not restore the intended string.
|
|
14
|
+
# Such an array is corrected to an array literal instead, as long as its content
|
|
15
|
+
# reads as one with only string elements.
|
|
16
|
+
#
|
|
12
17
|
# @safety
|
|
13
18
|
# The cop is unsafe because the correction changes the values in the array
|
|
14
19
|
# and that might have been done purposely.
|
|
@@ -26,6 +31,12 @@ module RuboCop
|
|
|
26
31
|
#
|
|
27
32
|
# # good
|
|
28
33
|
# %w(foo bar)
|
|
34
|
+
#
|
|
35
|
+
# # bad - the quoted strings are split at whitespace
|
|
36
|
+
# %w('foo bar', 'baz')
|
|
37
|
+
#
|
|
38
|
+
# # good
|
|
39
|
+
# ['foo bar', 'baz']
|
|
29
40
|
class PercentStringArray < Base
|
|
30
41
|
include PercentLiteral
|
|
31
42
|
extend AutoCorrector
|
|
@@ -36,27 +47,69 @@ module RuboCop
|
|
|
36
47
|
|
|
37
48
|
MSG = "Within `%w`/`%W`, quotes and ',' are unnecessary and may be " \
|
|
38
49
|
'unwanted in the resulting strings.'
|
|
50
|
+
MSG_SPLIT_STRING = 'Within `%w`/`%W`, quoted strings are split at whitespace; ' \
|
|
51
|
+
'use an array literal instead.'
|
|
39
52
|
|
|
40
53
|
def on_array(node)
|
|
41
54
|
process(node, '%w', '%W')
|
|
42
55
|
end
|
|
43
56
|
|
|
44
57
|
def on_percent_literal(node)
|
|
45
|
-
|
|
58
|
+
if split_quoted_string?(node)
|
|
59
|
+
register_split_quoted_string(node)
|
|
60
|
+
elsif contains_quotes_or_commas?(node)
|
|
61
|
+
register_quotes_or_commas(node)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
46
64
|
|
|
47
|
-
|
|
48
|
-
node.each_value do |value|
|
|
49
|
-
range = value.source_range
|
|
65
|
+
private
|
|
50
66
|
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
def split_quoted_string?(node)
|
|
68
|
+
sources = node.values.map { |value| value.source.delete_suffix(',') }
|
|
53
69
|
|
|
54
|
-
|
|
55
|
-
|
|
70
|
+
sources.each_with_index.any? do |source, index|
|
|
71
|
+
next false unless (quote = unclosed_quote(source))
|
|
72
|
+
|
|
73
|
+
sources.drop(index + 1).any? { |rest| closing_quote?(rest, quote) }
|
|
56
74
|
end
|
|
57
75
|
end
|
|
58
76
|
|
|
59
|
-
|
|
77
|
+
def unclosed_quote(source)
|
|
78
|
+
quote = source[0]
|
|
79
|
+
return unless LEADING_QUOTE.match?(quote)
|
|
80
|
+
|
|
81
|
+
quote if source.length > 1 && !source.end_with?(quote)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def closing_quote?(source, quote)
|
|
85
|
+
source.end_with?(quote) && (source.length == 1 || !source.start_with?(quote))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def register_split_quoted_string(node)
|
|
89
|
+
add_offense(node, message: MSG_SPLIT_STRING) do |corrector|
|
|
90
|
+
next unless (array_literal = array_literal_source(node))
|
|
91
|
+
|
|
92
|
+
corrector.replace(node, array_literal)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def array_literal_source(node)
|
|
97
|
+
content = range_between(node.loc.begin.end_pos, node.loc.end.begin_pos).source
|
|
98
|
+
array_literal = "[#{content}]"
|
|
99
|
+
|
|
100
|
+
array_literal if string_array?(parse(array_literal))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def string_array?(processed_source)
|
|
104
|
+
return false unless processed_source.valid_syntax? && processed_source.comments.empty?
|
|
105
|
+
return false unless (array = processed_source.ast).array_type?
|
|
106
|
+
|
|
107
|
+
array.children.all? { |child| quoted_string?(child) }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def quoted_string?(node)
|
|
111
|
+
node.type?(:str, :dstr) && node.loc?(:begin)
|
|
112
|
+
end
|
|
60
113
|
|
|
61
114
|
def contains_quotes_or_commas?(node)
|
|
62
115
|
node.values.any? do |value|
|
|
@@ -68,6 +121,19 @@ module RuboCop
|
|
|
68
121
|
QUOTES_AND_COMMAS.any? { |pat| literal.match?(pat) }
|
|
69
122
|
end
|
|
70
123
|
end
|
|
124
|
+
|
|
125
|
+
def register_quotes_or_commas(node)
|
|
126
|
+
add_offense(node) do |corrector|
|
|
127
|
+
node.each_value do |value|
|
|
128
|
+
range = value.source_range
|
|
129
|
+
|
|
130
|
+
match = range.source.match(TRAILING_QUOTE)
|
|
131
|
+
corrector.remove_trailing(range, match[0].length) if match
|
|
132
|
+
|
|
133
|
+
corrector.remove_leading(range, 1) if LEADING_QUOTE.match?(range.source)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
71
137
|
end
|
|
72
138
|
end
|
|
73
139
|
end
|
|
@@ -146,8 +146,8 @@ module RuboCop
|
|
|
146
146
|
comment = directive_comment(line_range)
|
|
147
147
|
next if skip_directive?(comment)
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
redundant = find_redundant_directive(cop, comment, line_range,
|
|
149
|
+
following_ranges = line_ranges[(line_range_index + 1)..]
|
|
150
|
+
redundant = find_redundant_directive(cop, comment, line_range, following_ranges)
|
|
151
151
|
yield comment, redundant if redundant
|
|
152
152
|
end
|
|
153
153
|
end
|
|
@@ -191,14 +191,33 @@ module RuboCop
|
|
|
191
191
|
directive.push? || directive.pop? || directive.next?
|
|
192
192
|
end
|
|
193
193
|
|
|
194
|
-
def find_redundant_directive(cop, comment, line_range,
|
|
195
|
-
if all_disabled?(comment)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
194
|
+
def find_redundant_directive(cop, comment, line_range, following_ranges)
|
|
195
|
+
return find_redundant_all(line_range, following_ranges.first) if all_disabled?(comment)
|
|
196
|
+
|
|
197
|
+
range = line_range_through_repeated_disables(cop, line_range, following_ranges)
|
|
198
|
+
if department_disabled?(cop, comment)
|
|
199
|
+
find_redundant_department(cop, range)
|
|
199
200
|
else
|
|
200
|
-
find_redundant_cop(cop,
|
|
201
|
+
find_redundant_cop(cop, range)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def line_range_through_repeated_disables(cop, line_range, following_ranges)
|
|
206
|
+
last_range = line_range
|
|
207
|
+
following_ranges.each do |range|
|
|
208
|
+
break unless followed_ranges?(last_range, range) && repeated_disable?(cop, range)
|
|
209
|
+
|
|
210
|
+
last_range = range
|
|
201
211
|
end
|
|
212
|
+
|
|
213
|
+
line_range.begin..last_range.end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def repeated_disable?(cop, range)
|
|
217
|
+
comment = directive_comment(range)
|
|
218
|
+
return false if comment.nil? || skip_directive?(comment)
|
|
219
|
+
|
|
220
|
+
!all_disabled?(comment) && !department_disabled?(cop, comment)
|
|
202
221
|
end
|
|
203
222
|
|
|
204
223
|
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
@@ -118,10 +118,7 @@ module RuboCop
|
|
|
118
118
|
def redundant_splat_expansion(node)
|
|
119
119
|
literal_expansion(node) do |expanded_item|
|
|
120
120
|
if expanded_item.send_type?
|
|
121
|
-
return
|
|
122
|
-
|
|
123
|
-
grandparent = node.parent.parent
|
|
124
|
-
return if grandparent && !ASSIGNMENT_TYPES.include?(grandparent.type)
|
|
121
|
+
return unless redundant_array_new_splat?(node, expanded_item)
|
|
125
122
|
# An empty array/percent literal (`*[]`, `*%w()`, ...) expands to nothing, so
|
|
126
123
|
# removing the splat would produce invalid or semantically different code.
|
|
127
124
|
elsif expanded_item.array_type? && expanded_item.children.empty?
|
|
@@ -132,6 +129,16 @@ module RuboCop
|
|
|
132
129
|
end
|
|
133
130
|
end
|
|
134
131
|
|
|
132
|
+
# A splatted `Array.new` passed as a method argument provides the arguments,
|
|
133
|
+
# so the splat is only redundant directly inside an array.
|
|
134
|
+
def redundant_array_new_splat?(node, array_new_node)
|
|
135
|
+
return false unless node.parent.array_type?
|
|
136
|
+
return false if array_new_inside_array_literal?(array_new_node)
|
|
137
|
+
|
|
138
|
+
grandparent = node.parent.parent
|
|
139
|
+
!grandparent || ASSIGNMENT_TYPES.include?(grandparent.type)
|
|
140
|
+
end
|
|
141
|
+
|
|
135
142
|
def array_new_inside_array_literal?(array_new_node)
|
|
136
143
|
return false unless array_new?(array_new_node)
|
|
137
144
|
|
|
@@ -60,7 +60,7 @@ module RuboCop
|
|
|
60
60
|
|
|
61
61
|
rest_operands = grouped_operands[begin_of_rest_operands..]
|
|
62
62
|
rest_operands.each do |operand|
|
|
63
|
-
next
|
|
63
|
+
next unless correction_needed?(operand, dot_op, grouped_operands)
|
|
64
64
|
|
|
65
65
|
register_offense(operand, dot_op)
|
|
66
66
|
end
|
|
@@ -100,12 +100,58 @@ module RuboCop
|
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
def correction_needed?(operand, dot_op, grouped_operands)
|
|
104
|
+
return false if already_appropriate_call?(operand, dot_op)
|
|
105
|
+
|
|
106
|
+
dot_op == '&.' || receiver_guaranteed?(operand, grouped_operands)
|
|
107
|
+
end
|
|
108
|
+
|
|
103
109
|
def already_appropriate_call?(operand, dot_op)
|
|
104
110
|
return true if operand.safe_navigation? && dot_op == '&.'
|
|
105
111
|
|
|
106
112
|
(operand.dot? || operand.operator_method?) && dot_op == '.'
|
|
107
113
|
end
|
|
108
114
|
|
|
115
|
+
def receiver_guaranteed?(operand, grouped_operands)
|
|
116
|
+
grouped_operands.take_while { |guard| !guard.equal?(operand) }.any? do |guard|
|
|
117
|
+
guaranteed_by?(guard, operand)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def guaranteed_by?(guard, operand)
|
|
122
|
+
return false unless (path = logical_path(guard, operand))
|
|
123
|
+
|
|
124
|
+
truthiness = path.last.first.and_type? ? :truthy : :falsey
|
|
125
|
+
path[0...-1].reverse_each do |node, child|
|
|
126
|
+
return false unless (truthiness = child_truthiness(node, child, truthiness))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
!guard.csend_type? || truthiness == :truthy
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def logical_path(guard, operand)
|
|
133
|
+
path = []
|
|
134
|
+
child = guard
|
|
135
|
+
|
|
136
|
+
guard.each_ancestor do |node|
|
|
137
|
+
unless node.begin_type?
|
|
138
|
+
return nil unless node.operator_keyword?
|
|
139
|
+
|
|
140
|
+
path << [node, child]
|
|
141
|
+
end
|
|
142
|
+
return path if operand.each_ancestor.any? { |ancestor| ancestor.equal?(node) }
|
|
143
|
+
|
|
144
|
+
child = node
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def child_truthiness(node, child, truthiness)
|
|
149
|
+
deciding = node.and_type? ? :truthy : :falsey
|
|
150
|
+
return truthiness == deciding ? deciding : :unknown if node.lhs.equal?(child)
|
|
151
|
+
|
|
152
|
+
deciding if truthiness == deciding
|
|
153
|
+
end
|
|
154
|
+
|
|
109
155
|
def register_offense(operand, dot_operator)
|
|
110
156
|
offense_range = operand.operator_method? ? operand : operand.loc.dot
|
|
111
157
|
message = dot_operator == '.' ? USE_DOT_MSG : USE_SAFE_NAVIGATION_MSG
|
|
@@ -35,15 +35,13 @@ module RuboCop
|
|
|
35
35
|
ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn].freeze
|
|
36
36
|
|
|
37
37
|
def on_def(node)
|
|
38
|
-
return
|
|
38
|
+
return if !node.body || node.void_context?
|
|
39
39
|
|
|
40
40
|
last_expr = last_expression(node.body)
|
|
41
41
|
return unless setter_call_to_local_variable?(last_expr)
|
|
42
42
|
|
|
43
|
-
tracker = MethodVariableTracker.new(node.body)
|
|
44
43
|
receiver, = *last_expr
|
|
45
|
-
|
|
46
|
-
return unless tracker.contain_local_object?(variable_name)
|
|
44
|
+
return unless contain_local_object?(node.body, receiver)
|
|
47
45
|
|
|
48
46
|
loc_name = receiver.loc.name
|
|
49
47
|
|
|
@@ -66,6 +64,11 @@ module RuboCop
|
|
|
66
64
|
expression.is_a?(Array) ? expression.last : expression
|
|
67
65
|
end
|
|
68
66
|
|
|
67
|
+
def contain_local_object?(body, receiver)
|
|
68
|
+
variable_name, = *receiver
|
|
69
|
+
MethodVariableTracker.new(body).contain_local_object?(variable_name)
|
|
70
|
+
end
|
|
71
|
+
|
|
69
72
|
# This class tracks variable assignments in a method body
|
|
70
73
|
# and if a variable contains object passed as argument at the end of
|
|
71
74
|
# the method.
|
|
@@ -76,11 +76,7 @@ module RuboCop
|
|
|
76
76
|
def extract_first_element_over_column_limit(node, elements, max)
|
|
77
77
|
line = node.first_line
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
# can result in changed behavior or a syntax error.
|
|
81
|
-
if node.call_type? && !node.parenthesized? && !first_argument_is_heredoc?(node)
|
|
82
|
-
elements = elements.drop(1)
|
|
83
|
-
end
|
|
79
|
+
elements = elements.drop(1) unless first_element_movable?(node)
|
|
84
80
|
|
|
85
81
|
i = 0
|
|
86
82
|
i += 1 while within_column_limit?(elements[i], max, line)
|
|
@@ -93,7 +89,12 @@ module RuboCop
|
|
|
93
89
|
end
|
|
94
90
|
|
|
95
91
|
# @api private
|
|
96
|
-
|
|
92
|
+
# If a method call or definition is not parenthesized, the first element cannot be moved,
|
|
93
|
+
# because it can result in changed behavior or a syntax error.
|
|
94
|
+
def first_element_movable?(node)
|
|
95
|
+
return !node.arguments.loc.begin.nil? if node.any_def_type?
|
|
96
|
+
return true if !node.call_type? || node.parenthesized?
|
|
97
|
+
|
|
97
98
|
node.first_argument.respond_to?(:heredoc?) && node.first_argument.heredoc?
|
|
98
99
|
end
|
|
99
100
|
|
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
|
5
5
|
# Checks for code on multiple lines that could be rewritten on a single line
|
|
6
6
|
# without changing semantics or exceeding the `Max` parameter of `Layout/LineLength`.
|
|
7
7
|
module CheckSingleLineSuitability
|
|
8
|
+
include LineLengthHelp
|
|
9
|
+
|
|
8
10
|
def suitable_as_single_line?(node)
|
|
9
11
|
!too_long?(node) &&
|
|
10
12
|
!comment_within?(node) &&
|
|
@@ -21,7 +23,7 @@ module RuboCop
|
|
|
21
23
|
return false unless max_line_length
|
|
22
24
|
|
|
23
25
|
lines = processed_source.lines[(line_range.begin - 1)...line_range.end]
|
|
24
|
-
to_single_line(lines.join("\n"))
|
|
26
|
+
line_length(to_single_line(lines.join("\n"))) > max_line_length
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def to_single_line(source)
|
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
|
66
66
|
# the line at which the parent node ends.
|
|
67
67
|
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
68
68
|
def find_end_line(node)
|
|
69
|
-
if node.if_type?
|
|
69
|
+
if node.if_type? && !node.modifier_form?
|
|
70
70
|
if node.else?
|
|
71
71
|
node.loc.else.line
|
|
72
72
|
elsif node.ternary?
|
|
@@ -45,12 +45,44 @@ module RuboCop
|
|
|
45
45
|
|
|
46
46
|
def command_disallowed_in_endless_body?(body)
|
|
47
47
|
return true if body.assignment? && command_call?(assigned_value(body))
|
|
48
|
+
return true if body_disallowed_in_argument?(body)
|
|
49
|
+
return true if negated_command_call?(body)
|
|
48
50
|
|
|
49
51
|
body.each_node(:any_block).any? do |block|
|
|
50
52
|
block.keywords? && command_call?(block.send_node)
|
|
51
53
|
end
|
|
52
54
|
end
|
|
53
55
|
|
|
56
|
+
def body_disallowed_in_argument?(body)
|
|
57
|
+
command_body_in_argument?(body) || do_end_block_body_in_command_argument?(body)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# `private def foo = bar baz` parses only on Ruby 4.0+, and only as the sole argument.
|
|
61
|
+
def command_body_in_argument?(body)
|
|
62
|
+
return false unless command_call?(body)
|
|
63
|
+
|
|
64
|
+
call = argument_receiving_call(body.parent)
|
|
65
|
+
return false if call.nil?
|
|
66
|
+
|
|
67
|
+
target_ruby_version < 4.0 || !call.arguments.one?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def argument_receiving_call(def_node)
|
|
71
|
+
call = def_node.parent
|
|
72
|
+
return unless call&.call_type?
|
|
73
|
+
|
|
74
|
+
call if call.arguments.any? { |argument| argument.equal?(def_node) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def do_end_block_body_in_command_argument?(body)
|
|
78
|
+
call = argument_receiving_call(body.parent)
|
|
79
|
+
return false if call.nil? || call.parenthesized?
|
|
80
|
+
|
|
81
|
+
body.each_node(:any_block).any? do |block|
|
|
82
|
+
block.keywords? && !block.send_node.lambda_literal?
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
54
86
|
def assigned_value(node)
|
|
55
87
|
while node.assignment? || node.rescue_type?
|
|
56
88
|
node = node.rescue_type? ? node.body : node.children.last
|
|
@@ -64,6 +96,10 @@ module RuboCop
|
|
|
64
96
|
|
|
65
97
|
node.arguments? && !node.parenthesized? && !node.operator_method? && !node.setter_method?
|
|
66
98
|
end
|
|
99
|
+
|
|
100
|
+
def negated_command_call?(node)
|
|
101
|
+
node.send_type? && node.prefix_bang? && command_call?(node.receiver)
|
|
102
|
+
end
|
|
67
103
|
end
|
|
68
104
|
end
|
|
69
105
|
end
|
|
@@ -55,13 +55,21 @@ module RuboCop
|
|
|
55
55
|
# Common functionality for checking alignment of hash values.
|
|
56
56
|
module ValueAlignment
|
|
57
57
|
def checkable_layout?(node)
|
|
58
|
-
!node.pairs_on_same_line? && !node.mixed_delimiters? && alignable_values?(node)
|
|
58
|
+
!node.pairs_on_same_line? && !node.mixed_delimiters? && alignable_values?(node) &&
|
|
59
|
+
!pair_after_kwsplat_on_same_line?(node)
|
|
59
60
|
end
|
|
60
61
|
|
|
62
|
+
# With several enforced styles, deltas are computed even for a hash this style
|
|
63
|
+
# can't check. A pair that doesn't begin its line can't be moved without
|
|
64
|
+
# deleting whatever precedes it, so it's left alone.
|
|
61
65
|
def deltas(first_pair, current_pair)
|
|
66
|
+
return {} unless current_pair.equal?(first_pair) ||
|
|
67
|
+
Util.begins_its_line?(current_pair.source_range)
|
|
68
|
+
|
|
62
69
|
key_delta = key_delta(first_pair, current_pair)
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
shift = separator_shift(current_pair, key_delta)
|
|
71
|
+
separator_delta = separator_delta(first_pair, current_pair, shift)
|
|
72
|
+
value_delta = value_delta(first_pair, current_pair) - shift - separator_delta
|
|
65
73
|
|
|
66
74
|
{ key: key_delta, separator: separator_delta, value: value_delta }
|
|
67
75
|
end
|
|
@@ -78,9 +86,22 @@ module RuboCop
|
|
|
78
86
|
pair.value && pair.key.last_line != pair.value.first_line
|
|
79
87
|
end
|
|
80
88
|
|
|
81
|
-
def
|
|
89
|
+
def pair_after_kwsplat_on_same_line?(node)
|
|
90
|
+
first_pair = node.pairs.first
|
|
91
|
+
|
|
92
|
+
node.children.each_cons(2).any? do |previous, current|
|
|
93
|
+
current.pair_type? && !current.equal?(first_pair) &&
|
|
94
|
+
previous.last_line == current.first_line
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def separator_shift(current_pair, key_delta)
|
|
99
|
+
current_pair.key.multiline? ? 0 : key_delta
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def separator_delta(first_pair, current_pair, shift)
|
|
82
103
|
if current_pair.hash_rocket?
|
|
83
|
-
hash_rocket_delta(first_pair, current_pair) -
|
|
104
|
+
hash_rocket_delta(first_pair, current_pair) - shift
|
|
84
105
|
else
|
|
85
106
|
0
|
|
86
107
|
end
|
|
@@ -7,6 +7,8 @@ module RuboCop
|
|
|
7
7
|
include LineLengthHelp
|
|
8
8
|
include AllowedPattern
|
|
9
9
|
|
|
10
|
+
SPACE_INSIDE_PARENS_STYLES = %w[space compact].freeze
|
|
11
|
+
|
|
10
12
|
private
|
|
11
13
|
|
|
12
14
|
def single_line_as_modifier?(node)
|
|
@@ -42,7 +44,10 @@ module RuboCop
|
|
|
42
44
|
def modifier_fits_on_single_line?(node)
|
|
43
45
|
return true unless max_line_length
|
|
44
46
|
|
|
45
|
-
line_length(line_in_modifier_form(node))
|
|
47
|
+
length = line_length(line_in_modifier_form(node))
|
|
48
|
+
length += 2 if parenthesize?(node) && space_inside_parens?
|
|
49
|
+
|
|
50
|
+
length <= max_line_length
|
|
46
51
|
end
|
|
47
52
|
|
|
48
53
|
def line_in_modifier_form(node)
|
|
@@ -52,6 +57,14 @@ module RuboCop
|
|
|
52
57
|
"#{code_before}#{to_modifier_form(node)}#{code_after(node)}"
|
|
53
58
|
end
|
|
54
59
|
|
|
60
|
+
def space_inside_parens?
|
|
61
|
+
return false unless config.cop_enabled?('Layout/SpaceInsideParens')
|
|
62
|
+
|
|
63
|
+
style = config.for_cop('Layout/SpaceInsideParens')['EnforcedStyle']
|
|
64
|
+
|
|
65
|
+
SPACE_INSIDE_PARENS_STYLES.include?(style)
|
|
66
|
+
end
|
|
67
|
+
|
|
55
68
|
# Whether an existing line is acceptable to `Layout/LineLength`,
|
|
56
69
|
# exemptions (the cop disabled at that line, an allowed pattern, an
|
|
57
70
|
# allowed cop directive, an allowed URI) included. Only for judging
|
|
@@ -98,7 +111,7 @@ module RuboCop
|
|
|
98
111
|
|
|
99
112
|
# rubocop:disable-next Metrics/AbcSize
|
|
100
113
|
def if_body_source(if_body)
|
|
101
|
-
if
|
|
114
|
+
if unparenthesized_call_with_omitted_value?(if_body)
|
|
102
115
|
"#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
|
|
103
116
|
elsif (value = wrapped_value(if_body))
|
|
104
117
|
prefix = if_body.source_range.begin.join(value.source_range.begin).source
|
|
@@ -110,7 +123,8 @@ module RuboCop
|
|
|
110
123
|
end
|
|
111
124
|
end
|
|
112
125
|
|
|
113
|
-
def
|
|
126
|
+
def unparenthesized_call_with_omitted_value?(if_body)
|
|
127
|
+
return false if !if_body.call_type? || if_body.method?(:[]=) || if_body.parenthesized?
|
|
114
128
|
return false unless (last_argument = if_body.last_argument)
|
|
115
129
|
|
|
116
130
|
last_argument.hash_type? && last_argument.pairs.last&.value_omission?
|
|
@@ -163,7 +163,7 @@ module RuboCop
|
|
|
163
163
|
|
|
164
164
|
def put_comma(items, kind)
|
|
165
165
|
last_item = items.last
|
|
166
|
-
return if last_item.
|
|
166
|
+
return if last_item.type?(:block_pass, :forwarded_args)
|
|
167
167
|
|
|
168
168
|
range = autocorrect_range(last_item)
|
|
169
169
|
msg = format(MSG, command: 'Put a', unit: format(kind, article: 'a multiline'))
|
|
@@ -63,9 +63,10 @@ module RuboCop
|
|
|
63
63
|
(send nil? VISIBILITY_SCOPES def)
|
|
64
64
|
PATTERN
|
|
65
65
|
|
|
66
|
+
# A modifier applies to every symbol it is given, not only to a sole argument.
|
|
66
67
|
# @!method visibility_inline_on_method_name?(node, method_name:)
|
|
67
68
|
def_node_matcher :visibility_inline_on_method_name?, <<~PATTERN
|
|
68
|
-
(send nil? VISIBILITY_SCOPES (sym %method_name))
|
|
69
|
+
(send nil? VISIBILITY_SCOPES <(sym %method_name) ...>)
|
|
69
70
|
PATTERN
|
|
70
71
|
end
|
|
71
72
|
end
|
|
@@ -128,7 +128,7 @@ module RuboCop
|
|
|
128
128
|
if child_node.lvar_type?
|
|
129
129
|
parent_node = child_node.parent
|
|
130
130
|
if parent_node.respond_to?(:value_omission?) && parent_node.value_omission?
|
|
131
|
-
corrector.
|
|
131
|
+
corrector.replace(parent_node.loc.operator, ": #{preferred_name}")
|
|
132
132
|
else
|
|
133
133
|
corrector.replace(child_node, preferred_name)
|
|
134
134
|
end
|
|
@@ -132,10 +132,11 @@ module RuboCop
|
|
|
132
132
|
# private alias_method :qux, :foo
|
|
133
133
|
#
|
|
134
134
|
# end
|
|
135
|
-
class AccessModifierDeclarations < Base
|
|
135
|
+
class AccessModifierDeclarations < Base # rubocop:disable Metrics/ClassLength
|
|
136
136
|
extend AutoCorrector
|
|
137
137
|
|
|
138
138
|
include ConfigurableEnforcedStyle
|
|
139
|
+
include EndlessMethodBodyHelp
|
|
139
140
|
include RangeHelp
|
|
140
141
|
|
|
141
142
|
GROUP_STYLE_MESSAGE = [
|
|
@@ -169,6 +170,10 @@ module RuboCop
|
|
|
169
170
|
(send nil? :alias_method _ _))
|
|
170
171
|
PATTERN
|
|
171
172
|
|
|
173
|
+
def self.autocorrect_incompatible_with
|
|
174
|
+
[Style::EndlessMethod, Style::SingleLineMethods]
|
|
175
|
+
end
|
|
176
|
+
|
|
172
177
|
def on_send(node)
|
|
173
178
|
return if allowed?(node)
|
|
174
179
|
|
|
@@ -248,10 +253,33 @@ module RuboCop
|
|
|
248
253
|
|
|
249
254
|
access_modifier_is_inlined?(node) && !right_siblings_same_inline_method?(node)
|
|
250
255
|
else
|
|
251
|
-
access_modifier_is_not_inlined?(node) && select_grouped_def_nodes(node)
|
|
256
|
+
access_modifier_is_not_inlined?(node) && inlinable?(select_grouped_def_nodes(node))
|
|
252
257
|
end
|
|
253
258
|
end
|
|
254
259
|
|
|
260
|
+
def inlinable?(def_nodes)
|
|
261
|
+
return false if def_nodes.empty?
|
|
262
|
+
|
|
263
|
+
def_nodes.none? { |def_node| def_node.endless? && body_unsafe_to_inline?(def_node.body) }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def body_unsafe_to_inline?(body)
|
|
267
|
+
return true if body.each_node(:any_block).any? { |block| do_end_block?(block) }
|
|
268
|
+
|
|
269
|
+
target_ruby_version < 4.0 && command_body?(body)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def do_end_block?(block)
|
|
273
|
+
block.keywords? && !block.send_node.lambda_literal?
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def command_body?(body)
|
|
277
|
+
body = body.body while body.rescue_type?
|
|
278
|
+
return true if body.send_type? && body.prefix_not? && !body.parenthesized?
|
|
279
|
+
|
|
280
|
+
command_call?(body)
|
|
281
|
+
end
|
|
282
|
+
|
|
255
283
|
def correctable_group_offense?(node)
|
|
256
284
|
return false unless group_style?
|
|
257
285
|
return false if allowed?(node)
|