rubocop 1.92.1 → 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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rubocop/config.rb +0 -4
  3. data/lib/rubocop/config_obsoletion.rb +9 -0
  4. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  5. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  6. data/lib/rubocop/cop/layout/end_alignment.rb +2 -8
  7. data/lib/rubocop/cop/layout/extra_spacing.rb +17 -6
  8. data/lib/rubocop/cop/layout/line_length.rb +23 -5
  9. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  10. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  11. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
  12. data/lib/rubocop/cop/layout/space_before_block_braces.rb +12 -0
  13. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
  14. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
  15. data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
  16. data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
  17. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
  18. data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
  19. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -8
  20. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
  21. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  22. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +17 -1
  23. data/lib/rubocop/cop/mixin/statement_modifier.rb +14 -1
  24. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  25. data/lib/rubocop/cop/style/and_or.rb +33 -10
  26. data/lib/rubocop/cop/style/case_equality.rb +14 -3
  27. data/lib/rubocop/cop/style/class_and_module_children.rb +4 -3
  28. data/lib/rubocop/cop/style/endless_method.rb +34 -6
  29. data/lib/rubocop/cop/style/float_division.rb +16 -1
  30. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -1
  31. data/lib/rubocop/cop/style/hash_lookup_method.rb +10 -0
  32. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -0
  33. data/lib/rubocop/cop/style/method_def_parentheses.rb +9 -1
  34. data/lib/rubocop/cop/style/numeric_predicate.rb +7 -0
  35. data/lib/rubocop/cop/style/parentheses_around_condition.rb +18 -0
  36. data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
  37. data/lib/rubocop/cop/style/raise_args.rb +66 -7
  38. data/lib/rubocop/cop/style/reduce_to_hash.rb +32 -34
  39. data/lib/rubocop/cop/style/redundant_begin.rb +24 -2
  40. data/lib/rubocop/cop/style/redundant_exception.rb +13 -9
  41. data/lib/rubocop/cop/style/redundant_self.rb +9 -1
  42. data/lib/rubocop/cop/style/single_line_methods.rb +21 -0
  43. data/lib/rubocop/cop/style/string_concatenation.rb +12 -1
  44. data/lib/rubocop/plugin/configuration_integrator.rb +24 -3
  45. data/lib/rubocop/runner.rb +1 -1
  46. data/lib/rubocop/version.rb +1 -1
  47. metadata +2 -2
@@ -74,7 +74,7 @@ module RuboCop
74
74
 
75
75
  arguments = [exception_node, message_node].compact.map(&:source).join(', ')
76
76
 
77
- if node.parent && requires_parens?(node.parent)
77
+ if parenthesize?(node)
78
78
  "#{node.method_name}(#{arguments})"
79
79
  else
80
80
  "#{node.method_name} #{arguments}"
@@ -86,28 +86,60 @@ module RuboCop
86
86
  return if message_nodes.size > 1
87
87
 
88
88
  argument = message_nodes.first.source
89
- exception_class = exception_node.receiver&.source || exception_node.source
89
+ exception_class = exception_class_node(exception_node).source
90
90
 
91
- if node.parent && requires_parens?(node.parent)
91
+ if parenthesize?(node)
92
92
  "#{node.method_name}(#{exception_class}.new(#{argument}))"
93
93
  else
94
94
  "#{node.method_name} #{exception_class}.new(#{argument})"
95
95
  end
96
96
  end
97
97
 
98
+ def exception_class_node(exception_node)
99
+ use_new_method?(exception_node) ? exception_node.receiver : exception_node
100
+ end
101
+
98
102
  def check_compact(node)
99
103
  if node.arguments.size > 1
100
104
  exception = node.first_argument
101
105
  return if exception.send_type? && exception.first_argument&.hash_type?
106
+ return if use_new_method?(exception) && exception.arguments?
102
107
 
103
108
  add_offense(node, message: format(COMPACT_MSG, method: node.method_name)) do |corrector|
