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
@@ -24,7 +24,7 @@ module RuboCop
24
24
  include FileFinder
25
25
 
26
26
  attr_accessor :debug, :ignore_parent_exclusion, :disable_pending_cops, :enable_pending_cops,
27
- :ignore_unrecognized_cops
27
+ :enabled_by_default, :disabled_by_default, :ignore_unrecognized_cops
28
28
  attr_writer :default_configuration, :cache_root
29
29
  attr_reader :loaded_plugins, :loaded_features
30
30
 
@@ -41,6 +41,8 @@ module RuboCop
41
41
  @loaded_features = Set.new
42
42
  @disable_pending_cops = nil
43
43
  @enable_pending_cops = nil
44
+ @enabled_by_default = nil
45
+ @disabled_by_default = nil
44
46
  @ignore_parent_exclusion = nil
45
47
  @ignore_unrecognized_cops = nil
46
48
  @cache_root = nil
@@ -121,7 +123,7 @@ module RuboCop
121
123
  end
122
124
 
123
125
  def configuration_from_file(config_file, check: true)
124
- return default_configuration if config_file == DEFAULT_FILE
126
+ return apply_default_overrides(default_configuration) if config_file == DEFAULT_FILE
125
127
 
126
128
  config = load_file(config_file, check: check)
127
129
  config.validate_after_resolution if check
@@ -190,6 +192,19 @@ module RuboCop
190
192
  resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
191
193
  end
192
194
 
195
+ # Applies CLI overrides for `AllCops/EnabledByDefault` and
196
+ # `AllCops/DisabledByDefault` to the given configuration. Used when the
197
+ # configuration would otherwise be returned without going through
198
+ # `merge_with_default` (e.g. there is no user-supplied `.rubocop.yml`).
199
+ def apply_default_overrides(config)
200
+ return config if @enabled_by_default.nil? && @disabled_by_default.nil?
201
+
202
+ hash = config.transform_values do |params|
203
+ params.is_a?(Hash) ? params.merge('Enabled' => !@disabled_by_default) : params
204
+ end
205
+ Config.new(hash, config.loaded_path)
206
+ end
207
+
193
208
  # @api private
194
209
  # Used to add plugins that were required inside a config or from
195
210
  # the CLI using `--plugin`.
@@ -45,6 +45,7 @@ module RuboCop
45
45
  base_config.each do |k, v|
46
46
  next unless v.is_a?(Hash)
47
47
 
48
+ only_base_has_include = v.key?('Include') && !hash.dig(k, 'Include')
48
49
  if hash.key?(k)
49
50
  v = merge(v, hash[k],
50
51
  cop_name: k, file: file, debug: debug,
@@ -52,7 +53,7 @@ module RuboCop
52
53
  inherit_mode: determine_inherit_mode(hash, k))
53
54
  end
54
55
  hash[k] = v
55
- fix_include_paths(base_config.loaded_path, hash, path, k, v) if v.key?('Include')
56
+ fix_include_paths(base_config.loaded_path, hash, path, k, v) if only_base_has_include
56
57
  end
57
58
  end
58
59
  end
@@ -91,11 +92,11 @@ module RuboCop
91
92
  # only cops from user configuration are enabled. If
92
93
  # AllCops:EnabledByDefault is true, it changes the Enabled params so that
93
94
  # only cops explicitly disabled in user configuration are disabled.
95
+ # When the `--disable-all-cops` or `--enable-all-cops` CLI option is given,
96
+ # it takes precedence over the configuration values.
94
97
  def merge_with_default(config, config_file, unset_nil:)
95
98
  default_configuration = ConfigLoader.default_configuration
96
-
97
- disabled_by_default = config.for_all_cops['DisabledByDefault']
98
- enabled_by_default = config.for_all_cops['EnabledByDefault']
99
+ disabled_by_default, enabled_by_default = resolve_default_overrides(config)
99
100
 
100
101
  if disabled_by_default || enabled_by_default
101
102
  default_configuration = transform(default_configuration) do |params|
@@ -168,6 +169,14 @@ module RuboCop
168
169
 
169
170
  private
170
171
 
