rubocop 1.84.2 → 1.87.0

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 (256) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +106 -16
  3. data/config/obsoletion.yml +5 -0
  4. data/lib/rubocop/cache_config.rb +1 -1
  5. data/lib/rubocop/cli/command/auto_generate_config.rb +28 -2
  6. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  7. data/lib/rubocop/cli/command/mcp.rb +19 -0
  8. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  9. data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
  10. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  11. data/lib/rubocop/cli.rb +9 -7
  12. data/lib/rubocop/comment_config.rb +12 -15
  13. data/lib/rubocop/config.rb +14 -10
  14. data/lib/rubocop/config_finder.rb +1 -1
  15. data/lib/rubocop/config_loader.rb +17 -2
  16. data/lib/rubocop/config_loader_resolver.rb +13 -4
  17. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  18. data/lib/rubocop/config_store.rb +2 -2
  19. data/lib/rubocop/config_validator.rb +1 -1
  20. data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
  21. data/lib/rubocop/cop/base.rb +8 -2
  22. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  23. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  24. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
  25. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  26. data/lib/rubocop/cop/correctors.rb +28 -0
  27. data/lib/rubocop/cop/documentation.rb +2 -3
  28. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  29. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  30. data/lib/rubocop/cop/gemspec/require_mfa.rb +5 -5
  31. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  32. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  33. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  34. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  35. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
  36. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  37. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  38. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  39. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  40. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +23 -7
  41. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  42. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  43. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
  44. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  45. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  46. data/lib/rubocop/cop/layout/end_alignment.rb +8 -5
  47. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
  48. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  49. data/lib/rubocop/cop/layout/indentation_width.rb +12 -0
  50. data/lib/rubocop/cop/layout/line_length.rb +5 -3
  51. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
  52. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  53. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +53 -3
  54. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  55. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
  56. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  57. data/lib/rubocop/cop/layout/space_around_keyword.rb +3 -1
  58. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
  59. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -0
  60. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  61. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  62. data/lib/rubocop/cop/lint/constant_reassignment.rb +93 -11
  63. data/lib/rubocop/cop/lint/constant_resolution.rb +6 -6
  64. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  65. data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
  66. data/lib/rubocop/cop/lint/duplicate_methods.rb +55 -8
  67. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  68. data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
  69. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  70. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  71. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  72. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  73. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  74. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  75. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  76. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  77. data/lib/rubocop/cop/lint/number_conversion.rb +6 -6
  78. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  79. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
  80. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -11
  81. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
  82. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
  83. data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
  84. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
  85. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
  86. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  87. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  88. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
  89. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
  90. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  91. data/lib/rubocop/cop/lint/unreachable_code.rb +2 -2
  92. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  93. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  94. data/lib/rubocop/cop/lint/useless_assignment.rb +4 -9
  95. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
  96. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  97. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  98. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +35 -9
  99. data/lib/rubocop/cop/lint/void.rb +32 -12
  100. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  101. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  102. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  103. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  104. data/lib/rubocop/cop/migration/department_name.rb +12 -1
  105. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  106. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  107. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  108. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  109. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
  110. data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
  111. data/lib/rubocop/cop/mixin.rb +86 -0
  112. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  113. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  114. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  115. data/lib/rubocop/cop/naming/predicate_method.rb +2 -2
  116. data/lib/rubocop/cop/naming/predicate_prefix.rb +1 -1
  117. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  118. data/lib/rubocop/cop/offense.rb +8 -0
  119. data/lib/rubocop/cop/registry.rb +62 -38
  120. data/lib/rubocop/cop/security/eval.rb +15 -2
  121. data/lib/rubocop/cop/security/io_methods.rb +1 -1
  122. data/lib/rubocop/cop/style/access_modifier_declarations.rb +14 -2
  123. data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
  124. data/lib/rubocop/cop/style/alias.rb +14 -2
  125. data/lib/rubocop/cop/style/and_or.rb +1 -0
  126. data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
  127. data/lib/rubocop/cop/style/array_join.rb +4 -2
  128. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  129. data/lib/rubocop/cop/style/attr.rb +5 -2
  130. data/lib/rubocop/cop/style/bare_percent_literals.rb +3 -1
  131. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  132. data/lib/rubocop/cop/style/block_delimiters.rb +25 -33
  133. data/lib/rubocop/cop/style/case_equality.rb +4 -0
  134. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  135. data/lib/rubocop/cop/style/class_and_module_children.rb +18 -2
  136. data/lib/rubocop/cop/style/collection_compact.rb +36 -16
  137. data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
  138. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
  139. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -4
  140. data/lib/rubocop/cop/style/copyright.rb +22 -11
  141. data/lib/rubocop/cop/style/date_time.rb +2 -2
  142. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
  143. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  144. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  145. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  146. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  147. data/lib/rubocop/cop/style/empty_class_definition.rb +43 -20
  148. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  149. data/lib/rubocop/cop/style/encoding.rb +7 -1
  150. data/lib/rubocop/cop/style/end_block.rb +3 -1
  151. data/lib/rubocop/cop/style/endless_method.rb +8 -3
  152. data/lib/rubocop/cop/style/file_open.rb +84 -0
  153. data/lib/rubocop/cop/style/file_write.rb +18 -16
  154. data/lib/rubocop/cop/style/for.rb +3 -0
  155. data/lib/rubocop/cop/style/format_string.rb +4 -3
  156. data/lib/rubocop/cop/style/format_string_token.rb +29 -2
  157. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  158. data/lib/rubocop/cop/style/guard_clause.rb +9 -6
  159. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +21 -5
  160. data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
  161. data/lib/rubocop/cop/style/hash_lookup_method.rb +19 -7
  162. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  163. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  164. data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
  165. data/lib/rubocop/cop/style/if_unless_modifier.rb +14 -3
  166. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
  167. data/lib/rubocop/cop/style/inline_comment.rb +4 -1
  168. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  169. data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
  170. data/lib/rubocop/cop/style/map_join.rb +123 -0
  171. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -3
  172. data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
  173. data/lib/rubocop/cop/style/module_member_existence_check.rb +7 -14
  174. data/lib/rubocop/cop/style/multiline_if_then.rb +3 -1
  175. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  176. data/lib/rubocop/cop/style/nil_comparison.rb +2 -3
  177. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  178. data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
  179. data/lib/rubocop/cop/style/not.rb +2 -0
  180. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  181. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  182. data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
  183. data/lib/rubocop/cop/style/parallel_assignment.rb +4 -0
  184. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  185. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
  186. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  187. data/lib/rubocop/cop/style/proc.rb +3 -2
  188. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  189. data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
  190. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  191. data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
  192. data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
  193. data/lib/rubocop/cop/style/redundant_each.rb +3 -3
  194. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  195. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  196. data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
  197. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  198. data/lib/rubocop/cop/style/redundant_parentheses.rb +25 -22
  199. data/lib/rubocop/cop/style/redundant_percent_q.rb +4 -1
  200. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
  201. data/lib/rubocop/cop/style/redundant_return.rb +3 -1
  202. data/lib/rubocop/cop/style/redundant_self.rb +2 -2
  203. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  204. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
  205. data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
  206. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
  207. data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
  208. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  209. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  210. data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
  211. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  212. data/lib/rubocop/cop/style/semicolon.rb +2 -0
  213. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  214. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
  215. data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
  216. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
  217. data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
  218. data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
  219. data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
  220. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  221. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
  222. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  223. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  224. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  225. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  226. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  227. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  228. data/lib/rubocop/cop/team.rb +86 -35
  229. data/lib/rubocop/cop/variable_force/branch.rb +2 -2
  230. data/lib/rubocop/directive_comment.rb +2 -1
  231. data/lib/rubocop/file_patterns.rb +9 -1
  232. data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -2
  233. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  234. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  235. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
  236. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  237. data/lib/rubocop/formatter.rb +22 -21
  238. data/lib/rubocop/lsp/diagnostic.rb +1 -0
  239. data/lib/rubocop/lsp/routes.rb +10 -3
  240. data/lib/rubocop/lsp/runtime.rb +1 -2
  241. data/lib/rubocop/mcp/server.rb +200 -0
  242. data/lib/rubocop/options.rb +35 -4
  243. data/lib/rubocop/path_util.rb +14 -2
  244. data/lib/rubocop/plugin/loader.rb +1 -1
  245. data/lib/rubocop/project_index_loader.rb +66 -0
  246. data/lib/rubocop/result_cache.rb +22 -10
  247. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  248. data/lib/rubocop/rspec/shared_contexts.rb +32 -2
  249. data/lib/rubocop/runner.rb +124 -53
  250. data/lib/rubocop/server/cache.rb +5 -7
  251. data/lib/rubocop/server/core.rb +2 -0
  252. data/lib/rubocop/target_finder.rb +14 -7
  253. data/lib/rubocop/target_ruby.rb +18 -12
  254. data/lib/rubocop/version.rb +21 -3
  255. data/lib/rubocop.rb +22 -96
  256. metadata +27 -5