104
- replace_raise(corrector, node, correction_exploded_to_compact(node))
109
+ correct_raise(node) { correct_to_compact(corrector, node) }
105
110
  end
106
111
  else
107
112
  correct_style_detected
108
113
  end
109
114
  end
110
115
 
116
+ def correct_to_compact(corrector, node)
117
+ if heredoc_message?(node)
118
+ correct_heredoc_exploded_to_compact(corrector, node)
119
+ else
120
+ corrector.replace(node, correction_exploded_to_compact(node))
121
+ end
122
+ end
123
+
124
+ def heredoc_message?(node)
125
+ node.parenthesized? && node.arguments.size == 2 && heredoc?(node.last_argument)
126
+ end
127
+
128
+ def heredoc?(node)
129
+ node.each_node(:any_str).any?(&:heredoc?)
130
+ end
131
+
132
+ def correct_heredoc_exploded_to_compact(corrector, node)
133
+ exception_node, message_node = *node.arguments
134
+ exception_class = exception_class_node(exception_node)
135
+ corrector.replace(range_between(exception_class, message_node), '.new(')
136
+ corrector.insert_after(message_node, ')')
137
+ end
138
+
139
+ def range_between(left_node, right_node)
140
+ left_node.source_range.end.join(right_node.source_range.begin)
141
+ end
142
+
111
143
  def check_exploded(node)
112
144
  return correct_style_detected unless node.arguments.one?
113
145
 
@@ -118,15 +150,36 @@ module RuboCop
118
150
  return if allowed_non_exploded_type?(first_arg)
119
151
 
120
152
  add_offense(node, message: format(EXPLODED_MSG, method: node.method_name)) do |corrector|
121
- replace_raise(corrector, node, correction_compact_to_exploded(node))
153
+ correct_raise(node) { correct_to_exploded(corrector, node) }
122
154
  end
123
155
  end
124
156
 
125
- def replace_raise(corrector, node, replacement)
157
+ def correct_to_exploded(corrector, node)
158
+ if heredoc_new_argument?(node)
159
+ correct_heredoc_compact_to_exploded(corrector, node)
160
+ else
161
+ corrector.replace(node, correction_compact_to_exploded(node))
162
+ end
163
+ end
164
+
165
+ def heredoc_new_argument?(node)
166
+ new_call = node.first_argument
167
+ return false unless new_call.arguments.one? && heredoc?(new_call.first_argument)
168
+
169
+ node.parenthesized? || !parenthesize?(node)
170
+ end
171
+
172
+ def correct_heredoc_compact_to_exploded(corrector, node)
173
+ new_call = node.first_argument
174
+ corrector.replace(range_between(new_call.receiver, new_call.first_argument), ', ')
175
+ corrector.remove(new_call.loc.end) if new_call.loc.end
176
+ end
177
+
178
+ def correct_raise(node)
126
179
  opposite_style_detected
127
180
  return if inside_corrected_raise?(node)
128
181
 
129
- corrector.replace(node, replacement)
182
+ yield
130
183
  ignore_node(node)
131
184
  end
132
185
 
@@ -157,6 +210,12 @@ module RuboCop
157
210
  Array(cop_config['AllowedCompactTypes']).include?(type)
158
211
  end
159
212
 
213
+ def parenthesize?(node)
214
+ return true if node.parenthesized?
215
+
216
+ node.parent && requires_parens?(node.parent)
217
+ end
218
+
160
219
  def requires_parens?(parent)
161
220
  return true if parent.operator_keyword?
162
221
  return true if parent.type?(:call, :super, :yield, :array, :pair)
@@ -100,6 +100,7 @@ module RuboCop
100
100
  return unless key
101
101
  return if accumulator_used_in_expressions?(block_node, key, value)
102
102
  return if nested_match?(key) || nested_match?(value)
103
+ return if heredoc_in_inject_numblock?(block_node, key, value)
103
104
 