172
+ def resolve_default_overrides(config)
173
+ if ConfigLoader.disabled_by_default || ConfigLoader.enabled_by_default
174
+ [ConfigLoader.disabled_by_default, ConfigLoader.enabled_by_default]
175
+ else
176
+ [config.for_all_cops['DisabledByDefault'], config.for_all_cops['EnabledByDefault']]
177
+ end
178
+ end
179
+
171
180
  def disabled?(hash, department)
172
181
  hash[department].is_a?(Hash) && hash[department]['Enabled'] == false
173
182
  end
@@ -39,8 +39,10 @@ module RuboCop
39
39
  end
40
40
 
41
41
  def plugin_loaded?
42
- # Plugins loaded via `require` are included in `loaded_features`.
43
- config.loaded_plugins.include?(gem) || config.loaded_features.include?(gem)
42
+ # Plugins loaded via `plugins` are Plugin objects with an `about.name` attribute.
43
+ # Plugins loaded via `require` are included in `loaded_features` as strings.
44
+ config.loaded_plugins.any? { |plugin| plugin.about.name == gem } ||
45
+ config.loaded_features.include?(gem)
44
46
  end
45
47
  end
46
48
  end
@@ -36,7 +36,7 @@ module RuboCop
36
36
  end
37
37
 
38
38
  def force_default_config!
39
- @options_config = ConfigLoader.default_configuration
39
+ @options_config = ConfigLoader.apply_default_overrides(ConfigLoader.default_configuration)
40
40
  end
41
41
 
42
42
  def unvalidated
@@ -49,7 +49,7 @@ module RuboCop
49
49
  end
50
50
 
51
51
  def for_pwd
52
- for_dir(Dir.pwd)
52
+ for_dir(PathUtil.pwd)
53
53
  end
54
54
 
55
55
  # If type (file/dir) is known beforehand,
@@ -9,7 +9,7 @@ module RuboCop
9
9
 
10
10
  # @api private
11
11
  COMMON_PARAMS = %w[Exclude Include Severity inherit_mode AutoCorrect StyleGuide Details
12
- Enabled Reference References].freeze
12
+ Enabled Reference References Safe SafeAutoCorrect].freeze
13
13
  # @api private