@@ -16,7 +16,9 @@ module RuboCop
16
16
  'root of the project. RuboCop will use this path to determine which ' \
17
17
  'cops are enabled (via eg. Include/Exclude), and so that certain cops ' \
18
18
  'like Naming/FileName can be checked.'
19
- EXITING_OPTIONS = %i[version verbose_version show_cops show_docs_url lsp].freeze
19
+ EXITING_OPTIONS = %i[
20
+ version verbose_version show_cops list_enabled_cops_for show_docs_url lsp mcp
21
+ ].freeze
20
22
  DEFAULT_MAXIMUM_EXCLUSION_ITEMS = 15
21
23
 
22
24
  def initialize
@@ -57,6 +59,7 @@ module RuboCop
57
59
  add_check_options(opts)
58
60
  add_cache_options(opts)
59
61
  add_lsp_option(opts)
62
+ add_mcp_option(opts)
60
63
  add_server_options(opts)
61
64
  add_output_options(opts)
62
65
  add_autocorrection_options(opts)
@@ -88,6 +91,8 @@ module RuboCop
88
91
  option(opts, '-F', '--fail-fast')
89
92
  option(opts, '--disable-pending-cops')
90
93
  option(opts, '--enable-pending-cops')
94
+ option(opts, '--disable-all-cops')
95
+ option(opts, '--enable-all-cops')
91
96
  option(opts, '--ignore-disable-comments')