104
105
  register_offense(node, block_node, key, value)
105
106
  end
@@ -124,6 +125,12 @@ module RuboCop
124
125
  end
125
126
  end
126
127
 
128
+ def heredoc_in_inject_numblock?(block_node, key, value)
129
+ return false if !block_node.numblock_type? || block_node.method?(:each_with_object)
130
+
131
+ [key, value].any? { |node| node.each_node(:any_str).any?(&:heredoc?) }
132
+ end
133
+
127
134
  def accumulator_name(block_node)
128
135
  index = block_node.method?(:each_with_object) ? 1 : 0
129
136
  block_node.argument_list[index].name
@@ -136,42 +143,20 @@ module RuboCop
136
143
  def register_offense(send_node, block_node, key_expr, value_expr)
137
144
  message = format(MSG, method: send_node.method_name)
138
145
 
146
+ # Each part is replaced separately so that heredoc bodies between them are kept.
139
147
  add_offense(send_node.loc.selector, message: message) do |corrector|
140
- corrector.replace(
141
- replacement_range(send_node, block_node),
142
- replacement(block_node, key_expr, value_expr)
143
- )
144
- end
145
- end
148
+ corrector.replace(method_call_range(send_node), 'to_h')
146
149
 
147
- def replacement(block_node, key_expr, value_expr)
148
- key_source = adjusted_source(key_expr, block_node)
149
- value_source = adjusted_source(value_expr, block_node)
150
- body = "[#{key_source}, #{value_source}]"
151
-
152
- if block_node.numblock_type?
153
- block_node.braces? ? "to_h { #{body} }" : do_end_replacement(block_node, body)
154
- else
155
- named_block_replacement(block_node, body)
156
- end
157
- end
150
+ unless block_node.numblock_type?
151
+ corrector.replace(block_node.arguments, "|#{element_arg_source(block_node)}|")
152
+ end
158
153
 
159
- def named_block_replacement(block_node, body)
160
- arg = element_arg_source(block_node)
161
- if block_node.braces?
162
- "to_h { |#{arg}| #{body} }"
163
- else
164
- do_end_replacement(block_node, body, arg)
154
+ correct_body(corrector, block_node, key_expr, value_expr)
165
155
  end
166
156
  end
167
157
 
168
- def do_end_replacement(block_node, body, arg = nil)
169
- args = arg ? " |#{arg}|" : ''
170
- "to_h do#{args}\n#{indent(block_node)} #{body}\n#{indent(block_node)}end"
171
- end
172
-
173
- def replacement_range(send_node, block_node)
174
- range_between(send_node.loc.selector.begin_pos, block_node.source_range.end_pos)
158
+ def method_call_range(send_node)
159
+ range_between(send_node.loc.selector.begin_pos, send_node.source_range.end_pos)
175
160
  end
176
161
 
177
162
  def element_arg_source(block_node)
@@ -182,6 +167,16 @@ module RuboCop
182
167
  end
183
168
  end
184
169
 
170
+ def correct_body(corrector, block_node, key_expr, value_expr)
171
+ key_source = adjusted_source(key_expr, block_node)
172
+ value_source = adjusted_source(value_expr, block_node)
173
+ body = block_node.body
174
+ assignment = body.begin_type? ? body.children.first : body
175
+
176
+ corrector.replace(assignment, "[#{key_source}, #{value_source}]")
177
+ corrector.remove(accumulator_range(body.children.last)) if body.begin_type?
178
+ end
179
+
185
180
  def adjusted_source(expr_node, block_node)
186
181
  source = element_source(expr_node)
187
182
  return source unless block_node.numblock_type?
@@ -191,10 +186,6 @@ module RuboCop
191
186
  source.gsub('_2', '_1')
192
187
  end
193
188
 
194
- def indent(node)
195
- ' ' * node.source_range.column
196
- end
197
-
198
189
  def element_source(expr_node)
199
190
  if command_call?(expr_node) || expr_node.assignment? || expr_node.rescue_type?