14
14
  INTERNAL_PARAMS = %w[Description StyleGuide
15
15
  VersionAdded VersionChanged VersionRemoved
@@ -50,7 +50,8 @@ module RuboCop
50
50
 
51
51
  def disable_offense(offense_range)
52
52
  unbreakable_range = multiline_ranges(offense_range)&.find do |range|
53
- eol_comment_would_be_inside_literal?(offense_range, range)
53
+ offense_range.overlaps?(range) &&
54
+ eol_comment_would_be_inside_literal?(offense_range, range)
54
55
  end
55
56
 
56
57
  if unbreakable_range
@@ -41,6 +41,7 @@ module RuboCop
41
41
  include AutocorrectLogic
42
42
 
43
43
  attr_reader :config, :processed_source
44
+ attr_accessor :project_index
44
45
 
45
46
  # Reports of an investigation.
46
47
  # Immutable
@@ -306,7 +307,9 @@ module RuboCop
306
307
  def ready
307
308
  return self if self.class.support_multiple_source?
308
309
 
309
- self.class.new(@config, @options)
310
+ self.class.new(@config, @options).tap do |fresh|
311
+ fresh.project_index = @project_index
312
+ end
310
313
  end
311
314
 
312
315
  ### Reserved for Cop::Cop
@@ -416,7 +419,10 @@ module RuboCop
416
419
  ### Actually private methods
417
420
 
418
421
  def reset_investigation
419
- @currently_disabled_lines = @current_offenses = @processed_source = @current_corrector = nil
422
+ @currently_disabled_lines = nil
423
+ @current_offenses = nil
424
+ @processed_source = nil
425
+ @current_corrector = nil
420
426
  end
421
427
 
422
428
  # @return [Symbol, Corrector] offense status
@@ -16,7 +16,7 @@ module RuboCop
16
16
 
17
17
  def negated_condition(node)
18
18
  condition = node.condition
19
- condition = condition.children.first while condition.begin_type?
19
+ condition = condition.children.last while condition.begin_type?
20
20
  condition
21
21
  end
22
22
  end
@@ -59,11 +59,7 @@ module RuboCop
59
59
  end
60
60
 
61
61
  def content_if_comment_present(corrector, node)
62
- range = range_with_surrounding_space(
63
- children(node).last.source_range,
64
- side: :right
65
- ).end.resize(1)
66
- if range.source == '#'
62
+ if processed_source.comment_at_line(children(node).last.last_line)
67
63
  select_content_to_be_inserted_after_last_element(corrector, node)
68
64
  else
69
65
  node.loc.end.source
@@ -13,8 +13,7 @@ module RuboCop
13
13
  buffer = node.source_range.source_buffer
14
14
  corrector.remove(range_with_surrounding_space(range: node.loc.begin, buffer: buffer,
15
15
  side: :right, whitespace: true))
16
- corrector.remove(range_with_surrounding_space(range: node.loc.end, buffer: buffer,
17
- side: :left))
16
+ remove_close_paren(corrector, node, buffer)
18
17
  handle_orphaned_comma(corrector, node)
19
18
 
20
19
  return unless ternary_condition?(node) && next_char_is_question_mark?(node)
@@ -24,6 +23,38 @@ module RuboCop
24
23
 
25
24
  private
26
25
 
26
+ # When the line above `)` ends with a comment and a chained call follows `)`,
27
+ # crossing the newline would pull the chain into the comment. Preserve the newline.
28
+ def remove_close_paren(corrector, node, buffer)
29
+ newlines = !comment_above_close_paren_swallows_chain?(node, buffer)
30
+ corrector.remove(range_with_surrounding_space(range: node.loc.end, buffer: buffer,
31
+ side: :left, newlines: newlines))
32
+ end
33
+
34
+ def comment_above_close_paren_swallows_chain?(node, buffer)
35
+ last_child = node.children.last
36
+ return false unless last_child
37
+
38
+ body_end = last_child.source_range.end_pos
39
+ close_paren_begin = node.loc.end.begin_pos
40
+ return false if body_end >= close_paren_begin
41
+
42
+ source_between = buffer.source[body_end...close_paren_begin]
43
+ return false unless source_between.match?(/#[^\n]*\n/)
44
+
45
+ chained_after_close_paren?(node)
46
+ end
47
+
48
+ def chained_after_close_paren?(node)
49
+ close_paren = node.loc.end
50
+ line_text = close_paren.source_line
51
+ after_paren = line_text[(close_paren.column + 1)..]
52
+ return false if after_paren.nil?
53
+
54
+ trimmed = after_paren.lstrip
55
+ !trimmed.empty? && !trimmed.start_with?('#')
56
+ end
57
+
27
58
  def ternary_condition?(node)
28
59
  node.parent&.if_type? && node.parent.ternary?
29
60
  end
@@ -97,8 +97,8 @@ module RuboCop
97
97
  if delimiters.first != delimiters.last
98
98
  # With different delimiters (eg. `[]`, `()`), if there are the same
99
99
  # number of each, escaping is not necessary
100
- delimiter_counts = delimiters.each_with_object({}) do |delimiter, counts|
101
- counts[delimiter] = content.count(delimiter)
100
+ delimiter_counts = delimiters.to_h do |delimiter|
101
+ [delimiter, content.count(delimiter)]
102
102
  end
103
103
 
104
104
  return content if delimiter_counts[delimiters.first] == delimiter_counts[delimiters.last]
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop # rubocop:disable Style/Documentation
5
+ # Autoloads corrector classes used by cops. Classes are autoloaded to reduce the number of
6
+ # required classes because they're referenced only when autocorrection is performed.
7
+
8
+ # rubocop:disable Layout/LineLength
9
+ autoload :AlignmentCorrector, 'rubocop/cop/correctors/alignment_corrector'
10
+ autoload :ConditionCorrector, 'rubocop/cop/correctors/condition_corrector'
11
+ autoload :EachToForCorrector, 'rubocop/cop/correctors/each_to_for_corrector'
12
+ autoload :EmptyLineCorrector, 'rubocop/cop/correctors/empty_line_corrector'
13
+ autoload :ForToEachCorrector, 'rubocop/cop/correctors/for_to_each_corrector'
14
+ autoload :IfThenCorrector, 'rubocop/cop/correctors/if_then_corrector'
15
+ autoload :LambdaLiteralToMethodCorrector, 'rubocop/cop/correctors/lambda_literal_to_method_corrector'
16
+ autoload :LineBreakCorrector, 'rubocop/cop/correctors/line_break_corrector'
17
+ autoload :MultilineLiteralBraceCorrector, 'rubocop/cop/correctors/multiline_literal_brace_corrector'
18
+ autoload :OrderedGemCorrector, 'rubocop/cop/correctors/ordered_gem_corrector'
19
+ autoload :ParenthesesCorrector, 'rubocop/cop/correctors/parentheses_corrector'
20
+ autoload :PercentLiteralCorrector, 'rubocop/cop/correctors/percent_literal_corrector'
21
+ autoload :PunctuationCorrector, 'rubocop/cop/correctors/punctuation_corrector'
22
+ autoload :RequireLibraryCorrector, 'rubocop/cop/correctors/require_library_corrector'
23
+ autoload :SpaceCorrector, 'rubocop/cop/correctors/space_corrector'
24
+ autoload :StringLiteralCorrector, 'rubocop/cop/correctors/string_literal_corrector'
25
+ autoload :UnusedArgCorrector, 'rubocop/cop/correctors/unused_arg_corrector'
26
+ # rubocop:enable Layout/LineLength
27
+ end
28
+ end
@@ -55,10 +55,9 @@ module RuboCop
55
55
 
56
56
  # @api private
57
57
  def builtin?(cop_class)
58
- # any custom method will do
59
- return false unless (m = cop_class.instance_methods(false).first)
58
+ return false unless (name = cop_class.name)
60
59
 
61
- path, _line = cop_class.instance_method(m).source_location
60
+ path, _line = Module.const_source_location(name)
62
61
  path.start_with?(__dir__)
63
62
  end
64
63
  end
@@ -4,16 +4,42 @@ module RuboCop
4
4
  # Allows specified configuration options to have an exclude limit
5
5
  # ie. a maximum value tracked that it can be used by `--auto-gen-config`.
6
6
  module ExcludeLimit
7
+ class << self
8
+ attr_accessor :tmp_dir
9
+
10
+ # Reads the aggregated exclude limit values for a cop from tmp files.
11
+ # Returns a hash like { 'Max' => 81 } or an empty hash if no values were written.
12
+ def read_limits(cop_name)
13
+ cop_dir = cop_dir_for(cop_name)
14
+ return {} unless cop_dir&.directory?
15
+
16
+ limits = {}
17
+ cop_dir.children.each do |filepath|
18
+ next unless filepath.file?
19
+
20
+ values = filepath.readlines.map(&:to_i)
21
+ limits[filepath.basename.to_s] = values.max unless values.empty?
22
+ end
23
+ limits
24
+ end
25
+
26
+ # Returns the tmp directory path for a given cop, or nil if tmp_dir is not set.
27
+ def cop_dir_for(cop_name)
28
+ tmp_dir&.join(cop_name.tr('/', '-'))
29
+ end
30
+ end
31
+
7
32
  # Sets up a configuration option to have an exclude limit tracked.
8
33
  # The parameter name given is transformed into a method name (eg. `Max`
9
34
  # becomes `self.max=` and `MinDigits` becomes `self.min_digits=`).
10
35
  def exclude_limit(parameter_name, method_name: transform(parameter_name))
11
36
  define_method(:"#{method_name}=") do |value|
12
- cfg = config_to_allow_offenses
13
- cfg[:exclude_limit] ||= {}
14
- current_max = cfg[:exclude_limit][parameter_name]
15
- value = [current_max, value].max if current_max
16
- cfg[:exclude_limit][parameter_name] = value
37
+ cop_dir = RuboCop::ExcludeLimit.cop_dir_for(self.class.badge.to_s)
38
+ return unless cop_dir
39
+
40
+ cop_dir.mkpath
41
+ filepath = cop_dir.join(parameter_name)
42
+ filepath.write("#{value}\n", mode: 'a')
17
43
  end
18
44
  end
19
45
 
@@ -3,12 +3,12 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Gemspec
6
- # An attribute assignment method calls should be listed only once
6
+ # An attribute assignment method call should be listed only once
7
7
  # in a gemspec.
8
8
  #
9
9
  # Assigning to an attribute with the same name using `spec.foo =` or
10
10
  # `spec.attribute#[]=` will be an unintended usage. On the other hand,
11
- # duplication of methods such # as `spec.requirements`,
11
+ # duplication of methods such as `spec.requirements`,
12
12
  # `spec.add_runtime_dependency`, and others are permitted because it is
13
13
  # the intended use of appending values.
14
14
  #
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Requires a gemspec to have `rubygems_mfa_required` metadata set.
7
7
  #
8
8
  # This setting tells RubyGems that MFA (Multi-Factor Authentication) is
9
- # required for accounts to be able perform privileged operations, such as
9
+ # required for accounts to be able to perform privileged operations, such as
10
10
  # (see RubyGems' documentation for the full list of privileged
11
11
  # operations):
12
12
  #
@@ -70,7 +70,7 @@ module RuboCop
70
70
  def_node_matcher :metadata, <<~PATTERN
71
71
  `{
72
72
  (send _ :metadata= $_)
73
- (send (send _ :metadata) :[]= (str "rubygems_mfa_required") $_)
73
+ (send (send _ :metadata) :[]= {(str "rubygems_mfa_required") (sym :rubygems_mfa_required)} $_)
74
74
  }
75
75
  PATTERN
76
76
 
@@ -78,13 +78,13 @@ module RuboCop
78
78
  def_node_search :metadata_assignment, <<~PATTERN
79
79
  `{
80
80
  (send _ :metadata= _)
81
- (send (send _ :metadata) :[]= (str _) _)
81
+ (send (send _ :metadata) :[]= {str sym} _)
82
82
  }
83
83
  PATTERN
84
84
 
85
85
  # @!method rubygems_mfa_required(node)
86
86
  def_node_search :rubygems_mfa_required, <<~PATTERN
87
- (pair (str "rubygems_mfa_required") $_)
87
+ (pair {(str "rubygems_mfa_required") (sym :rubygems_mfa_required)} $_)
88
88
  PATTERN
89
89
 
90
90
  # @!method true_string?(node)
@@ -92,7 +92,7 @@ module RuboCop
92
92
  (str "true")
93
93
  PATTERN
94
94
 
95
- def on_block(node) # rubocop:disable Metrics/MethodLength, InternalAffairs/NumblockHandler
95
+ def on_block(node) # rubocop:disable Metrics/MethodLength, InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
96
96
  gem_specification(node) do |block_var|
97
97
  metadata_value = metadata(node)
98
98
  mfa_value = mfa_value(metadata_value)
@@ -4,10 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module Gemspec
6
6
  # Checks that `RUBY_VERSION` and `Ruby::VERSION` constants are not used in gemspec.
7
- # Using `RUBY_VERSION` and `Ruby::VERSION` are dangerous because value of the
7
+ # Using `RUBY_VERSION` and `Ruby::VERSION` is dangerous because the value of the
8
8
  # constant is determined by `rake release`.
9
- # It's possible to have dependency based on ruby version used
10
- # to execute `rake release` and not user's ruby version.
9
+ # It's possible to have a dependency based on the Ruby version used
10
+ # to execute `rake release` and not the user's Ruby version.
11
11
  #
12
12
  # @example
13
13
  #
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for missing `itblock` handlers. The blocks with the `it`
7
+ # parameter introduced in Ruby 3.4 are parsed with a node type of
8
+ # `itblock` instead of block. Cops that define `block` handlers
9
+ # need to define `itblock` handlers or disable this cop for them.
10
+ #
11
+ # @example
12
+ #
13
+ # # bad
14
+ # class BlockRelatedCop < Base
15
+ # def on_block(node)
16
+ # end
17
+ # end
18
+ #
19
+ # # good
20
+ # class BlockRelatedCop < Base
21
+ # def on_block(node)
22
+ # end
23
+ #
24
+ # alias on_itblock on_block
25
+ # end
26
+ #
27
+ # class BlockRelatedCop < Base
28
+ # def on_block(node)
29
+ # end
30
+ #
31
+ # alias_method :on_itblock, :on_block
32
+ # end
33
+ #
34
+ # class BlockRelatedCop < Base
35
+ # def on_block(node)
36
+ # end
37
+ #
38
+ # def on_itblock(node)
39
+ # end
40
+ # end
41
+ class ItblockHandler < Base
42
+ MSG = 'Define on_itblock to handle blocks with the `it` parameter.'
43
+
44
+ def on_def(node)
45
+ return unless block_handler?(node)
46
+ return unless node.parent
47
+
48
+ add_offense(node) unless itblock_handler?(node.parent)
49
+ end
50
+
51
+ private
52
+
53
+ # @!method block_handler?(node)
54
+ def_node_matcher :block_handler?, <<~PATTERN
55
+ (def :on_block (args (arg :node)) ...)
56
+ PATTERN
57
+
58
+ # @!method itblock_handler?(node)
59
+ def_node_matcher :itblock_handler?, <<~PATTERN
60
+ {
61
+ `(def :on_itblock (args (arg :node)) ...)
62
+ `(alias (sym :on_itblock) (sym :on_block))
63
+ `(send nil? :alias_method (sym :on_itblock) (sym :on_block))
64
+ }
65
+ PATTERN
66
+ end
67
+ end
68
+ end
69
+ end
@@ -25,6 +25,7 @@ module RuboCop
25
25
  def_node_matcher :line_send, <<~PATTERN
26
26
  {
27
27
  (send (send _ {:loc :source_range}) {:line :first_line})
28
+ (send (send (send _ :loc) {:begin :end}) :line)
28
29
  (send _ :first_line)
29
30
  }
30
31
  PATTERN
@@ -7,6 +7,7 @@ require_relative 'internal_affairs/empty_line_between_expect_offense_and_correct
7
7
  require_relative 'internal_affairs/example_description'
8
8
  require_relative 'internal_affairs/example_heredoc_delimiter'
9
9
  require_relative 'internal_affairs/inherit_deprecated_cop_class'
10
+ require_relative 'internal_affairs/itblock_handler'
10
11
  require_relative 'internal_affairs/lambda_or_proc'
11
12
  require_relative 'internal_affairs/location_exists'
12
13
  require_relative 'internal_affairs/location_expression'
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Check that the arguments on a multi-line method call are aligned.
6
+ # Checks that the arguments on a multi-line method call are aligned.
7
7
  #
8
8
  # @example EnforcedStyle: with_first_argument (default)
9
9
  # # good
@@ -52,7 +52,7 @@ module RuboCop
52
52
  'following the first line of a multi-line method call.'
53
53
 
54
54
  def on_send(node)
55
- return if !multiple_arguments?(node) || (node.send_type? && node.method?(:[]=)) ||
55
+ return if !multiple_arguments?(node) || (node.call_type? && node.method?(:[]=)) ||
56
56
  autocorrect_incompatible_with_other_cops?
57
57
 
58
58
  items = flattened_arguments(node)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # Check that the elements of a multi-line array literal are
6
+ # Checks that the elements of a multi-line array literal are
7
7
  # aligned.
8
8
  #
9
9
  # @example EnforcedStyle: with_first_element (default)
@@ -14,7 +14,7 @@ module RuboCop
14
14
  # `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`)
15
15
  # by default. On the other hand, `||= begin` that this cop targets tends to
16
16
  # align with the start of the line, it defaults to `EnforcedStyleAlignWith: start_of_line`.
17
- # These style can be configured by each cop.
17
+ # These styles can be configured by each cop.
18
18
  #
19
19
  # @example EnforcedStyleAlignWith: start_of_line (default)
20
20
  # # bad
@@ -49,7 +49,7 @@ module RuboCop
49
49
  # - private_methods
50
50
  # ----
51
51
  #
52
- # Instead of putting all literals in the expected order, is also
52
+ # Instead of putting all literals in the expected order, it is also
53
53
  # possible to group categories of macros. Visibility levels are handled
54
54
  # automatically.
55
55
  #
@@ -112,7 +112,7 @@ module RuboCop
112
112
  end
113
113
 
114
114
  def last_heredoc_line(node)
115
- if node.send_type?
115
+ if node.call_type?
116
116
  node.arguments.select { |arg| heredoc?(arg) }.map { |arg| arg.loc.heredoc_end.line }.max
117
117
  elsif heredoc?(node)
118
118
  node.loc.heredoc_end.line
@@ -5,8 +5,10 @@ module RuboCop
5
5
  module Layout
6
6
  # Enforces empty line after guard clause.
7
7
  #
8
- # This cop allows `# :nocov:` directive after guard clause because
9
- # SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
8
+ # This cop allows a SimpleCov directive comment after guard clause because
9
+ # SimpleCov excludes code from the coverage report by wrapping it in such directives.
10
+ # Both the legacy `# :nocov:` comment and the newer `# simplecov:disable` /
11
+ # `# simplecov:enable` comments are recognized:
10
12
  #
11
13
  # [source,ruby]
12
14
  # ----
@@ -16,6 +18,13 @@ module RuboCop
16
18
  # # :nocov:
17
19
  # bar
18
20
  # end
21
+ #
22
+ # def foo
23
+ # # simplecov:disable
24
+ # return if condition
25
+ # # simplecov:enable
26
+ # bar
27
+ # end
19
28
  # ----
20
29
  #
21
30
  # Refer to SimpleCov's documentation for more details:
@@ -58,7 +67,12 @@ module RuboCop
58
67
 
59
68
  MSG = 'Add empty line after guard clause.'
60
69
  END_OF_HEREDOC_LINE = 1
61
- SIMPLE_DIRECTIVE_COMMENT_PATTERN = /\A# *:nocov:\z/.freeze
70
+ SIMPLECOV_COMMENT_PATTERN = /\A#\s*(?::nocov:|simplecov\s*:\s*(?:disable|enable)\b)/.freeze
71
+
72
+ # @!method guard_clause_branch?(node)
73
+ def_node_matcher :guard_clause_branch?, <<~PATTERN
74
+ {(send nil? {:raise :fail} ...) return break next}
75
+ PATTERN
62
76
 
63
77
  def on_if(node)
64
78
  return if correct_style?(node)
@@ -97,14 +111,16 @@ module RuboCop
97
111
  end
98
112
 
99
113
  def correct_style?(node)
100
- !contains_guard_clause?(node) ||
114
+ !node.if_branch&.guard_clause? ||
101
115
  next_line_rescue_or_ensure?(node) ||
102
116
  next_sibling_parent_empty_or_else?(node) ||
103
117
  next_sibling_empty_or_guard_clause?(node)
104
118
  end
105
119
 
106
120
  def contains_guard_clause?(node)
107
- node.if_branch&.guard_clause?
121
+ return false unless (branch = node.if_branch)
122
+
123
+ branch.guard_clause? || guard_clause_branch?(branch)
108
124
  end
109
125
 
110
126
  def next_line_empty_or_allowed_directive_comment?(line)
@@ -206,10 +222,10 @@ module RuboCop
206
222
  parent.begin_type? && same_line?(node, node.right_sibling)
207
223
  end
208
224
 
209
- # SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
225
+ # SimpleCov excludes code from the coverage report by wrapping it in directive comments:
210
226
  # https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
211
227
  def simplecov_directive_comment?(comment)
212
- SIMPLE_DIRECTIVE_COMMENT_PATTERN.match?(comment.text)
228
+ SIMPLECOV_COMMENT_PATTERN.match?(comment.text)
213
229
  end
214
230
  end
215
231
  end
@@ -185,7 +185,7 @@ module RuboCop
185
185
  end
186
186
 
187
187
  def empty_line_between_macros
188
- cop_config.fetch('DefLikeMacros', []).map(&:to_sym)
188
+ @empty_line_between_macros ||= cop_config.fetch('DefLikeMacros', []).map(&:to_sym).freeze
189
189
  end
190
190
 
191
191
  def macro_candidate?(node)