92
97
  option(opts, '--force-exclusion')
93
98
  option(opts, '--only-recognized-file-types')
@@ -215,6 +220,12 @@ module RuboCop
215
220
  end
216
221
  end
217
222
 
223
+ def add_mcp_option(opts)
224
+ section(opts, 'MCP Option') do
225
+ option(opts, '--mcp')
226
+ end
227
+ end
228
+
218
229
  def add_server_options(opts)
219
230
  section(opts, 'Server Options') do
220
231
  option(opts, '--[no-]server')
@@ -229,6 +240,7 @@ module RuboCop
229
240
  def add_additional_modes(opts)
230
241
  section(opts, 'Additional Modes') do
231
242
  option(opts, '-L', '--list-target-files')
243
+ option(opts, '--list-enabled-cops-for PATH')
232
244
  option(opts, '--show-cops [COP1,COP2,...]') do |list|
233
245
  @options[:show_cops] = list.nil? ? [] : list.split(',')
234
246
  end
@@ -386,6 +398,7 @@ module RuboCop
386
398
  validate_display_only_failed_and_display_only_correctable
387
399
  validate_display_only_correctable_and_autocorrect
388
400
  validate_lsp_and_editor_mode
401
+ validate_enable_all_cops_and_disable_all_cops
389
402
  disable_parallel_when_invalid_option_combo
390
403
 
391
404
  return if incompatible_options.size <= 1
@@ -439,6 +452,13 @@ module RuboCop
439
452
  raise OptionArgumentError, 'Do not specify `--editor-mode` as it is redundant in `--lsp`.'
440
453
  end
441
454
 
