rubocop 1.85.1 → 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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +9 -12
  3. data/lib/rubocop/cache_config.rb +1 -1
  4. data/lib/rubocop/cli/command/auto_generate_config.rb +1 -1
  5. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  6. data/lib/rubocop/cli/command/show_docs_url.rb +1 -1
  7. data/lib/rubocop/config.rb +14 -10
  8. data/lib/rubocop/config_finder.rb +1 -1
  9. data/lib/rubocop/config_loader_resolver.rb +2 -1
  10. data/lib/rubocop/config_store.rb +1 -1
  11. data/lib/rubocop/config_validator.rb +1 -1
  12. data/lib/rubocop/cop/documentation.rb +2 -3
  13. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  14. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  15. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -2
  16. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  17. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  18. data/lib/rubocop/cop/layout/end_alignment.rb +6 -3
  19. data/lib/rubocop/cop/layout/line_length.rb +5 -3
  20. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +28 -3
  21. data/lib/rubocop/cop/layout/space_around_keyword.rb +3 -1
  22. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -0
  23. data/lib/rubocop/cop/lint/constant_reassignment.rb +59 -9
  24. data/lib/rubocop/cop/lint/duplicate_methods.rb +55 -8
  25. data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
  26. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  27. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  28. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  29. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +16 -0
  30. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
  31. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  32. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
  33. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  34. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
  35. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  36. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +22 -7
  37. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
  38. data/lib/rubocop/cop/registry.rb +20 -13
  39. data/lib/rubocop/cop/style/access_modifier_declarations.rb +14 -2
  40. data/lib/rubocop/cop/style/and_or.rb +1 -0
  41. data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
  42. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  43. data/lib/rubocop/cop/style/block_delimiters.rb +23 -31
  44. data/lib/rubocop/cop/style/collection_compact.rb +36 -16
  45. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
  46. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -4
  47. data/lib/rubocop/cop/style/empty_class_definition.rb +24 -2
  48. data/lib/rubocop/cop/style/file_open.rb +1 -1
  49. data/lib/rubocop/cop/style/global_vars.rb +1 -1
  50. data/lib/rubocop/cop/style/guard_clause.rb +9 -6
  51. data/lib/rubocop/cop/style/hash_lookup_method.rb +7 -0
  52. data/lib/rubocop/cop/style/if_inside_else.rb +1 -5
  53. data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -0
  54. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
  55. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  56. data/lib/rubocop/cop/style/magic_comment_format.rb +2 -2
  57. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -3
  58. data/lib/rubocop/cop/style/module_member_existence_check.rb +1 -11
  59. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  60. data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
  61. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  62. data/lib/rubocop/cop/style/one_class_per_file.rb +24 -4
  63. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  64. data/lib/rubocop/cop/style/redundant_each.rb +3 -3
  65. data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
  66. data/lib/rubocop/cop/style/redundant_parentheses.rb +22 -20
  67. data/lib/rubocop/cop/style/redundant_percent_q.rb +4 -1
  68. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  69. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +10 -0
  70. data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
  71. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  72. data/lib/rubocop/cop/style/symbol_proc.rb +4 -3
  73. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  74. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  75. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  76. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  77. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  78. data/lib/rubocop/lsp/routes.rb +10 -3
  79. data/lib/rubocop/mcp/server.rb +27 -1
  80. data/lib/rubocop/path_util.rb +14 -2
  81. data/lib/rubocop/plugin/loader.rb +1 -1
  82. data/lib/rubocop/result_cache.rb +10 -1
  83. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  84. data/lib/rubocop/rspec/shared_contexts.rb +11 -2
  85. data/lib/rubocop/runner.rb +8 -3
  86. data/lib/rubocop/server/core.rb +2 -0
  87. data/lib/rubocop/target_finder.rb +1 -1
  88. data/lib/rubocop/version.rb +2 -2
  89. metadata +5 -19
@@ -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
 
@@ -114,7 +114,7 @@ module RuboCop
114
114
  def first_arg_begins_with_hash_literal?(node)
115
115
  # Don't flag `method ({key: value})` or `method ({key: value}.method)`
116
116
  hash_literal = method_chain_begins_with_hash_literal(node.children.first)