200
191
  return "(#{expr_node.source})"
@@ -210,6 +201,13 @@ module RuboCop
210
201
 
211
202
  node.arguments? && !node.parenthesized? && !node.operator_method? && !node.setter_method?
212
203
  end
204
+
205
+ def accumulator_range(accumulator)
206
+ range = range_with_surrounding_space(accumulator.source_range, side: :left)
207
+ return range unless range.source_buffer.source[range.begin_pos - 1] == ';'
208
+
209
+ range_with_surrounding_space(range.adjust(begin_pos: -1), side: :left, newlines: false)
210
+ end
213
211
  end
214
212
  end
215
213
  end
@@ -67,6 +67,7 @@ module RuboCop
67
67
  extend AutoCorrector
68
68
 
69
69
  MSG = 'Redundant `begin` block detected.'
70
+ SPACE_INSIDE_PARENS_STYLES = %w[space compact].freeze
70
71
 
71
72
  def self.autocorrect_incompatible_with
72
73
  [Style::BlockDelimiters]
@@ -132,7 +133,8 @@ module RuboCop
132
133
  empty_begin?(node) ||
133
134
  begin_block_has_multiline_statements?(node) ||
134
135
  contain_rescue_or_ensure?(node) ||
135
- valid_context_using_only_begin?(node)
136
+ valid_context_using_only_begin?(node) ||
137
+ ternary_operand_requiring_begin?(node)
136
138
  end
137
139
 
138
140
  def register_offense(node)
@@ -229,6 +231,12 @@ module RuboCop
229
231
  parent&.send_type? || parent&.operator_keyword?
230
232
  end
231
233
 
234
+ def ternary_operand_requiring_begin?(node)
235
+ return false unless node.parent&.if_type? && node.parent.ternary?
236
+
237
+ !node.children.one? || low_precedence_statement?(node.children.first)
238
+ end
239
+
232
240
  def valid_begin_assignment?(node)
233
241
  node.parent&.assignment? && (!node.children.one? || too_long_when_joined?(node))
234
242
  end
@@ -239,14 +247,28 @@ module RuboCop
239
247
  return false unless max && statement.single_line?
240
248
 
241
249
  length = statement.source.length
242
- length += 2 if low_precedence_statement?(statement)
250
+ length += parentheses_width if low_precedence_statement?(statement)
251
+
243
252
  node.loc.column + length > max
244
253
  end
245
254
 
255
+ def parentheses_width
256
+ space_inside_parens? ? 4 : 2
257
+ end
258
+
259
+ def space_inside_parens?
260
+ return false unless config.cop_enabled?('Layout/SpaceInsideParens')
261
+
262
+ style = config.for_cop('Layout/SpaceInsideParens')['EnforcedStyle']
263
+
264
+ SPACE_INSIDE_PARENS_STYLES.include?(style)
265
+ end
266
+
246
267
  def inspect_branches(node)
247
268
  node.branches.each do |branch|
248
269
  next unless branch&.kwbegin_type?
249
270
  next if branch.rescue_node || branch.ensure_node
271
+ next if ternary_operand_requiring_begin?(branch)
250
272
 
251
273
  register_offense(branch)
252
274
  end
@@ -37,23 +37,18 @@ module RuboCop
37
37
  private
38
38
 
39
39
  def fix_exploded(node)
40
- exploded?(node) do |command, message|
40
+ exploded?(node) do |exception, message|
41
41
  # `raise RuntimeError, nil` uses the class name as the message, so
42
42
  # rewriting it to `raise nil.to_s` (an empty message) would change it.
43
43
  next if message.nil_type?
44
44
 
45
45
  add_offense(node, message: MSG_1) do |corrector|
46
- corrector.replace(node, replaced_exploded(node, command, message))
46
+ corrector.remove(exception.source_range.join(message.source_range.begin))
47
+ corrector.replace(message, message_source(message))
47
48
  end