455
+ def validate_enable_all_cops_and_disable_all_cops
456
+ return if !@options.key?(:enable_all_cops) || !@options.key?(:disable_all_cops)
457
+
458
+ raise OptionArgumentError,
459
+ '--enable-all-cops cannot be used together with --disable-all-cops.'
460
+ end
461
+
442
462
  def validate_autocorrect
443
463
  if @options.key?(:safe_autocorrect) && @options.key?(:autocorrect_all)
444
464
  message = Rainbow(<<~MESSAGE).red
@@ -467,8 +487,7 @@ module RuboCop
467
487
  end
468
488
 
469
489
  def invalid_arguments_for_parallel
470
- [('--auto-gen-config' if @options.key?(:auto_gen_config)),
471
- ('-F/--fail-fast' if @options.key?(:fail_fast)),
490
+ [('-F/--fail-fast' if @options.key?(:fail_fast)),
472
491
  ('--profile' if @options[:profile]),
473
492
  ('--memory' if @options[:memory]),
474
493
  ('--cache false' if @options > { cache: 'false' })].compact
@@ -592,7 +611,7 @@ module RuboCop
592
611
  display_only_correctable: ['Only output correctable offense messages.'],
593
612
  display_only_safe_correctable: ['Only output safe-correctable offense messages',
594
613
  'when combined with --display-only-correctable.'],
595
- show_cops: ['Shows the given cops, or all cops by',
614
+ show_cops: ['Show the given cops, or all cops by',
596
615
  'default, and their configurations for the',
597
616
  'current directory.',
598
617
  'You can use `*` as a wildcard.'],
@@ -612,8 +631,16 @@ module RuboCop
612
631
  display_cop_names: ['Display cop names in offense messages.',
613
632
  'Default is true.'],
614
633
  disable_pending_cops: 'Run without pending cops.',
634
+ disable_all_cops: ['Run with all cops disabled by default,',
635
+ 'except `Lint/Syntax`. Overrides',
636
+ '`AllCops/EnabledByDefault` and',
637
+ '`AllCops/DisabledByDefault` in config files.'],
615
638
  display_style_guide: 'Display style guide URLs in offense messages.',
616
639
  enable_pending_cops: 'Run with pending cops.',
640
+ enable_all_cops: ['Run with all cops enabled, including those',
641
+ 'disabled by default. Overrides',
642
+ '`AllCops/EnabledByDefault` and',
643
+ '`AllCops/DisabledByDefault` in config files.'],
617
644
  extra_details: 'Display extra details in offense messages.',
618
645
  lint: 'Run only lint cops.',
619
646
  safe: 'Run only safe cops.',
@@ -621,6 +648,8 @@ module RuboCop
621
648
  'autocorrected source. This is especially useful',
622
649
  'when combined with --autocorrect and --stdin.'],
623
650
  list_target_files: 'List all files RuboCop will inspect.',
651
+ list_enabled_cops_for: ['List which cops will inspect a given file or',
652
+ 'directory.'],
624
653
  autocorrect: 'Autocorrect offenses (only when it\'s safe).',
625
654
  auto_correct: '(same, deprecated)',
626
655
  safe_auto_correct: '(same, deprecated)',
@@ -651,6 +680,8 @@ module RuboCop
651
680
  server_status: 'Show server status.',
652
681
  no_detach: 'Run the server process in the foreground.',
653
682
  lsp: 'Start a language server listening on STDIN.',
683
+ mcp: ['Start an MCP (Model Context Protocol) server that',
684
+ 'communicates over stdio.'],
654
685
  raise_cop_error: ['Raise cop-related errors with cause and location.',
655
686
  'This is used to prevent cops from failing silently.',
656
687
  'Default is false.'],
@@ -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)
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # Defensive loader for the optional `rubydex` gem.
5
+ #
6
+ # When `AllCops/UseProjectIndex` is enabled in the user's configuration, RuboCop builds
7
+ # a project-wide index using `Rubydex::Graph` and exposes it to cops that opt in.
8
+ # The gem is intentionally not a runtime dependency; if it is not installed,
9
+ # or if the running Ruby is older than what `rubydex` supports, RuboCop falls back to
10
+ # its standard file-local behavior.
11
+ module ProjectIndexLoader
12
+ MINIMUM_RUBY_VERSION = '3.2'
13
+
14
+ module_function
15
+
16
+ # Returns whether the `rubydex` gem can be loaded. The result is memoized
17
+ # for the lifetime of the process.
18
+ def available?
19
+ return @available if defined?(@available)
20
+
21
+ @available = supported_ruby? && try_require
22
+ end
23
+
24
+ def supported_ruby?
25
+ RUBY_VERSION >= MINIMUM_RUBY_VERSION
26
+ end
27
+
28
+ def warn_unavailable
29
+ return if @warned
30
+
31
+ @warned = true
32
+
33
+ if supported_ruby?
34
+ warn Rainbow(<<~MSG).yellow
35
+ `AllCops/UseProjectIndex` is enabled but the `rubydex` gem is not installed.
36
+ Analyses that use the project index will be skipped. Add `gem 'rubydex'` to your Gemfile.
37
+ MSG
38
+ else
39
+ warn Rainbow(<<~MSG).yellow
40
+ `AllCops/UseProjectIndex` is enabled but `rubydex` requires Ruby #{MINIMUM_RUBY_VERSION} or later (current: #{RUBY_VERSION}).
41
+ Analyses that use the project index will be skipped.
42
+ MSG
43
+ end
44
+ end
45
+
46
+ def try_require
47
+ require 'rubydex'
48
+ true
49
+ rescue LoadError
50
+ false
51
+ end
52
+
53
+ # Builds and resolves a `Rubydex::Graph` for the given file paths. Returns the resolved graph,
54
+ # or `nil` if the build fails. This is the only place in RuboCop that depends on the concrete
55
+ # `Rubydex::Graph` API, so callers (e.g. `Runner`) do not need to know which Rubydex classes
56
+ # or methods are involved.
57
+ def build_index(paths)
58
+ graph = Rubydex::Graph.new
59
+ graph.index_all(paths.map(&:to_s))
60
+ graph.resolve
61
+ graph
62
+ rescue StandardError => e
63
+ warn Rainbow("rubydex index build failed: #{e.message}. Continuing without it.").yellow
64
+ end
65
+ end
66
+ end
@@ -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)
@@ -196,6 +205,17 @@ module RuboCop
196
205
  end