117
- if (root_method = node.each_ancestor(:send).to_a.last)
117
+ if (root_method = node.each_ancestor(:call).to_a.last)
118
118
  parenthesized = root_method.parenthesized_call?
119
119
  end
120
120
  hash_literal && first_argument?(node) && !parentheses?(hash_literal) && !parenthesized
@@ -139,6 +139,8 @@ module RuboCop
139
139
  node = begin_node.children.first
140
140
 
141
141
  if (message = find_offense_message(begin_node, node))
142
+ return offense(begin_node, message) if message == 'block body'
143
+
142
144
  if node.range_type? && !argument_of_parenthesized_method_call?(begin_node, node)
143
145
  begin_node = begin_node.parent
144
146
  end
@@ -155,7 +157,8 @@ module RuboCop
155
157
  return 'a literal' if node.literal? && disallowed_literal?(begin_node, node)
156
158
  return 'a variable' if node.variable?
157
159
  return 'a constant' if node.const_type?
158
- return 'block body' if begin_node.parent&.any_block_type? && !node.range_type?
160
+ return 'block body' if begin_node.parent&.any_block_type? || body_range?(begin_node, node)
161
+
159
162
  if node.assignment? && (begin_node.parent.nil? || begin_node.parent.begin_type?)
160
163
  return 'an assignment'
161
164
  end
@@ -267,6 +270,18 @@ module RuboCop
267
270
  end
268
271
  end
269
272
 
273
+ # rubocop:disable Metrics/CyclomaticComplexity
274
+ def body_range?(begin_node, node)
275
+ return false if begin_node.chained?
276
+ return false unless node.range_type?
277
+ return false unless (parent = begin_node.parent)
278
+ return false unless parent.begin_type?
279
+
280
+ (node.begin.nil? && begin_node == parent.children.first) ||
281
+ (node.end.nil? && begin_node == parent.children.last)
282
+ end
283
+ # rubocop:enable Metrics/CyclomaticComplexity
284
+
270
285
  def disallowed_one_line_pattern_matching?(begin_node, node)
271
286
  if (parent = begin_node.parent)
272
287
  return false if parent.any_def_type? && parent.endless?
@@ -320,28 +335,15 @@ module RuboCop
320
335
  end
321
336
 
322
337
  def first_argument?(node)
323
- if first_send_argument?(node) ||
324
- first_super_argument?(node) ||
325
- first_yield_argument?(node)
326
- return true
327
- end
338
+ return true if first_call_argument?(node)
328
339
 
329
340
  node.each_ancestor.any? { |ancestor| first_argument?(ancestor) }
330
341
  end
331
342
 
332
- # @!method first_send_argument?(node)
333
- def_node_matcher :first_send_argument?, <<~PATTERN
334
- ^(send _ _ equal?(%0) ...)
335
- PATTERN
336
-
337
- # @!method first_super_argument?(node)
338
- def_node_matcher :first_super_argument?, <<~PATTERN
339
- ^(super equal?(%0) ...)
340
- PATTERN
341
-
342
- # @!method first_yield_argument?(node)
343
- def_node_matcher :first_yield_argument?, <<~PATTERN
344
- ^(yield equal?(%0) ...)
343
+ # @!method first_call_argument?(node)
344
+ def_node_matcher :first_call_argument?, <<~PATTERN
345
+ {^(call _ _ equal?(%0) ...)
346
+ ^({super yield} equal?(%0) ...)}
345
347
  PATTERN
346
348
 
347
349
  def call_chain_starts_with_int?(begin_node, send_node)
@@ -90,7 +90,10 @@ module RuboCop
90
90
  def acceptable_q?(node)
91
91
  src = node.source
92
92
 
93
- return true if STRING_INTERPOLATION_REGEXP.match?(src)
93
+ # If the string contains interpolation-like syntax and would be
94
+ # converted to a double-quoted string (because it contains single
95
+ # quotes), the replacement would activate interpolation.
96
+ return true if STRING_INTERPOLATION_REGEXP.match?(src) && src.include?(SINGLE_QUOTE)
94
97
 
95
98
  src.scan(/\\./).any?(ESCAPED_NON_BACKSLASH)
96
99
  end
