rubocop 1.86.0 → 1.86.1
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 +6 -2
- data/lib/rubocop/config.rb +13 -9
- data/lib/rubocop/config_loader_resolver.rb +2 -1
- data/lib/rubocop/cop/documentation.rb +2 -3
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +4 -2
- data/lib/rubocop/cop/layout/line_length.rb +5 -3
- data/lib/rubocop/cop/lint/duplicate_methods.rb +10 -5
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +17 -3
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +14 -2
- data/lib/rubocop/cop/style/guard_clause.rb +9 -6
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -5
- data/lib/rubocop/cop/style/module_member_existence_check.rb +1 -11
- data/lib/rubocop/cop/style/one_class_per_file.rb +24 -4
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -1
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +10 -0
- data/lib/rubocop/mcp/server.rb +2 -0
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e7e3463c6020de496396b13ecf80f691f532af83ac8f8627286f3887f07b11b2
|
|
4
|
+
data.tar.gz: 9e8c332d0f33ea078abcc71e0ddb7cd009497842a026dfdcae103a63fc909ba6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f0d7cff4de9dc7d8f04cdea8f8f28d6e45d5c0676a40ca67daa4e3fd6e3397363d2c2f4b368b5bcbb165d7478bdfb33c5352c49d2fd52896f8aa6d488e017cc
|
|
7
|
+
data.tar.gz: 357c3047ffea023a5c10162e4e2f2ee782796b5ca87d7c4413bde296d284c41362033ca9d997609ac6d9eceea7227b46e240150340a8a26cad8071bc5cce33c7
|
data/config/default.yml
CHANGED
|
@@ -4796,7 +4796,6 @@ Style/ModuleMemberExistenceCheck:
|
|
|
4796
4796
|
Description: 'Checks for usage of `Module` methods returning arrays that can be replaced with equivalent predicates.'
|
|
4797
4797
|
Enabled: pending
|
|
4798
4798
|
VersionAdded: '1.82'
|
|
4799
|
-
AllowedMethods: []
|
|
4800
4799
|
|
|
4801
4800
|
Style/MultilineBlockChain:
|
|
4802
4801
|
Description: 'Avoid multi-line chains of blocks.'
|
|
@@ -5112,7 +5111,11 @@ Style/OneClassPerFile:
|
|
|
5112
5111
|
Description: 'Checks that each source file defines at most one top-level class or module.'
|
|
5113
5112
|
Enabled: pending
|
|
5114
5113
|
VersionAdded: '1.85'
|
|
5114
|
+
VersionChanged: '1.86'
|
|
5115
5115
|
AllowedClasses: []
|
|
5116
|
+
Exclude:
|
|
5117
|
+
- 'spec/**/*'
|
|
5118
|
+
- 'test/**/*'
|
|
5116
5119
|
|
|
5117
5120
|
Style/OneLineConditional:
|
|
5118
5121
|
Description: >-
|
|
@@ -5557,9 +5560,10 @@ Style/RedundantStringEscape:
|
|
|
5557
5560
|
|
|
5558
5561
|
Style/RedundantStructKeywordInit:
|
|
5559
5562
|
Description: 'Checks for redundant `keyword_init` option for `Struct.new`.'
|
|
5560
|
-
Enabled:
|
|
5563
|
+
Enabled: false
|
|
5561
5564
|
SafeAutoCorrect: false
|
|
5562
5565
|
VersionAdded: '1.85'
|
|
5566
|
+
VersionChanged: '1.86'
|
|
5563
5567
|
|
|
5564
5568
|
Style/RegexpLiteral:
|
|
5565
5569
|
Description: 'Use / or %r around regular expressions.'
|
data/lib/rubocop/config.rb
CHANGED
|
@@ -217,6 +217,9 @@ module RuboCop
|
|
|
217
217
|
for_all_cops['StringLiteralsFrozenByDefault']
|
|
218
218
|
end
|
|
219
219
|
|
|
220
|
+
# Returns true if the file matches any include pattern. If a block is given, the block is called
|
|
221
|
+
# to determine if the pattern is relevant (true returned by the block) or should be skipped
|
|
222
|
+
# (false returned).
|
|
220
223
|
def file_to_include?(file)
|
|
221
224
|
relative_file_path = path_relative_to_config(file)
|
|
222
225
|
|
|
@@ -228,11 +231,9 @@ module RuboCop
|
|
|
228
231
|
absolute_file_path = File.expand_path(file)
|
|
229
232
|
|
|
230
233
|
patterns_to_include.any? do |pattern|
|
|
231
|
-
if block_given?
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
match_path?(pattern, relative_file_path) || match_path?(pattern, absolute_file_path)
|
|
235
|
-
end
|
|
234
|
+
next if block_given? && !yield(pattern)
|
|
235
|
+
|
|
236
|
+
match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path)
|
|
236
237
|
end
|
|
237
238
|
end
|
|
238
239
|
|
|
@@ -242,10 +243,7 @@ module RuboCop
|
|
|
242
243
|
# `bundler-console` conveys `Bundler::Console`).
|
|
243
244
|
return true if File.extname(file) == '.gemspec'
|
|
244
245
|
|
|
245
|
-
file_to_include?(file)
|
|
246
|
-
/[A-Z]/.match?(pattern.to_s) &&
|
|
247
|
-
(match_path?(pattern, relative_path) || match_path?(pattern, absolute_path))
|
|
248
|
-
end
|
|
246
|
+
file_to_include?(file) { |pattern| /[A-Z]/.match?(pattern.to_s) }
|
|
249
247
|
end
|
|
250
248
|
|
|
251
249
|
# Returns true if there's a chance that an Include pattern matches hidden
|
|
@@ -345,6 +343,12 @@ module RuboCop
|
|
|
345
343
|
|
|
346
344
|
private
|
|
347
345
|
|
|
346
|
+
def match_relative_or_absolute_path?(pattern, relative_file_path, absolute_file_path)
|
|
347
|
+
should_use_absolute_path = absolute?(pattern.to_s) || pattern.to_s.start_with?('..') ||
|
|
348
|
+
relative_file_path.start_with?('..')
|
|
349
|
+
match_path?(pattern, should_use_absolute_path ? absolute_file_path : relative_file_path)
|
|
350
|
+
end
|
|
351
|
+
|
|
348
352
|
# @return [Float, nil] The Rails version as a `major.minor` Float.
|
|
349
353
|
def target_rails_version_from_bundler_lock_file
|
|
350
354
|
@target_rails_version_from_bundler_lock_file ||= read_rails_version_from_bundler_lock_file
|
|
@@ -45,6 +45,7 @@ module RuboCop
|
|
|
45
45
|
base_config.each do |k, v|
|
|
46
46
|
next unless v.is_a?(Hash)
|
|
47
47
|
|
|
48
|
+
only_base_has_include = v.key?('Include') && !hash.dig(k, 'Include')
|
|
48
49
|
if hash.key?(k)
|
|
49
50
|
v = merge(v, hash[k],
|
|
50
51
|
cop_name: k, file: file, debug: debug,
|
|
@@ -52,7 +53,7 @@ module RuboCop
|
|
|
52
53
|
inherit_mode: determine_inherit_mode(hash, k))
|
|
53
54
|
end
|
|
54
55
|
hash[k] = v
|
|
55
|
-
fix_include_paths(base_config.loaded_path, hash, path, k, v) if
|
|
56
|
+
fix_include_paths(base_config.loaded_path, hash, path, k, v) if only_base_has_include
|
|
56
57
|
end
|
|
57
58
|
end
|
|
58
59
|
end
|
|
@@ -55,10 +55,9 @@ module RuboCop
|
|
|
55
55
|
|
|
56
56
|
# @api private
|
|
57
57
|
def builtin?(cop_class)
|
|
58
|
-
|
|
59
|
-
return false unless (m = cop_class.instance_methods(false).first)
|
|
58
|
+
return false unless (name = cop_class.name)
|
|
60
59
|
|
|
61
|
-
path, _line =
|
|
60
|
+
path, _line = Module.const_source_location(name)
|
|
62
61
|
path.start_with?(__dir__)
|
|
63
62
|
end
|
|
64
63
|
end
|
|
@@ -111,7 +111,7 @@ module RuboCop
|
|
|
111
111
|
def contains_guard_clause?(node)
|
|
112
112
|
return false unless (branch = node.if_branch)
|
|
113
113
|
|
|
114
|
-
guard_clause_branch?(branch)
|
|
114
|
+
branch.guard_clause? || guard_clause_branch?(branch)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def next_line_empty_or_allowed_directive_comment?(line)
|
|
@@ -123,6 +123,7 @@ module RuboCop
|
|
|
123
123
|
AlignmentCorrector.align_end(corrector, processed_source, node, alignment_node(node))
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
126
127
|
def check_assignment(node, rhs)
|
|
127
128
|
# If there are method calls chained to the right hand side of the
|
|
128
129
|
# assignment, we let rhs be the receiver of those method calls before
|
|
@@ -131,13 +132,14 @@ module RuboCop
|
|
|
131
132
|
|
|
132
133
|
# If `rhs` is a `begin` node or a logical operator,
|
|
133
134
|
# unwrap to find the leading conditional.
|
|
134
|
-
rhs = rhs.child_nodes.first while rhs
|
|
135
|
+
rhs = rhs.child_nodes.first while rhs&.type?(:begin, :or, :and)
|
|
135
136
|
|
|
136
|
-
return unless rhs
|
|
137
|
+
return unless rhs&.conditional?
|
|
137
138
|
return if rhs.if_type? && rhs.ternary?
|
|
138
139
|
|
|
139
140
|
check_asgn_alignment(node, rhs)
|
|
140
141
|
end
|
|
142
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
141
143
|
|
|
142
144
|
def check_asgn_alignment(outer_node, inner_node)
|
|
143
145
|
align_with = {
|
|
@@ -406,9 +406,11 @@ module RuboCop
|
|
|
406
406
|
end
|
|
407
407
|
|
|
408
408
|
def string_delimiter(node)
|
|
409
|
-
delimiter = node.loc
|
|
410
|
-
|
|
411
|
-
|
|
409
|
+
delimiter = if node.loc?(:begin)
|
|
410
|
+
node.loc.begin
|
|
411
|
+
elsif node.parent&.dstr_type? && node.parent.loc?(:begin)
|
|
412
|
+
node.parent.loc.begin
|
|
413
|
+
end&.source
|
|
412
414
|
|
|
413
415
|
delimiter if %w[' "].include?(delimiter)
|
|
414
416
|
end
|
|
@@ -308,7 +308,7 @@ module RuboCop
|
|
|
308
308
|
def anonymous_class_block(node)
|
|
309
309
|
first_block = node.each_ancestor(:block).first
|
|
310
310
|
return unless class_or_module_new_block?(first_block)
|
|
311
|
-
return if first_block.parent&.type?(:lvasgn
|
|
311
|
+
return if first_block.parent&.type?(:lvasgn)
|
|
312
312
|
return if node.each_ancestor(:sclass).any? { |s| !s.children.first.self_type? }
|
|
313
313
|
|
|
314
314
|
first_block
|
|
@@ -316,15 +316,20 @@ module RuboCop
|
|
|
316
316
|
|
|
317
317
|
def anon_block_scope_id(anon_block)
|
|
318
318
|
parent = anon_block.parent
|
|
319
|
-
return unless parent&.
|
|
319
|
+
return unless parent&.type?(:any_block, :begin, :call, :casgn, :any_def)
|
|
320
320
|
|
|
321
|
-
if parent
|
|
322
|
-
"#{
|
|
323
|
-
|
|
321
|
+
if (receiver = named_receiver(parent))
|
|
322
|
+
"#{receiver.source}.#{parent.method_name}"
|
|
323
|
+
elsif !parent.begin_type? || parent.parent&.any_block_type?
|
|
324
324
|
source_location(anon_block)
|
|
325
325
|
end
|
|
326
326
|
end
|
|
327
327
|
|
|
328
|
+
def named_receiver(node)
|
|
329
|
+
receiver = node.receiver
|
|
330
|
+
receiver unless class_or_module_new_block?(receiver)
|
|
331
|
+
end
|
|
332
|
+
|
|
328
333
|
def found_sclass_method(node, name)
|
|
329
334
|
singleton_ancestor = node.each_ancestor.find(&:sclass_type?)
|
|
330
335
|
return unless singleton_ancestor
|
|
@@ -26,7 +26,31 @@ module RuboCop
|
|
|
26
26
|
"#{diagnostic.message}\n(Using Ruby #{ruby_version} parser; " \
|
|
27
27
|
'configure using `TargetRubyVersion` parameter, under `AllCops`)'
|
|
28
28
|
end
|
|
29
|
-
|
|
29
|
+
location = diagnostic_location(diagnostic.location)
|
|
30
|
+
add_offense(location, message: message, severity: diagnostic.level)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Expand zero-length diagnostic ranges so that editors and formatters
|
|
34
|
+
# can display them. This typically occurs when the parser reports
|
|
35
|
+
# `unexpected token $end` at EOF.
|
|
36
|
+
def diagnostic_location(location)
|
|
37
|
+
return location if location.size.positive?
|
|
38
|
+
|
|
39
|
+
source_buffer = location.source_buffer
|
|
40
|
+
if location.end_pos < source_buffer.source.size
|
|
41
|
+
location.resize(1)
|
|
42
|
+
elsif location.begin_pos.positive?
|
|
43
|
+
location.adjust(begin_pos: -1)
|
|
44
|
+
else
|
|
45
|
+
location
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Override to skip multiline_ranges check which requires AST.
|
|
50
|
+
# Syntax errors mean the AST is nil, so we go directly to
|
|
51
|
+
# the EOL comment insertion path.
|
|
52
|
+
def disable_offense(offense_range)
|
|
53
|
+
disable_offense_with_eol_or_surround_comment(offense_range)
|
|
30
54
|
end
|
|
31
55
|
|
|
32
56
|
def add_offense_from_error(error)
|
|
@@ -95,10 +95,20 @@ module RuboCop
|
|
|
95
95
|
return unless variable.method_argument?
|
|
96
96
|
return if variable.keyword_argument? && cop_config['AllowUnusedKeywordArguments']
|
|
97
97
|
return if ignored_method?(variable.scope.node.body)
|
|
98
|
+
return if block_argument_with_yield?(variable)
|
|
98
99
|
|
|
99
100
|
super
|
|
100
101
|
end
|
|
101
102
|
|
|
103
|
+
def block_argument_with_yield?(variable)
|
|
104
|
+
return false unless variable.declaration_node.blockarg_type?
|
|
105
|
+
|
|
106
|
+
method_body = variable.scope.node.body
|
|
107
|
+
return false unless method_body
|
|
108
|
+
|
|
109
|
+
method_body.yield_type? || method_body.each_descendant(:yield).any?
|
|
110
|
+
end
|
|
111
|
+
|
|
102
112
|
def ignored_method?(body)
|
|
103
113
|
(cop_config['IgnoreEmptyMethods'] && body.nil?) ||
|
|
104
114
|
(cop_config['IgnoreNotImplementedMethods'] && not_implemented?(body))
|
|
@@ -84,14 +84,13 @@ module RuboCop
|
|
|
84
84
|
|
|
85
85
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
86
86
|
def sole_condition_of_parent_if?(node)
|
|
87
|
+
child = node
|
|
87
88
|
parent = node.parent
|
|
88
89
|
|
|
89
90
|
while parent
|
|
90
91
|
if parent.if_type?
|
|
91
92
|
condition = parent.condition
|
|
92
|
-
|
|
93
|
-
return true
|
|
94
|
-
end
|
|
93
|
+
return true if !child.equal?(condition) && non_nil_condition?(condition, node)
|
|
95
94
|
|
|
96
95
|
parent = find_top_if(parent) if parent.elsif?
|
|
97
96
|
elsif else_branch?(parent)
|
|
@@ -99,6 +98,7 @@ module RuboCop
|
|
|
99
98
|
parent = parent.parent
|
|
100
99
|
end
|
|
101
100
|
|
|
101
|
+
child = parent
|
|
102
102
|
parent = parent&.parent
|
|
103
103
|
end
|
|
104
104
|
|
|
@@ -106,6 +106,12 @@ module RuboCop
|
|
|
106
106
|
end
|
|
107
107
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
108
108
|
|
|
109
|
+
def non_nil_condition?(condition, node)
|
|
110
|
+
return true if condition == node
|
|
111
|
+
|
|
112
|
+
condition.csend_type? && csend_root_receiver(condition) == node
|
|
113
|
+
end
|
|
114
|
+
|
|
109
115
|
def else_branch?(node)
|
|
110
116
|
node.parent&.if_type? && node.parent.else_branch == node
|
|
111
117
|
end
|
|
@@ -115,6 +121,14 @@ module RuboCop
|
|
|
115
121
|
|
|
116
122
|
node
|
|
117
123
|
end
|
|
124
|
+
|
|
125
|
+
def csend_root_receiver(node)
|
|
126
|
+
return unless (receiver = node.receiver)
|
|
127
|
+
|
|
128
|
+
receiver = receiver.receiver while receiver.call_type? && receiver.receiver
|
|
129
|
+
|
|
130
|
+
receiver
|
|
131
|
+
end
|
|
118
132
|
end
|
|
119
133
|
end
|
|
120
134
|
end
|
|
@@ -348,8 +348,20 @@ module RuboCop
|
|
|
348
348
|
|
|
349
349
|
def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
|
|
350
350
|
def_node = begin_node.children[begin_node.children.index(modifier_node) + 1]
|
|
351
|
-
range
|
|
352
|
-
|
|
351
|
+
# Stop the removal range at the first comment that precedes the def, if
|
|
352
|
+
# any exist. Without this, comments between the modifier and the def are
|
|
353
|
+
# dropped because they fall inside the removed range.
|
|
354
|
+
end_pos = first_comment_or_node_start(def_node)
|
|
355
|
+
corrector.remove(modifier_node.source_range.begin.join(end_pos))
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def first_comment_or_node_start(node)
|
|
359
|
+
preceding = processed_source.ast_with_comments[node].select do |comment|
|
|
360
|
+
comment.loc.line < node.loc.line
|
|
361
|
+
end
|
|
362
|
+
return node.source_range.begin if preceding.empty?
|
|
363
|
+
|
|
364
|
+
preceding.first.source_range.begin
|
|
353
365
|
end
|
|
354
366
|
|
|
355
367
|
def def_source(node, def_nodes)
|
|
@@ -224,15 +224,18 @@ module RuboCop
|
|
|
224
224
|
end
|
|
225
225
|
|
|
226
226
|
def find_heredoc_argument(node)
|
|
227
|
-
return unless node
|
|
227
|
+
return unless node
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
node = node.children.first while node.begin_type?
|
|
230
|
+
return node if heredoc?(node)
|
|
231
|
+
return unless node.call_type?
|
|
230
232
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
find_heredoc_argument(last_arg)
|
|
233
|
+
node.arguments.reverse_each do |argument|
|
|
234
|
+
heredoc_argument = find_heredoc_argument(argument)
|
|
235
|
+
return heredoc_argument if heredoc_argument
|
|
235
236
|
end
|
|
237
|
+
|
|
238
|
+
find_heredoc_argument(node.receiver)
|
|
236
239
|
end
|
|
237
240
|
|
|
238
241
|
def autocorrect_heredoc_argument(corrector, node, heredoc_node, leave_branch, guard)
|
|
@@ -85,7 +85,7 @@ module RuboCop
|
|
|
85
85
|
private
|
|
86
86
|
|
|
87
87
|
def autocorrect(corrector, node)
|
|
88
|
-
if then?
|
|
88
|
+
if node.then?
|
|
89
89
|
# If the nested `if` is a then node, correct it first,
|
|
90
90
|
# then the next pass will use `correct_to_elsif_from_if_inside_else_form`
|
|
91
91
|
IfThenCorrector.new(node, indentation: 0).call(corrector)
|
|
@@ -124,10 +124,6 @@ module RuboCop
|
|
|
124
124
|
corrector.remove(range_by_whole_lines(find_end_range(node), include_final_newline: true))
|
|
125
125
|
end
|
|
126
126
|
|
|
127
|
-
def then?(node)
|
|
128
|
-
node.loc.begin&.source == 'then'
|
|
129
|
-
end
|
|
130
|
-
|
|
131
127
|
def find_end_range(node)
|
|
132
128
|
end_range = node.loc.end
|
|
133
129
|
return end_range if end_range
|
|
@@ -32,7 +32,6 @@ module RuboCop
|
|
|
32
32
|
# Array.private_instance_methods.include?(:foo)
|
|
33
33
|
# Array.protected_instance_methods.include?(:foo)
|
|
34
34
|
# Array.public_instance_methods.include?(:foo)
|
|
35
|
-
# Array.included_modules.include?(:foo)
|
|
36
35
|
#
|
|
37
36
|
# # good
|
|
38
37
|
# Array.class_variable_defined?(:foo)
|
|
@@ -40,15 +39,8 @@ module RuboCop
|
|
|
40
39
|
# Array.private_method_defined?(:foo)
|
|
41
40
|
# Array.protected_method_defined?(:foo)
|
|
42
41
|
# Array.public_method_defined?(:foo)
|
|
43
|
-
# Array.include?(:foo)
|
|
44
|
-
#
|
|
45
|
-
# @example AllowedMethods: [included_modules]
|
|
46
|
-
#
|
|
47
|
-
# # good
|
|
48
|
-
# Array.included_modules.include?(:foo)
|
|
49
42
|
#
|
|
50
43
|
class ModuleMemberExistenceCheck < Base
|
|
51
|
-
include AllowedMethods
|
|
52
44
|
extend AutoCorrector
|
|
53
45
|
|
|
54
46
|
MSG = 'Use `%<replacement>s` instead.'
|
|
@@ -64,14 +56,13 @@ module RuboCop
|
|
|
64
56
|
METHOD_REPLACEMENTS = {
|
|
65
57
|
class_variables: :class_variable_defined?,
|
|
66
58
|
constants: :const_defined?,
|
|
67
|
-
included_modules: :include?,
|
|
68
59
|
instance_methods: :method_defined?,
|
|
69
60
|
private_instance_methods: :private_method_defined?,
|
|
70
61
|
protected_instance_methods: :protected_method_defined?,
|
|
71
62
|
public_instance_methods: :public_method_defined?
|
|
72
63
|
}.freeze
|
|
73
64
|
|
|
74
|
-
METHODS_WITHOUT_INHERIT_PARAM = Set[:class_variables
|
|
65
|
+
METHODS_WITHOUT_INHERIT_PARAM = Set[:class_variables].freeze
|
|
75
66
|
METHODS_WITH_INHERIT_PARAM =
|
|
76
67
|
(METHOD_REPLACEMENTS.keys.to_set - METHODS_WITHOUT_INHERIT_PARAM).freeze
|
|
77
68
|
|
|
@@ -81,7 +72,6 @@ module RuboCop
|
|
|
81
72
|
return unless (parent = node.parent)
|
|
82
73
|
return unless module_member_inclusion?(parent)
|
|
83
74
|
return unless simple_method_argument?(node) && simple_method_argument?(parent)
|
|
84
|
-
return if allowed_method?(node.method_name)
|
|
85
75
|
|
|
86
76
|
offense_range = node.location.selector.join(parent.source_range.end)
|
|
87
77
|
replacement = replacement_for(node, parent)
|
|
@@ -13,30 +13,50 @@ module RuboCop
|
|
|
13
13
|
# classes that logically belong with the main class.
|
|
14
14
|
#
|
|
15
15
|
# @example
|
|
16
|
-
# # bad
|
|
16
|
+
# # bad - Multiple top-level classes
|
|
17
17
|
# class Foo
|
|
18
18
|
# end
|
|
19
19
|
#
|
|
20
20
|
# class Bar
|
|
21
21
|
# end
|
|
22
22
|
#
|
|
23
|
-
# # bad
|
|
23
|
+
# # bad - Multiple top-level modules
|
|
24
|
+
# module Foo
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# module Bar
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# # bad - A top-level class and a top-level module
|
|
24
31
|
# class Foo
|
|
25
32
|
# end
|
|
26
33
|
#
|
|
27
34
|
# module Bar
|
|
28
35
|
# end
|
|
29
36
|
#
|
|
30
|
-
# # good
|
|
37
|
+
# # good - A single top-level class
|
|
31
38
|
# class Foo
|
|
32
39
|
# end
|
|
33
40
|
#
|
|
34
|
-
# # good
|
|
41
|
+
# # good - A single top-level module
|
|
42
|
+
# module Foo
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# # good - Nested classes within a single top-level class
|
|
35
46
|
# class Foo
|
|
36
47
|
# class Bar
|
|
37
48
|
# end
|
|
38
49
|
# end
|
|
39
50
|
#
|
|
51
|
+
# # good - Multiple classes within a single top-level module
|
|
52
|
+
# module Foo
|
|
53
|
+
# class Bar
|
|
54
|
+
# end
|
|
55
|
+
#
|
|
56
|
+
# class Baz
|
|
57
|
+
# end
|
|
58
|
+
# end
|
|
59
|
+
#
|
|
40
60
|
# @example AllowedClasses: ['AllowedClass']
|
|
41
61
|
# # good
|
|
42
62
|
# class Foo
|
|
@@ -82,6 +82,7 @@ module RuboCop
|
|
|
82
82
|
tIDENTIFIER kBREAK kNEXT kRETURN kSUPER kYIELD
|
|
83
83
|
].freeze
|
|
84
84
|
ARITHMETIC_OPERATOR_TOKENS = %i[tDIVIDE tDSTAR tMINUS tPERCENT tPLUS tSTAR2].freeze
|
|
85
|
+
STRING_LITERAL_BEGIN_TOKENS = %i[tSTRING_BEG tXSTRING_BEG tREGEXP_BEG tSYMBEG].freeze
|
|
85
86
|
|
|
86
87
|
def on_new_investigation
|
|
87
88
|
return unless processed_source.ast
|
|
@@ -105,6 +106,7 @@ module RuboCop
|
|
|
105
106
|
string_concatenation?(range.source_line) ||
|
|
106
107
|
start_with_arithmetic_operator?(range) ||
|
|
107
108
|
inside_string_literal_or_method_with_argument?(range) ||
|
|
109
|
+
inside_string_literal_with_interpolation?(range) ||
|
|
108
110
|
leading_dot_method_chain_with_blank_line?(range)
|
|
109
111
|
end
|
|
110
112
|
|
|
@@ -132,6 +134,20 @@ module RuboCop
|
|
|
132
134
|
end
|
|
133
135
|
end
|
|
134
136
|
|
|
137
|
+
def inside_string_literal_with_interpolation?(range)
|
|
138
|
+
string_depth = 0
|
|
139
|
+
processed_source.tokens.each do |token|
|
|
140
|
+
break if token.pos.begin_pos >= range.begin_pos
|
|
141
|
+
|
|
142
|
+
if STRING_LITERAL_BEGIN_TOKENS.include?(token.type)
|
|
143
|
+
string_depth += 1
|
|
144
|
+
elsif token.type == :tSTRING_END
|
|
145
|
+
string_depth -= 1
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
string_depth.positive?
|
|
149
|
+
end
|
|
150
|
+
|
|
135
151
|
def leading_dot_method_chain_with_blank_line?(range)
|
|
136
152
|
return false unless range.source_line.strip.start_with?('.', '&.')
|
|
137
153
|
|
|
@@ -270,14 +270,17 @@ module RuboCop
|
|
|
270
270
|
end
|
|
271
271
|
end
|
|
272
272
|
|
|
273
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
273
274
|
def body_range?(begin_node, node)
|
|
275
|
+
return false if begin_node.chained?
|
|
274
276
|
return false unless node.range_type?
|
|
275
277
|
return false unless (parent = begin_node.parent)
|
|
276
|
-
return false
|
|
278
|
+
return false unless parent.begin_type?
|
|
277
279
|
|
|
278
280
|
(node.begin.nil? && begin_node == parent.children.first) ||
|
|
279
281
|
(node.end.nil? && begin_node == parent.children.last)
|
|
280
282
|
end
|
|
283
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
281
284
|
|
|
282
285
|
def disallowed_one_line_pattern_matching?(begin_node, node)
|
|
283
286
|
if (parent = begin_node.parent)
|
|
@@ -9,6 +9,16 @@ module RuboCop
|
|
|
9
9
|
# Therefore, this cop detects and autocorrects redundant `keyword_init: nil`
|
|
10
10
|
# and `keyword_init: true` in `Struct.new`.
|
|
11
11
|
#
|
|
12
|
+
# This cop is disabled by default because `keyword_init: true` is not purely
|
|
13
|
+
# redundant. It changes behavior in the following ways:
|
|
14
|
+
#
|
|
15
|
+
# - `Struct#keyword_init?` returns `true` instead of `nil`.
|
|
16
|
+
# - A `Struct` with `keyword_init: true` accepts a `Hash` argument and
|
|
17
|
+
# expands it as keyword arguments, whereas without it the `Hash` is
|
|
18
|
+
# treated as a positional argument.
|
|
19
|
+
# - `keyword_init: true` raises an `ArgumentError` for positional arguments,
|
|
20
|
+
# enforcing keyword-only initialization.
|
|
21
|
+
#
|
|
12
22
|
# @safety
|
|
13
23
|
# This autocorrect is unsafe because when the value of `keyword_init` changes
|
|
14
24
|
# from `true` to `nil`, the return value of `Struct#keyword_init?` changes.
|
data/lib/rubocop/mcp/server.rb
CHANGED
|
@@ -190,6 +190,8 @@ module RuboCop
|
|
|
190
190
|
result = yield(path, source_code, safety)
|
|
191
191
|
|
|
192
192
|
::MCP::Tool::Response.new([{ type: 'text', text: result }])
|
|
193
|
+
rescue RuboCop::Error => e
|
|
194
|
+
::MCP::Tool::Response.new([{ type: 'text', text: e.message }], error: true)
|
|
193
195
|
end
|
|
194
196
|
end
|
|
195
197
|
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
|
|
@@ -6,6 +6,12 @@ require 'tempfile'
|
|
|
6
6
|
module CopHelper
|
|
7
7
|
extend RSpec::SharedContext
|
|
8
8
|
|
|
9
|
+
@integrated_plugins = false
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
attr_accessor :integrated_plugins
|
|
13
|
+
end
|
|
14
|
+
|
|
9
15
|
let(:ruby_version) do
|
|
10
16
|
# The minimum version Prism can parse is 3.3.
|
|
11
17
|
ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : RuboCop::TargetRuby::DEFAULT_VERSION
|
|
@@ -18,11 +24,13 @@ module CopHelper
|
|
|
18
24
|
|
|
19
25
|
before(:all) do
|
|
20
26
|
next if ENV['RUBOCOP_CORE_DEVELOPMENT']
|
|
27
|
+
next if CopHelper.integrated_plugins
|
|
21
28
|
|
|
22
29
|
plugins = Gem.loaded_specs.filter_map do |feature_name, feature_specification|
|
|
23
30
|
feature_name if feature_specification.metadata['default_lint_roller_plugin']
|
|
24
31
|
end
|
|
25
32
|
RuboCop::Plugin.integrate_plugins(RuboCop::Config.new, plugins)
|
|
33
|
+
CopHelper.integrated_plugins = true
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
def inspect_source(source, file = nil)
|
data/lib/rubocop/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.86.
|
|
4
|
+
version: 1.86.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bozhidar Batsov
|
|
@@ -57,14 +57,14 @@ dependencies:
|
|
|
57
57
|
name: parallel
|
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
|
59
59
|
requirements:
|
|
60
|
-
- - "
|
|
60
|
+
- - ">="
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
62
|
version: '1.10'
|
|
63
63
|
type: :runtime
|
|
64
64
|
prerelease: false
|
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
|
66
66
|
requirements:
|
|
67
|
-
- - "
|
|
67
|
+
- - ">="
|
|
68
68
|
- !ruby/object:Gem::Version
|
|
69
69
|
version: '1.10'
|
|
70
70
|
- !ruby/object:Gem::Dependency
|
|
@@ -1114,7 +1114,7 @@ licenses:
|
|
|
1114
1114
|
- MIT
|
|
1115
1115
|
metadata:
|
|
1116
1116
|
homepage_uri: https://rubocop.org/
|
|
1117
|
-
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.86.
|
|
1117
|
+
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.86.1
|
|
1118
1118
|
source_code_uri: https://github.com/rubocop/rubocop/
|
|
1119
1119
|
documentation_uri: https://docs.rubocop.org/rubocop/1.86/
|
|
1120
1120
|
bug_tracker_uri: https://github.com/rubocop/rubocop/issues
|