197
206
  end
198
207
 
208
+ # Return a hash of the options given at invocation, minus the ones that have
209
+ # no effect on which offenses and disabled line ranges are found, and thus
210
+ # don't affect caching.
211
+ def relevant_options_digest(options)
212
+ @relevant_options_digest ||= {}
213
+ @relevant_options_digest[options] ||= begin
214
+ options = options.reject { |key, _| NON_CHANGING.include?(key) }
215
+ options.to_s.gsub(/[^a-z]+/i, '_')
216
+ end
217
+ end
218
+
199
219
  private
200
220
 
201
221
  def digest(path)
@@ -227,20 +247,12 @@ module RuboCop
227
247
  end
228
248
  end
229
249
 
230
- # Return a hash of the options given at invocation, minus the ones that have
231
- # no effect on which offenses and disabled line ranges are found, and thus
232
- # don't affect caching.
233
- def relevant_options_digest(options)
234
- options = options.reject { |key, _| NON_CHANGING.include?(key) }
235
- options.to_s.gsub(/[^a-z]+/i, '_')
236
- end
237
-
238
250
  # We combine team and options into a single "context" checksum to avoid
239
251
  # making file names that are too long for some filesystems to handle.
240
252
  # This context is for anything that's not (1) the RuboCop executable
241
253
  # checksum or (2) the inspected file checksum.
242
254
  def context_checksum(team, options)
243
- keys = [team.external_dependency_checksum, relevant_options_digest(options)]
255
+ keys = [team.external_dependency_checksum, self.class.relevant_options_digest(options)]
244
256
  Digest::SHA1.hexdigest(keys.join)
245
257
  end
246
258
  end