48
49
  end
49
50
  end
50
51
 
51
- def replaced_exploded(node, command, message)
52
- arg = message_source(message)
53
- arg = node.parenthesized? ? "(#{arg})" : " #{arg}"
54
- "#{command}#{arg}"
55
- end
56
-
57
52
  def string_message?(message)
58
53
  message.any_str_type?
59
54
  end
@@ -63,11 +58,20 @@ module RuboCop
63
58
  next if message.nil_type?
64
59
 
65
60
  add_offense(node, message: MSG_2) do |corrector|
61
+ # Replacing the call would drop a heredoc body that sits inside its parentheses.
62
+ next if heredoc_body_inside?(new_call, message)
63
+
66
64
  corrector.replace(new_call, message_source(message))
67
65
  end
68
66
  end
69
67
  end
70
68
 
69
+ def heredoc_body_inside?(new_call, message)
70
+ message.each_node(:any_str).any? do |str|
71
+ str.heredoc? && str.loc.heredoc_end.end_pos < new_call.source_range.end_pos
72
+ end
73
+ end
74
+
71
75
  def message_source(message)
72
76
  if string_message?(message)
73
77
  message.source
@@ -90,7 +94,7 @@ module RuboCop
90
94
 
91
95
  # @!method exploded?(node)
92
96
  def_node_matcher :exploded?, <<~PATTERN
93
- (send nil? ${:raise :fail} (const {nil? cbase} :RuntimeError) $_)
97
+ (send nil? {:raise :fail} $(const {nil? cbase} :RuntimeError) $_)
94
98
  PATTERN
95
99
 
96
100
  # @!method compact?(node)
@@ -115,7 +115,7 @@ module RuboCop
115
115
 
116
116
  def on_send(node)
117
117
  return unless node.self_receiver? && regular_method_call?(node)
118
- return if node.parent&.mlhs_type?
118
+ return if multiple_assignment_target?(node)
119
119
  return if allowed_send_node?(node)
120
120
  return if it_method_in_block?(node)
121
121
 
@@ -154,6 +154,14 @@ module RuboCop
154
154
  end
155
155
  end
156
156
 
157
+ def multiple_assignment_target?(node)
158
+ return false unless (parent = node.parent)
159
+
160
+ parent = parent.parent if parent.splat_type?
161
+
162
+ parent.mlhs_type?
163
+ end
164
+
157
165
  def allowed_send_node?(node)
158
166
  @allowed_send_nodes.include?(node) ||
159
167
  @local_variables_scopes[node].include?(node.method_name) ||
@@ -69,10 +69,31 @@ module RuboCop
69
69
  return false if disallow_endless_method_style?
70
70
  return false unless body_node
71
71
  return false if body_node.parent.assignment_method?
72
+ return false if captures_following_code?(body_node.parent)
72
73
 
73
74
  !unsupported_endless_method_body?(body_node) && endless_method_body?(body_node)
74
75
  end
75
76
 
77
+ # `def foo; bar; end && baz` would become `def foo() = bar && baz`. The same goes for a def
78
+ # that ends an operand, as in `a && def foo; bar; end || baz`.
79
+ def captures_following_code?(node)
80
+ return false unless (parent = node.parent)
81
+
82
+ node_end = node.source_range.end_pos
83
+ return captures_following_code?(parent) if parent.source_range.end_pos == node_end
84
+
85
+ parent.children.first.equal?(node) && extends_endless_body?(parent, node)
86
+ end
87
+
88
+ def extends_endless_body?(parent, node)
89
+ case parent.type
90
+ when :and, :or then parent.logical_operator?
91
+ when :if then parent.ternary?
92
+ when :rescue then same_line?(node, parent.resbody_branches.first) # the modifier form
93
+ else parent.type?(:call, :range)
94
+ end
95
+ end
96
+
76
97
  def unsupported_endless_method_body?(body_node)
77
98
  body_node.basic_conditional? ||