@@ -27,11 +27,6 @@ module RuboCop
27
27
 
28
28
  MSG = 'Remove the self-assignment branch.'
29
29
 
30
- # @!method bad_method?(node)
31
- def_node_matcher :bad_method?, <<~PATTERN
32
- (send nil? :bad_method ...)
33
- PATTERN
34
-
35
30
  def on_lvasgn(node)
36
31
  expression = node.expression
37
32
 
@@ -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.
@@ -367,13 +367,13 @@ module RuboCop
367
367
  def unsafe_method_used?(node, method_chain, method)
368
368
  return true if unsafe_method?(node, method)
369
369
 
370
- method.each_ancestor(:send).any? do |ancestor|
371
- break true unless config.cop_enabled?('Lint/SafeNavigationChain')
372
-
373
- break true if unsafe_method?(node, ancestor)
374
- break true if nil_methods.include?(ancestor.method_name)
375
- break false if ancestor == method_chain
370
+ method.each_ancestor(:send) do |ancestor|
371
+ return true unless config.cop_enabled?('Lint/SafeNavigationChain')
372
+ return true if unsafe_method?(node, ancestor)
373
+ return true if nil_methods.include?(ancestor.method_name)
374
+ return false if ancestor == method_chain
376
375
  end
376
+ false
377
377
  end
378
378
 
379
379
  def unsafe_method?(node, send_node)
@@ -409,7 +409,7 @@ module RuboCop
409
409
  start_method,
410
410
  method_chain)
411
411
  start_method.each_ancestor do |ancestor|
412
- break unless %i[send block].include?(ancestor.type)
412
+ break unless ancestor.type?(:call, :any_block)
413
413
  next if !ancestor.send_type? || ancestor.operator_method?
414
414
 
415
415
  corrector.insert_before(ancestor.loc.dot, '&')
@@ -89,7 +89,7 @@ module RuboCop
89
89
  end
90
90
 
91
91
  def method_names
92
- methods.map { |method| method_name(method).to_sym }
92
+ @method_names ||= methods.map { |method| method_name(method).to_sym }.freeze
93
93
  end
94
94
 
95
95
  def method_name(method)
@@ -179,7 +179,7 @@ module RuboCop
179
179
  return if allowed_method_name?(dispatch_node.method_name)
180
180
  return if allow_if_method_has_argument?(node.send_node)
181
181
  return if node.block_type? && destructuring_block_argument?(arguments_node)
182
- return if allow_comments? && contains_comments?(node)
182
+ return if allow_comments?(node)
183
183
 
184
184
  register_offense(node, method_name, dispatch_node.method_name)
185
185
  end
@@ -273,8 +273,9 @@ module RuboCop
273
273
  !!cop_config.fetch('AllowMethodsWithArguments', false) && send_node.arguments.any?
274
274
  end
275
275
 
276
- def allow_comments?
277
- cop_config.fetch('AllowComments', false)
276
+ def allow_comments?(node)
277
+ cop_config.fetch('AllowComments', false) && contains_comments?(node) &&
278
+ !comments_contain_disables?(node, name)
278
279
  end
279
280
  end
280
281
  end
@@ -45,6 +45,7 @@ module RuboCop
45
45
  corrector.insert_before(node.loc.end, "\n#{' ' * node.loc.keyword.column}")
46
46
  end
47
47
  end
48
+ alias on_defs on_def
48
49
 
49
50
  private
50
51
 
@@ -76,7 +76,7 @@ module RuboCop
76
76
  end
77
77
 
78
78
  def supported_operators
79
- Array(cop_config['SupportedOperators'])
79
+ @supported_operators ||= Array(cop_config['SupportedOperators']).freeze
80
80
  end
81
81
 
82
82
  def offended_ancestor?(node)
@@ -233,7 +233,7 @@ module RuboCop
233
233
 
234
234
  def output_exclude_list(output_buffer, offending_files, cop_name)
235
235
  require 'pathname'
236
- parent = Pathname.new(Dir.pwd)
236
+ parent = Pathname.new(PathUtil.pwd)
237
237
 
238
238
  output_buffer.puts ' Exclude:'
239
239
  excludes(offending_files, cop_name, parent).each do |exclude_path|