@@ -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
@@ -203,6 +212,27 @@ RSpec.shared_context 'lsp' do
203
212
  end
204
213
  end
205
214
 
215
+ RSpec.shared_context 'with exclude limit tracking' do
216
+ around do |example|
217
+ Dir.mktmpdir('rubocop-exclude-limit') do |dir|
218
+ RuboCop::ExcludeLimit.tmp_dir = Pathname.new(dir)
219
+ example.run
220
+ ensure
221
+ RuboCop::ExcludeLimit.tmp_dir = nil
222
+ end
223
+ end
224
+
225
+ # Reads exclude_limit values from the tmp files written by ExcludeLimit.
226
+ # Returns a hash like { 'Max' => 81 } or nil if no values were written.
227
+ def read_exclude_limit(cop, parameter_name = nil)
228
+ if parameter_name
229
+ read_exclude_limit(cop)[parameter_name]
230
+ else
231
+ RuboCop::ExcludeLimit.read_limits(cop.class.badge.to_s)
232
+ end
233
+ end
234
+ end
235
+
206
236
  RSpec.shared_context 'ruby 2.0' do
207
237
  # Prism supports parsing Ruby 3.3+.
208
238
  let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.0 }
@@ -62,6 +62,8 @@ module RuboCop
62
62
  @errors = []
63
63
  @warnings = []
64
64
  @aborting = false
65
+ @inspected_files = []
66
+ @report_queue = {}
65
67
  end
66
68
 
67
69
  def run(paths)
@@ -70,10 +72,11 @@ module RuboCop
70
72
  ResultCache.source_checksum
71
73
 
72
74
  target_files = find_target_files(paths)
75
+ @project_index = ProjectIndexLoader.build_index(target_files) if project_index_enabled?
76
+
73
77
  if @options[:list_target_files]
74
78
  list_files(target_files)
75
79
  else
76
- warm_cache(target_files) if @options[:parallel]
77
80
  inspect_files(target_files)
78
81
  end
79
82
  rescue Interrupt
@@ -90,21 +93,6 @@ module RuboCop
90
93
 
91
94
  private
92
95
 
93
- # Warms up the RuboCop cache by forking a suitable number of RuboCop
94
- # instances that each inspects its allotted group of files.
95
- def warm_cache(target_files)
96
- saved_options = @options.dup
97
- if target_files.length <= 1
98
- puts 'Skipping parallel inspection: only a single file needs inspection' if @options[:debug]
99
- return
100
- end
101
- puts 'Running parallel inspection' if @options[:debug]
102
- %i[autocorrect safe_autocorrect].each { |opt| @options[opt] = false }
103
- Parallel.each(target_files) { |target_file| file_offenses(target_file) }
104
- ensure
105
- @options = saved_options
106
- end
107
-
108
96
  def find_target_files(paths)
109
97
  target_finder = TargetFinder.new(@config_store, @options)
110
98
  mode = if @options[:only_recognized_file_types]
@@ -116,12 +104,26 @@ module RuboCop
116
104
  target_files.each(&:freeze).freeze
117
105
  end
118
106
 
119
- def inspect_files(files)
120
- inspected_files = []
107
+ def project_index_enabled?
108
+ return false unless @config_store.for_pwd.for_all_cops['UseProjectIndex']
121
109
 
110
+ unless ProjectIndexLoader.available?
111
+ ProjectIndexLoader.warn_unavailable
112
+ return false
113
+ end
114
+
115
+ true
116
+ end
117
+
118
+ def inspect_files(files) # rubocop:disable Metrics/AbcSize
122
119
  formatter_set.started(files)
120
+ file_iterator(files) do |file|
121
+ offenses = process_file(file)
122
+ succeeded = offenses.none? { |o| considered_failure?(o) && offense_displayed?(o) }
123
+ raise Parallel::Break if @options[:fail_fast] && !succeeded
123
124
 
124
- each_inspected_file(files) { |file| inspected_files << file }
125
+ [offenses, succeeded]
126
+ end
125
127
  ensure
126
128
  # OPTIMIZE: Calling `ResultCache.cleanup` takes time. This optimization
127
129
  # mainly targets editors that integrates RuboCop. When RuboCop is run
@@ -129,23 +131,88 @@ module RuboCop
129
131
  if files.size > 1 && cached_run?
130
132
  ResultCache.cleanup(@config_store, @options[:debug], @options[:cache_root])
131
133
  end
132
-
133
- formatter_set.finished(inspected_files.freeze)
134
+ formatter_set.finished(@inspected_files.freeze)
134
135
  formatter_set.close_output_files
135
136
  end
136
137
 
137
- def each_inspected_file(files)
138
- files.reduce(true) do |all_passed, file|
139
- offenses = process_file(file)
140
- yield file
138
+ def file_iterator(files, &block)
139
+ all_passed = true
141
140
 
142
- if offenses.any? { |o| considered_failure?(o) && offense_displayed?(o) }
143
- break false if @options[:fail_fast]
141
+ on_start = ->(file, _index) { file_started(file) }
142
+ on_finish = lambda do |file, index, (offenses, passed)|
143
+ all_passed &&= passed
144
+ finished_report(file, index, offenses)
145
+ end
144
146
 
145
- next false
146
- end
147
+ if run_in_parallel?(files)
148
+ parallel_file_iterator(files, on_start, on_finish, &block)
149
+ else
150
+ serial_file_iterator(files, on_start, on_finish, &block)
151
+ end
152
+
153
+ process_remaining_report_queue
154
+
155
+ all_passed
156
+ end
147
157
 
148
- all_passed
158
+ def finished_report(file, index, offenses)
159
+ @report_queue[index] = [file, offenses]
160
+ @next_index_to_report ||= 0
161
+ while @report_queue.key?(@next_index_to_report)
162
+ process_report_queue_entry(@next_index_to_report)
163
+ @next_index_to_report += 1
164
+ end
165
+ end
166
+
167
+ def process_report_queue_entry(index)
168
+ file, offenses = @report_queue.delete(index)
169
+ file_finished(file, offenses)
170
+ end
171
+
172
+ def process_remaining_report_queue
173
+ @report_queue.keys.sort.each do |index|
174
+ process_report_queue_entry(index)
175
+ end
176
+ end
177
+
178
+ def run_in_parallel?(files)
179
+ return false if @options[:auto_gen_config]
180
+ return false unless @options[:parallel]
181
+
182
+ if files.size <= 1
183
+ puts 'Skipping parallel inspection: only a single file needs inspection' if @options[:debug]
184
+ return false
185
+ end
186
+
187
+ return false if project_index_disables_parallel?
188
+
189
+ puts 'Running parallel inspection' if @options[:debug]
190
+
191
+ true
192
+ end
193
+
194
+ def project_index_disables_parallel?
195
+ return false if @project_index.nil? || !Gem.win_platform?
196
+
197
+ if @options[:debug]
198
+ puts 'Skipping parallel inspection: the project index is enabled and parallel ' \
199
+ 'inspection is not yet supported on Windows.'
200
+ end
201
+
202
+ true
203
+ end
204
+
205
+ def parallel_file_iterator(files, on_start, on_finish, &block)
206
+ Parallel.each(files, start: on_start, finish: on_finish, &block)
207
+ end
208
+
209
+ def serial_file_iterator(files, on_start, on_finish, &block)
210
+ files.each_with_index do |file, index|
211
+ on_start.call(file, index)
212
+ result = yield file
213
+ on_finish.call(file, index, result)
214
+ rescue Parallel::Break
215
+ break
149
216
  end
150
217
  end
151
218
 
@@ -154,16 +221,13 @@ module RuboCop
154
221
  end
155
222
 
156
223
  def process_file(file)
157
- file_started(file)
158
- offenses = file_offenses(file)
224
+ file_offenses(file)
159
225
  rescue InfiniteCorrectionLoop => e
160
226
  raise e if @options[:raise_cop_error]
161
227
 
162
228
  errors << e
163
229
  warn Rainbow(e.message).red
164
- offenses = e.offenses.compact.sort.freeze
165
- ensure
166
- file_finished(file, offenses || [])
230
+ e.offenses.compact.sort.freeze
167
231
  end
168
232
 
169
233
  def file_offenses(file)
@@ -194,7 +258,7 @@ module RuboCop
194
258
 
195
259
  if real_run_needed
196
260
  offenses = yield
197
- save_in_cache(cache, offenses)
261
+ save_in_cache(cache, offenses) unless Cop::Registry.global.warnings?(file)
198
262
  end
199
263
 
200
264
  offenses
@@ -250,6 +314,7 @@ module RuboCop
250
314
  end
251
315
 
252
316
  def file_finished(file, offenses)
317
+ @inspected_files << file
253
318
  offenses = offenses_to_report(offenses)
254
319
  formatter_set.file_finished(file, offenses)
255
320
  end
@@ -258,10 +323,6 @@ module RuboCop
258
323
  @cached_run ||=
259
324
  (@options[:cache] == 'true' ||
260
325
  (@options[:cache] != 'false' && @config_store.for_pwd.for_all_cops['UseCache'])) &&
261
- # When running --auto-gen-config, there's some processing done in the
262
- # cops related to calculating the Max parameters for Metrics cops. We
263
- # need to do that processing and cannot use caching.
264
- !@options[:auto_gen_config] &&
265
326
  # We can't cache results from code which is piped in to stdin
266
327
  !@options[:stdin]
267
328
  end
@@ -350,16 +411,9 @@ module RuboCop
350
411
 
351
412
  def inspect_file(processed_source, team = mobilize_team(processed_source))
352
413
  extracted_ruby_sources = extract_ruby_sources(processed_source)
353
- offenses = extracted_ruby_sources.flat_map do |extracted_ruby_source|
354
- report = team.investigate(
355
- extracted_ruby_source[:processed_source],
356
- offset: extracted_ruby_source[:offset],
357
- original: processed_source
358
- )
359
- @errors.concat(team.errors)
360
- @warnings.concat(team.warnings)
361
- report.offenses
362
- end
414
+ offenses = team.investigate_fragments(extracted_ruby_sources, original: processed_source)
415
+ @errors.concat(team.errors)
416
+ @warnings.concat(team.warnings)
363
417
  [offenses, team.updated_source_file?]
364
418
  end
365
419
 
@@ -379,7 +433,15 @@ module RuboCop
379
433
 
380
434
  def mobilize_team(processed_source)
381
435
  config = @config_store.for_file(processed_source.path)
382
- Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
436
+ team = Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
437
+
438
+ if @project_index
439
+ team.cops.each do |cop|
440
+ cop.project_index = @project_index
441
+ end
442
+ end
443
+
444
+ team
383
445
  end
384
446
 
385
447
  def mobilized_cop_classes(config) # rubocop:disable Metrics/AbcSize
@@ -522,8 +584,17 @@ module RuboCop
522
584
  # level caching in ResultCache.
523
585
  def standby_team(config)
524
586
  @team_by_config ||= {}.compare_by_identity
525
- @team_by_config[config] ||=
526
- Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
587
+ @team_by_config[config] ||= begin
588
+ team = Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
589
+
590
+ if @project_index
591
+ team.cops.each do |cop|
592
+ cop.project_index = @project_index
593
+ end
594
+ end
595
+
596
+ team
597
+ end
527
598
  end
528
599
  end
529
600
  end
@@ -114,13 +114,11 @@ module RuboCop
114
114
  end
115
115
 
116
116
  def acquire_lock
117
- lock_file = File.open(lock_path, File::CREAT)
118
- # flock returns 0 if successful, and false if not.
119
- flock_result = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
120
- yield flock_result != false
121
- ensure
122
- lock_file.flock(File::LOCK_UN)
123
- lock_file.close
117
+ File.open(lock_path, File::CREAT) do |lock_file|
118
+ # flock returns 0 if successful, and false if not.
119
+ flock_result = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
120
+ yield flock_result != false
121
+ end
124
122
  end
125
123
 
126
124
  def write_port_and_token_files(port:, token:)