78
99
  NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
@@ -143,7 +143,18 @@ module RuboCop
143
143
  def replacement(parts)
144
144
  interpolated_parts = parts.map { |part| adjust_str(part) }
145
145
 
146
- "\"#{handle_quotes(interpolated_parts).join}\""
146
+ "\"#{join_parts(handle_quotes(interpolated_parts))}\""
147
+ end
148
+
149
+ def join_parts(parts)
150
+ parts.each_with_object(+'') do |part, result|
151
+ result.insert(-2, '\\') if interpolation_formed?(result, part)
152
+ result << part
153
+ end
154
+ end
155
+
156
+ def interpolation_formed?(preceding, part)
157
+ part.start_with?('{', '@', '$') && preceding.match?(/(?<!\\)(?:\\\\)*#\z/)
147
158
  end
148
159
 
149
160
  def adjust_str(part)
@@ -105,18 +105,39 @@ module RuboCop
105
105
 
106
106
  case rules.type
107
107
  when :path
108
- [ConfigLoader.load_file(rules.value, check: false), rules.value]
108
+ config = ConfigLoader.load_file(rules.value, check: false)
109
+ warn_about_obsolete_config(plugin, config)
110
+ [config, rules.value]
109
111
  when :object
110
112
  path = plugin.method(:rules).source_location[0]
111
113
  [Config.create(rules.value, path, check: true), path]
112
114
  when :error
113
- plugin_name = plugin.about&.name || plugin.inspect
114
115
  error_message = rules.value.respond_to?(:message) ? rules.value.message : rules.value
115
116
 
116
- raise "Plugin `#{plugin_name}' failed to load with error: #{error_message}"
117
+ raise "Plugin `#{plugin_name(plugin)}' failed to load with error: #{error_message}"
117
118
  end
118
119
  end
119
120
 
121
+ # Plugin configuration is loaded without validation, so an obsolete key in a plugin's
122
+ # defaults used to surface only later, against the user's own file, once the two had
123
+ # been merged. Report it here, while the path is still the plugin's, and name the
124
+ # plugin: the file lives inside an installed gem, so the fix is to report it upstream.
125
+ # It is a warning whatever the rule's severity: a stale plugin is not the user's
126
+ # mistake and must not stop the run.
127
+ def warn_about_obsolete_config(plugin, config)
128
+ messages = ConfigObsoletion.new(config).messages
129
+ return if messages.empty?
130
+
131
+ warn Rainbow(<<~WARNING).yellow
132
+ Warning: obsolete configuration found in the `#{plugin_name(plugin)}` plugin:
133
+ #{messages.join("\n")}
134
+ WARNING
135
+ end
136
+
137
+ def plugin_name(plugin)
138
+ plugin.about&.name || plugin.inspect
139
+ end
140
+
120
141
  # This is how we ensure "first-in wins": plugins can override AllCops settings that are
121
142
  # set by RuboCop's default configuration, but once a plugin sets an AllCop setting, they
122
143
  # have exclusive first-in-wins rights to that setting.
@@ -367,8 +367,8 @@ module RuboCop
367
367
  return if team.cops.empty?
368
368
 
369
369
  team.defer_corrections = @options[:diff]
370
+ team.cops.first.offenses_to_check = offenses.reject(&:corrected?)
370
371
 
371
- team.cops.first.offenses_to_check = offenses
372
372
  yield team
373
373
  end
374
374
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.92.1'
6
+ STRING = '1.92.2'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
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.92.1
4
+ version: 1.92.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -1157,7 +1157,7 @@ licenses:
1157
1157
  - MIT
1158
1158
  metadata:
1159
1159
  homepage_uri: https://rubocop.org/
1160
- changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.92.1
1160
+ changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.92.2
1161
1161
  source_code_uri: https://github.com/rubocop/rubocop/
1162
1162
  documentation_uri: https://docs.rubocop.org/rubocop/1.92/
1163
1163
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues