rubocop 1.78.0 → 1.79.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/README.md +1 -3
- data/config/default.yml +32 -19
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +12 -0
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/naming/method_name.rb +40 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +4 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
- data/lib/rubocop/cop/style/array_intersect.rb +53 -23
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -0
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +2 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +30 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +18 -7
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/lsp/routes.rb +4 -4
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +2 -0
- metadata +12 -7
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'tsort'
|
4
|
-
|
5
3
|
module RuboCop
|
6
4
|
module Cop
|
7
5
|
module Style
|
@@ -29,6 +27,8 @@ module RuboCop
|
|
29
27
|
MSG = 'Do not use parallel assignment.'
|
30
28
|
|
31
29
|
def on_masgn(node) # rubocop:disable Metrics/AbcSize
|
30
|
+
return if part_of_ignored_node?(node)
|
31
|
+
|
32
32
|
rhs = node.rhs
|
33
33
|
rhs = rhs.body if rhs.rescue_type?
|
34
34
|
rhs_elements = Array(rhs).compact # edge case for one constant
|
@@ -41,6 +41,7 @@ module RuboCop
|
|
41
41
|
add_offense(range) do |corrector|
|
42
42
|
autocorrect(corrector, node, rhs)
|
43
43
|
end
|
44
|
+
ignore_node(node)
|
44
45
|
end
|
45
46
|
|
46
47
|
private
|
@@ -91,15 +92,9 @@ module RuboCop
|
|
91
92
|
def find_valid_order(left_elements, right_elements)
|
92
93
|
# arrange left_elements in an order such that no corresponding right
|
93
94
|
# element refers to a left element earlier in the sequence
|
94
|
-
# this can be done using an algorithm called a "topological sort"
|
95
|
-
# fortunately for us, Ruby's stdlib contains an implementation
|
96
95
|
assignments = left_elements.zip(right_elements)
|
97
96
|
|
98
|
-
|
99
|
-
AssignmentSorter.new(assignments).tsort
|
100
|
-
rescue TSort::Cyclic
|
101
|
-
nil
|
102
|
-
end
|
97
|
+
AssignmentSorter.new(assignments).tsort
|
103
98
|
end
|
104
99
|
|
105
100
|
# Converts (send nil :something) nodes to (send (:self) :something).
|
@@ -114,10 +109,9 @@ module RuboCop
|
|
114
109
|
# @!method implicit_self_getter?(node)
|
115
110
|
def_node_matcher :implicit_self_getter?, '(send nil? $_)'
|
116
111
|
|
117
|
-
#
|
118
|
-
#
|
112
|
+
# Topologically sorts the assignments with Kahn's algorithm.
|
113
|
+
# https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
|
119
114
|
class AssignmentSorter
|
120
|
-
include TSort
|
121
115
|
extend RuboCop::NodePattern::Macros
|
122
116
|
|
123
117
|
# @!method var_name(node)
|
@@ -133,21 +127,39 @@ module RuboCop
|
|
133
127
|
@assignments = assignments
|
134
128
|
end
|
135
129
|
|
136
|
-
def
|
137
|
-
@assignments.
|
130
|
+
def tsort
|
131
|
+
dependencies = @assignments.to_h do |assignment|
|
132
|
+
[assignment, dependencies_for_assignment(assignment)]
|
133
|
+
end
|
134
|
+
result = []
|
135
|
+
|
136
|
+
while (matched_node, = dependencies.find { |_node, edges| edges.empty? })
|
137
|
+
dependencies.delete(matched_node)
|
138
|
+
result.push(matched_node)
|
139
|
+
|
140
|
+
dependencies.each do |node, edges|
|
141
|
+
dependencies[node].delete(matched_node) if edges.include?(matched_node)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
# Cyclic dependency
|
145
|
+
return nil if dependencies.any?
|
146
|
+
|
147
|
+
result
|
138
148
|
end
|
139
149
|
|
140
|
-
|
141
|
-
|
142
|
-
|
150
|
+
# Returns all the assignments which must come after `assignment`
|
151
|
+
# (due to dependencies on the previous value of the assigned var)
|
152
|
+
def dependencies_for_assignment(assignment)
|
143
153
|
my_lhs, _my_rhs = *assignment
|
144
154
|
|
145
|
-
@assignments.
|
146
|
-
|
155
|
+
@assignments.filter_map do |other|
|
156
|
+
# Exclude self, there are no dependencies in cases such as `a, b = a, b`.
|
157
|
+
next if other == assignment
|
147
158
|
|
159
|
+
_other_lhs, other_rhs = *other
|
148
160
|
next unless dependency?(my_lhs, other_rhs)
|
149
161
|
|
150
|
-
|
162
|
+
other
|
151
163
|
end
|
152
164
|
end
|
153
165
|
|
@@ -169,6 +169,7 @@ module RuboCop
|
|
169
169
|
end
|
170
170
|
return 'an interpolated expression' if interpolation?(begin_node)
|
171
171
|
return 'a method argument' if argument_of_parenthesized_method_call?(begin_node, node)
|
172
|
+
return 'a one-line rescue' if oneline_rescue_parentheses_required?(begin_node, node)
|
172
173
|
|
173
174
|
return if begin_node.chained?
|
174
175
|
|
@@ -200,6 +201,14 @@ module RuboCop
|
|
200
201
|
parent.call_type? && parent.parenthesized? && parent.receiver != begin_node
|
201
202
|
end
|
202
203
|
|
204
|
+
def oneline_rescue_parentheses_required?(begin_node, node)
|
205
|
+
return false unless node.rescue_type?
|
206
|
+
return false unless (parent = begin_node.parent)
|
207
|
+
return false if parent.if_type? && parent.ternary?
|
208
|
+
|
209
|
+
!parent.type?(:call, :array, :pair)
|
210
|
+
end
|
211
|
+
|
203
212
|
def method_call_parentheses_required?(node)
|
204
213
|
return false unless node.call_type?
|
205
214
|
|
@@ -65,7 +65,7 @@ module RuboCop
|
|
65
65
|
return false if target_ruby_version < 3.0
|
66
66
|
return false if disallow_endless_method_style?
|
67
67
|
return false unless body_node
|
68
|
-
return false if body_node.parent.assignment_method? ||
|
68
|
+
return false if body_node.basic_conditional? || body_node.parent.assignment_method? ||
|
69
69
|
NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
|
70
70
|
|
71
71
|
!body_node.type?(:begin, :kwbegin)
|
@@ -86,10 +86,10 @@ module RuboCop
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def correct_to_endless(corrector, node)
|
89
|
-
|
89
|
+
receiver = "#{node.receiver.source}." if node.receiver
|
90
90
|
arguments = node.arguments.any? ? node.arguments.source : '()'
|
91
91
|
body_source = method_body_source(node.body)
|
92
|
-
replacement = "def #{
|
92
|
+
replacement = "def #{receiver}#{node.method_name}#{arguments} = #{body_source}"
|
93
93
|
|
94
94
|
corrector.replace(node, replacement)
|
95
95
|
end
|
@@ -175,6 +175,8 @@ module RuboCop
|
|
175
175
|
|
176
176
|
if parenthesize_method?(condition)
|
177
177
|
parenthesized_method_arguments(condition)
|
178
|
+
elsif condition.and_type?
|
179
|
+
parenthesized_and(condition)
|
178
180
|
else
|
179
181
|
"(#{condition.source})"
|
180
182
|
end
|
@@ -186,12 +188,19 @@ module RuboCop
|
|
186
188
|
end
|
187
189
|
|
188
190
|
def add_parentheses?(node)
|
189
|
-
return true if node.assignment? ||
|
191
|
+
return true if node.assignment? || node.or_type?
|
192
|
+
return true if assignment_in_and?(node)
|
190
193
|
return false unless node.call_type?
|
191
194
|
|
192
195
|
(node.arguments.any? && !node.parenthesized?) || node.prefix_not?
|
193
196
|
end
|
194
197
|
|
198
|
+
def assignment_in_and?(node)
|
199
|
+
return false unless node.and_type?
|
200
|
+
|
201
|
+
node.each_descendant.any?(&:assignment?)
|
202
|
+
end
|
203
|
+
|
195
204
|
def parenthesized_method_arguments(node)
|
196
205
|
method_call = node.source_range.begin.join(node.loc.selector.end).source
|
197
206
|
arguments = node.first_argument.source_range.begin.join(node.source_range.end).source
|
@@ -199,6 +208,26 @@ module RuboCop
|
|
199
208
|
"#{method_call}(#{arguments})"
|
200
209
|
end
|
201
210
|
|
211
|
+
def parenthesized_and(node)
|
212
|
+
# We only need to add parentheses around the last clause if it's an assignment,
|
213
|
+
# because other clauses will be unchanged by merging conditionals.
|
214
|
+
lhs = node.lhs.source
|
215
|
+
rhs = parenthesized_and_clause(node.rhs)
|
216
|
+
operator = range_with_surrounding_space(node.loc.operator, whitespace: true).source
|
217
|
+
|
218
|
+
"#{lhs}#{operator}#{rhs}"
|
219
|
+
end
|
220
|
+
|
221
|
+
def parenthesized_and_clause(node)
|
222
|
+
if node.and_type?
|
223
|
+
parenthesized_and(node)
|
224
|
+
elsif node.assignment?
|
225
|
+
"(#{node.source})"
|
226
|
+
else
|
227
|
+
node.source
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
202
231
|
def allow_modifier?
|
203
232
|
cop_config['AllowModifier']
|
204
233
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for parentheses around stabby lambda arguments.
|
7
7
|
# There are two different styles. Defaults to `require_parentheses`.
|
8
8
|
#
|
9
9
|
# @example EnforcedStyle: require_parentheses (default)
|
@@ -296,7 +296,7 @@ module RuboCop
|
|
296
296
|
variable_table.accessible_variables.each { |variable| variable.reference!(node) }
|
297
297
|
end
|
298
298
|
|
299
|
-
# Mark
|
299
|
+
# Mark last assignments which are referenced in the same loop
|
300
300
|
# as referenced by ignoring AST order since they would be referenced
|
301
301
|
# in next iteration.
|
302
302
|
def mark_assignments_as_referenced_in_loop(node)
|
@@ -308,13 +308,12 @@ module RuboCop
|
|
308
308
|
# would be skipped here.
|
309
309
|
next unless variable
|
310
310
|
|
311
|
-
variable.assignments.
|
312
|
-
|
313
|
-
assignment_node.equal?(assignment.node)
|
314
|
-
end
|
315
|
-
|
316
|
-
assignment.reference!(node)
|
311
|
+
loop_assignments = variable.assignments.select do |assignment|
|
312
|
+
assignment_nodes_in_loop.include?(assignment.node)
|
317
313
|
end
|
314
|
+
next unless loop_assignments.any?
|
315
|
+
|
316
|
+
reference_assignments(loop_assignments, node)
|
318
317
|
end
|
319
318
|
end
|
320
319
|
|
@@ -354,6 +353,18 @@ module RuboCop
|
|
354
353
|
end
|
355
354
|
end
|
356
355
|
|
356
|
+
def reference_assignments(loop_assignments, node)
|
357
|
+
# If inside a branching statement, mark all as referenced.
|
358
|
+
# Otherwise, mark only the last assignment as referenced.
|
359
|
+
# Note that `rescue` must be considered as branching because of
|
360
|
+
# the `retry` keyword.
|
361
|
+
if loop_assignments.first.node.each_ancestor(:if, :rescue, :case, :case_match).any?
|
362
|
+
loop_assignments.each { |assignment| assignment.reference!(node) }
|
363
|
+
else
|
364
|
+
loop_assignments.last&.reference!(node)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
357
368
|
def scanned_node?(node)
|
358
369
|
scanned_nodes.include?(node)
|
359
370
|
end
|
@@ -7,6 +7,7 @@ require 'yard'
|
|
7
7
|
# @api private
|
8
8
|
class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
9
9
|
include ::RuboCop::Cop::Documentation
|
10
|
+
|
10
11
|
CopData = Struct.new(
|
11
12
|
:cop, :description, :example_objects, :safety_objects, :see_objects, :config, keyword_init: true
|
12
13
|
)
|
data/lib/rubocop/lsp/routes.rb
CHANGED
@@ -194,7 +194,7 @@ module RuboCop
|
|
194
194
|
return []
|
195
195
|
end
|
196
196
|
|
197
|
-
new_text = @server.format(
|
197
|
+
new_text = @server.format(convert_file_uri_to_path(file_uri), text, command: command)
|
198
198
|
|
199
199
|
return [] if new_text == text
|
200
200
|
|
@@ -214,13 +214,13 @@ module RuboCop
|
|
214
214
|
method: 'textDocument/publishDiagnostics',
|
215
215
|
params: {
|
216
216
|
uri: file_uri,
|
217
|
-
diagnostics: @server.offenses(
|
217
|
+
diagnostics: @server.offenses(convert_file_uri_to_path(file_uri), text)
|
218
218
|
}
|
219
219
|
}
|
220
220
|
end
|
221
221
|
|
222
|
-
def
|
223
|
-
uri.delete_prefix('file://')
|
222
|
+
def convert_file_uri_to_path(uri)
|
223
|
+
URI.decode_www_form_component(uri.delete_prefix('file://'))
|
224
224
|
end
|
225
225
|
end
|
226
226
|
end
|
data/lib/rubocop/version.rb
CHANGED
data/lib/rubocop.rb
CHANGED
@@ -211,6 +211,7 @@ require_relative 'rubocop/cop/layout/empty_line_after_guard_clause'
|
|
211
211
|
require_relative 'rubocop/cop/layout/empty_line_after_magic_comment'
|
212
212
|
require_relative 'rubocop/cop/layout/empty_line_after_multiline_condition'
|
213
213
|
require_relative 'rubocop/cop/layout/empty_line_between_defs'
|
214
|
+
require_relative 'rubocop/cop/layout/empty_lines_after_module_inclusion'
|
214
215
|
require_relative 'rubocop/cop/layout/empty_lines_around_access_modifier'
|
215
216
|
require_relative 'rubocop/cop/layout/empty_lines_around_arguments'
|
216
217
|
require_relative 'rubocop/cop/layout/empty_lines_around_attribute_accessor'
|
@@ -290,6 +291,7 @@ require_relative 'rubocop/cop/layout/space_inside_string_interpolation'
|
|
290
291
|
require_relative 'rubocop/cop/layout/trailing_empty_lines'
|
291
292
|
require_relative 'rubocop/cop/layout/trailing_whitespace'
|
292
293
|
|
294
|
+
require_relative 'rubocop/cop/lint/utils/nil_receiver_checker'
|
293
295
|
require_relative 'rubocop/cop/lint/ambiguous_assignment'
|
294
296
|
require_relative 'rubocop/cop/lint/ambiguous_block_association'
|
295
297
|
require_relative 'rubocop/cop/lint/ambiguous_operator'
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.79.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
8
8
|
- Jonas Arvidsson
|
9
9
|
- Yuji Nakayama
|
10
|
+
autorequire:
|
10
11
|
bindir: exe
|
11
12
|
cert_chain: []
|
12
|
-
date: 2025-07-
|
13
|
+
date: 2025-07-31 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: json
|
@@ -127,7 +128,7 @@ dependencies:
|
|
127
128
|
requirements:
|
128
129
|
- - ">="
|
129
130
|
- !ruby/object:Gem::Version
|
130
|
-
version: 1.
|
131
|
+
version: 1.46.0
|
131
132
|
- - "<"
|
132
133
|
- !ruby/object:Gem::Version
|
133
134
|
version: '2.0'
|
@@ -137,7 +138,7 @@ dependencies:
|
|
137
138
|
requirements:
|
138
139
|
- - ">="
|
139
140
|
- !ruby/object:Gem::Version
|
140
|
-
version: 1.
|
141
|
+
version: 1.46.0
|
141
142
|
- - "<"
|
142
143
|
- !ruby/object:Gem::Version
|
143
144
|
version: '2.0'
|
@@ -342,6 +343,7 @@ files:
|
|
342
343
|
- lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb
|
343
344
|
- lib/rubocop/cop/layout/empty_line_between_defs.rb
|
344
345
|
- lib/rubocop/cop/layout/empty_lines.rb
|
346
|
+
- lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb
|
345
347
|
- lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb
|
346
348
|
- lib/rubocop/cop/layout/empty_lines_around_arguments.rb
|
347
349
|
- lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb
|
@@ -572,6 +574,7 @@ files:
|
|
572
574
|
- lib/rubocop/cop/lint/useless_ruby2_keywords.rb
|
573
575
|
- lib/rubocop/cop/lint/useless_setter_call.rb
|
574
576
|
- lib/rubocop/cop/lint/useless_times.rb
|
577
|
+
- lib/rubocop/cop/lint/utils/nil_receiver_checker.rb
|
575
578
|
- lib/rubocop/cop/lint/void.rb
|
576
579
|
- lib/rubocop/cop/message_annotator.rb
|
577
580
|
- lib/rubocop/cop/metrics/abc_size.rb
|
@@ -1088,11 +1091,12 @@ licenses:
|
|
1088
1091
|
- MIT
|
1089
1092
|
metadata:
|
1090
1093
|
homepage_uri: https://rubocop.org/
|
1091
|
-
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.
|
1094
|
+
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.79.1
|
1092
1095
|
source_code_uri: https://github.com/rubocop/rubocop/
|
1093
|
-
documentation_uri: https://docs.rubocop.org/rubocop/1.
|
1096
|
+
documentation_uri: https://docs.rubocop.org/rubocop/1.79/
|
1094
1097
|
bug_tracker_uri: https://github.com/rubocop/rubocop/issues
|
1095
1098
|
rubygems_mfa_required: 'true'
|
1099
|
+
post_install_message:
|
1096
1100
|
rdoc_options: []
|
1097
1101
|
require_paths:
|
1098
1102
|
- lib
|
@@ -1107,7 +1111,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1107
1111
|
- !ruby/object:Gem::Version
|
1108
1112
|
version: '0'
|
1109
1113
|
requirements: []
|
1110
|
-
rubygems_version: 3.
|
1114
|
+
rubygems_version: 3.3.7
|
1115
|
+
signing_key:
|
1111
1116
|
specification_version: 4
|
1112
1117
|
summary: Automatic Ruby code style checking tool.
|
1113
1118
|
test_files: []
|