@@ -93,7 +93,7 @@ module RuboCop
93
93
 
94
94
  def classname_attribute_value(file)
95
95
  @classname_attribute_value_cache ||= Hash.new do |hash, key|
96
- hash[key] = key.delete_suffix('.rb').gsub("#{Dir.pwd}/", '').tr('/', '.')
96
+ hash[key] = key.delete_suffix('.rb').gsub("#{PathUtil.pwd}/", '').tr('/', '.')
97
97
  end
98
98
  @classname_attribute_value_cache[file]
99
99
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  def file_finished(file, offenses)
25
25
  return if offenses.empty?
26
26
 
27
- path = Pathname.new(file).relative_path_from(Pathname.new(Dir.pwd))
27
+ path = Pathname.new(file).relative_path_from(Pathname.new(PathUtil.pwd))
28
28
  @offense_counts[path] = offenses.size
29
29
  end
30
30
 
@@ -61,9 +61,16 @@ module RuboCop
61
61
 
62
62
  handle 'initialized' do |_request|
63
63
  version = RuboCop::Version::STRING
64
- yjit = Object.const_defined?('RubyVM::YJIT') && RubyVM::YJIT.enabled? ? ' +YJIT' : ''
65
-
66
- Logger.log("RuboCop #{version} language server#{yjit} initialized, PID #{Process.pid}")
64
+ # Only one JIT can be enabled at the same time, since YJIT and ZJIT are mutually exclusive.
65
+ jit = if Object.const_defined?('RubyVM::YJIT') && RubyVM::YJIT.enabled?
66
+ '+YJIT'
67
+ elsif Object.const_defined?('RubyVM::ZJIT') && RubyVM::ZJIT.enabled?
68
+ '+ZJIT'
69
+ else
70
+ ''
71
+ end
72
+
73
+ Logger.log("RuboCop #{version} language server#{jit} initialized, PID #{Process.pid}")
67
74
  end
68
75
 
69
76
  handle 'shutdown' do |request|
@@ -1,6 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'mcp'
3
+ begin
4
+ require 'mcp'
5
+
6
+ required_mcp_version = '0.6.0'
7
+
8
+ if Gem::Version.new(required_mcp_version) > Gem::Version.new(MCP::VERSION)
9
+ # While `mcp` is not a runtime dependency, users may have an outdated version installed.
10
+ warn <<~MESSAGE
11
+ Error: `mcp` gem version #{MCP::VERSION} was loaded, but `rubocop --mcp` requires #{required_mcp_version}.
12
+ - If you're using Bundler and don't yet have `gem 'mcp'` as a dependency, add it now.
13
+ - If you're using Bundler and already have `gem 'mcp'` as a dependency, update it to the most recent version.
14
+ - If you don't use Bundler, run `gem update mcp`.
15
+ MESSAGE
16
+ exit!
17
+ end
18
+ rescue LoadError => e
19
+ raise unless e.path == 'mcp'
20
+
21
+ warn <<~MESSAGE
22
+ Error: Unable to load `mcp` gem. Add `gem 'mcp', '~> 0.6'` to your Gemfile, or run `gem install mcp`.
23
+ MESSAGE
24
+
25
+ exit!
26
+ end
27
+
4
28
  require_relative '../lsp'
5
29
  require_relative '../lsp/runtime'
6
30
 
@@ -166,6 +190,8 @@ module RuboCop
166
190
  result = yield(path, source_code, safety)
167
191
 
168
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)
169
195
  end
170
196
  end
171
197
  # rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
@@ -10,7 +10,19 @@ module RuboCop
10
10
 
11
11
  module_function
12
12
 
13
- def relative_path(path, base_dir = Dir.pwd)
13
+ # Returns the current working directory, cached for the duration of a run.
14
+ # Dir.pwd is a syscall; caching it avoids repeated overhead since RuboCop
15
+ # never changes the working directory during a run.
16
+ def pwd
17
+ @pwd ||= Dir.pwd
18
+ end
19
+
20
+ # Reset the cached pwd. Only needed in tests that use Dir.chdir.
21
+ def reset_pwd
22
+ @pwd = nil
23
+ end
24
+
25
+ def relative_path(path, base_dir = PathUtil.pwd)
14
26
  PathUtil.relative_paths_cache[base_dir][path] ||=
15
27
  # Optimization for the common case where path begins with the base
16
28
  # dir. Just cut off the first part.
@@ -41,7 +53,7 @@ module RuboCop
41
53
  path.uri.to_s
42
54
  else
43
55
  # Ideally, we calculate this relative to the project root.
44
- base_dir = Dir.pwd
56
+ base_dir = PathUtil.pwd
45
57
 
46
58
  if path.start_with? base_dir
47
59
  relative_path(path, base_dir)
@@ -84,7 +84,7 @@ module RuboCop
84
84
  end
85
85
 
86
86
  def require_plugin(require_path)
87
- FeatureLoader.load(config_directory_path: Dir.pwd, feature: require_path)
87
+ FeatureLoader.load(config_directory_path: PathUtil.pwd, feature: require_path)
88
88
  end
89
89
 
90
90
  def constantize_plugin_from_gemspec_metadata(plugin_name)
@@ -27,6 +27,7 @@ module RuboCop
27
27
  # there's parallel execution and the cache is shared.
28
28
  def self.cleanup(config_store, verbose, cache_root_override = nil)
29
29
  return if inhibit_cleanup # OPTIMIZE: For faster testing
30
+ return unless config_store.for_pwd.for_all_cops['MaxFilesInCache']
30
31
 
31
32
  rubocop_cache_dir = cache_root(config_store, cache_root_override)
32
33
  return unless File.exist?(rubocop_cache_dir)
@@ -85,15 +86,23 @@ module RuboCop
85
86
  end
86
87
 
87
88
  def self.cache_root(config_store, cache_root_override = nil)
88
- CacheConfig.root_dir do
89
+ return @cache_root if @cache_root && !cache_root_override
90
+
91
+ result = CacheConfig.root_dir do
89
92
  cache_root_override || config_store.for_pwd.for_all_cops['CacheRootDirectory']
90
93
  end
94
+ @cache_root = result unless cache_root_override
95
+ result
91
96
  end
92
97
 
93
98
  def self.allow_symlinks_in_cache_location?(config_store)
94
99
  config_store.for_pwd.for_all_cops['AllowSymlinksInCacheRootDirectory']
95
100
  end
96
101
 
102
+ def self.reset_config_cache
103
+ @cache_root = nil
104
+ end
105
+
97
106
  attr_reader :path
98
107
 
99
108
  def initialize(file, team, options, config_store, cache_root_override = nil)
@@ -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)
@@ -2,8 +2,12 @@
2
2
 
3
3
  require 'tmpdir'
4
4
 
5
+ # Reset cached PathUtil.pwd before each example so that tests using Dir.chdir
6
+ # or stubbing Dir.pwd get a fresh value.
7
+ RSpec.configure { |c| c.before { RuboCop::PathUtil.reset_pwd } }
8
+
5
9
  RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLength
6
- around do |example|
10
+ around do |example| # rubocop:disable Metrics/BlockLength
7
11
  Dir.mktmpdir do |tmpdir|
8
12
  original_home = Dir.home
9
13
  original_xdg_config_home = ENV.fetch('XDG_CONFIG_HOME', nil)
@@ -26,11 +30,16 @@ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLe
26
30
  begin
27
31
  FileUtils.mkdir_p(working_dir)
28
32
 
29
- Dir.chdir(working_dir) { example.run }
33
+ Dir.chdir(working_dir) do
34
+ RuboCop::PathUtil.reset_pwd
35
+ RuboCop::ResultCache.reset_config_cache
36
+ example.run
37
+ end
30
38
  ensure
31
39
  ENV['HOME'] = original_home
32
40
  ENV['XDG_CONFIG_HOME'] = original_xdg_config_home
33
41
 
42
+ RuboCop::ResultCache.reset_config_cache
34
43
  RuboCop::ConfigLoader.clear_options # This also resets RuboCop::FileFinder.root_level
35
44
  end
36
45
  end
@@ -194,7 +194,7 @@ module RuboCop
194
194
 
195
195
  if real_run_needed
196
196
  offenses = yield
197
- save_in_cache(cache, offenses)
197
+ save_in_cache(cache, offenses) unless Cop::Registry.global.warnings?(file)
198
198
  end
199
199
 
200
200
  offenses
@@ -350,7 +350,9 @@ module RuboCop
350
350
 
351
351
  def inspect_file(processed_source, team = mobilize_team(processed_source))
352
352
  extracted_ruby_sources = extract_ruby_sources(processed_source)
353
- offenses = extracted_ruby_sources.flat_map do |extracted_ruby_source|
353
+ offenses = []
354
+
355
+ extracted_ruby_sources.each do |extracted_ruby_source|
354
356
  report = team.investigate(
355
357
  extracted_ruby_source[:processed_source],
356
358
  offset: extracted_ruby_source[:offset],
@@ -358,8 +360,11 @@ module RuboCop
358
360
  )
359
361
  @errors.concat(team.errors)
360
362
  @warnings.concat(team.warnings)
361
- report.offenses
363
+ offenses.concat(report.offenses)
364
+
365
+ break if team.updated_source_file?
362
366
  end
367
+
363
368
  [offenses, team.updated_source_file?]
364
369
  end
365
370
 
@@ -45,6 +45,8 @@ module RuboCop
45
45
  write_port_and_token_files
46
46
 
47
47
  pid = fork do
48
+ # NOTE: As of Ruby 4.0.0, ZJIT is still under development, while YJIT is production-ready,
49
+ # so support for ZJIT is deferred.
48
50
  if defined?(RubyVM::YJIT.enable)
49
51
  RubyVM::YJIT.enable
50
52
  end
@@ -38,7 +38,7 @@ module RuboCop
38
38
  # @param base_dir Root directory under which to search for
39
39
  # ruby source files
40
40
  # @return [Array] Array of filenames
41
- def target_files_in_dir(base_dir = Dir.pwd)
41
+ def target_files_in_dir(base_dir = PathUtil.pwd)
42
42
  # Support Windows: Backslashes from command-line -> forward slashes
43
43
  base_dir = base_dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
44
44
  all_files = find_files(base_dir, File::FNM_DOTMATCH)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.85.1'
6
+ STRING = '1.86.1'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
@@ -55,7 +55,7 @@ module RuboCop
55
55
 
56
56
  # @api private
57
57
  def self.parser_version(target_ruby_version)
58
- config_path = ConfigFinder.find_config_path(Dir.pwd)
58
+ config_path = ConfigFinder.find_config_path(PathUtil.pwd)
59
59
  yaml = Util.silence_warnings do
60
60
  ConfigLoader.load_yaml_configuration(config_path)
61
61
  end
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.85.1
4
+ version: 1.86.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -53,32 +53,18 @@ dependencies:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: 1.1.0
56
- - !ruby/object:Gem::Dependency
57
- name: mcp
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - "~>"
61
- - !ruby/object:Gem::Version
62
- version: '0.6'
63
- type: :runtime
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - "~>"
68
- - !ruby/object:Gem::Version
69
- version: '0.6'
70
56
  - !ruby/object:Gem::Dependency
71
57
  name: parallel
72
58
  requirement: !ruby/object:Gem::Requirement
73
59
  requirements:
74
- - - "~>"
60
+ - - ">="
75
61
  - !ruby/object:Gem::Version
76
62
  version: '1.10'
77
63
  type: :runtime
78
64
  prerelease: false
79
65
  version_requirements: !ruby/object:Gem::Requirement
80
66
  requirements:
81
- - - "~>"
67
+ - - ">="
82
68
  - !ruby/object:Gem::Version
83
69
  version: '1.10'
84
70
  - !ruby/object:Gem::Dependency
@@ -1128,9 +1114,9 @@ licenses:
1128
1114
  - MIT
1129
1115
  metadata:
1130
1116
  homepage_uri: https://rubocop.org/
1131
- changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.85.1
1117
+ changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.86.1
1132
1118
  source_code_uri: https://github.com/rubocop/rubocop/
1133
- documentation_uri: https://docs.rubocop.org/rubocop/1.85/
1119
+ documentation_uri: https://docs.rubocop.org/rubocop/1.86/
1134
1120
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues
1135
1121
  rubygems_mfa_required: 'true'
1136
1122
  rdoc_options: []