rubocop 1.84.2 → 1.86.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +99 -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 +7 -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_resolver.rb +2 -1
  16. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  17. data/lib/rubocop/config_store.rb +1 -1
  18. data/lib/rubocop/config_validator.rb +1 -1
  19. data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
  20. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  21. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  22. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  23. data/lib/rubocop/cop/correctors.rb +28 -0
  24. data/lib/rubocop/cop/documentation.rb +2 -3
  25. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  26. data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -4
  27. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  28. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  29. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
  31. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  32. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  33. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -2
  34. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
  35. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  36. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
  37. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  38. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  39. data/lib/rubocop/cop/layout/end_alignment.rb +6 -3
  40. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
  41. data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
  42. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  43. data/lib/rubocop/cop/layout/line_length.rb +5 -3
  44. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
  45. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  46. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +53 -3
  47. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  48. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  49. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  50. data/lib/rubocop/cop/layout/space_around_keyword.rb +3 -1
  51. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -0
  52. data/lib/rubocop/cop/lint/constant_reassignment.rb +59 -9
  53. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  54. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  55. data/lib/rubocop/cop/lint/duplicate_methods.rb +55 -8
  56. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  57. data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
  58. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  59. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  60. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  61. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  62. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -1
  63. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  64. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
  65. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
  66. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
  67. data/lib/rubocop/cop/lint/require_relative_self_path.rb +2 -0
  68. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
  69. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
  70. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  71. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
  72. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  73. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  74. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  75. data/lib/rubocop/cop/lint/useless_assignment.rb +4 -9
  76. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
  77. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  78. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +35 -9
  79. data/lib/rubocop/cop/lint/void.rb +32 -12
  80. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  81. data/lib/rubocop/cop/migration/department_name.rb +12 -1
  82. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  83. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  84. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  85. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  86. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
  87. data/lib/rubocop/cop/mixin.rb +85 -0
  88. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  89. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  90. data/lib/rubocop/cop/offense.rb +8 -0
  91. data/lib/rubocop/cop/registry.rb +39 -37
  92. data/lib/rubocop/cop/security/eval.rb +15 -2
  93. data/lib/rubocop/cop/style/access_modifier_declarations.rb +14 -2
  94. data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
  95. data/lib/rubocop/cop/style/alias.rb +4 -1
  96. data/lib/rubocop/cop/style/and_or.rb +1 -0
  97. data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
  98. data/lib/rubocop/cop/style/array_join.rb +4 -2
  99. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  100. data/lib/rubocop/cop/style/attr.rb +5 -2
  101. data/lib/rubocop/cop/style/bare_percent_literals.rb +3 -1
  102. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  103. data/lib/rubocop/cop/style/block_delimiters.rb +25 -33
  104. data/lib/rubocop/cop/style/case_equality.rb +4 -0
  105. data/lib/rubocop/cop/style/class_and_module_children.rb +10 -2
  106. data/lib/rubocop/cop/style/collection_compact.rb +36 -16
  107. data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
  108. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
  109. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -4
  110. data/lib/rubocop/cop/style/copyright.rb +22 -11
  111. data/lib/rubocop/cop/style/date_time.rb +2 -2
  112. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  113. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  114. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  115. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  116. data/lib/rubocop/cop/style/empty_class_definition.rb +43 -20
  117. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  118. data/lib/rubocop/cop/style/encoding.rb +7 -1
  119. data/lib/rubocop/cop/style/end_block.rb +3 -1
  120. data/lib/rubocop/cop/style/endless_method.rb +8 -3
  121. data/lib/rubocop/cop/style/file_open.rb +84 -0
  122. data/lib/rubocop/cop/style/for.rb +3 -0
  123. data/lib/rubocop/cop/style/format_string_token.rb +29 -2
  124. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  125. data/lib/rubocop/cop/style/guard_clause.rb +9 -6
  126. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +21 -5
  127. data/lib/rubocop/cop/style/hash_lookup_method.rb +19 -7
  128. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  129. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  130. data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
  131. data/lib/rubocop/cop/style/if_unless_modifier.rb +14 -3
  132. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
  133. data/lib/rubocop/cop/style/inline_comment.rb +4 -1
  134. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  135. data/lib/rubocop/cop/style/magic_comment_format.rb +2 -2
  136. data/lib/rubocop/cop/style/map_join.rb +123 -0
  137. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -3
  138. data/lib/rubocop/cop/style/module_member_existence_check.rb +7 -14
  139. data/lib/rubocop/cop/style/multiline_if_then.rb +3 -1
  140. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  141. data/lib/rubocop/cop/style/nil_comparison.rb +2 -3
  142. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  143. data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
  144. data/lib/rubocop/cop/style/not.rb +2 -0
  145. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  146. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  147. data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
  148. data/lib/rubocop/cop/style/parallel_assignment.rb +4 -0
  149. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  150. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
  151. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  152. data/lib/rubocop/cop/style/proc.rb +3 -2
  153. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  154. data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
  155. data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
  156. data/lib/rubocop/cop/style/redundant_each.rb +3 -3
  157. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  158. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  159. data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
  160. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  161. data/lib/rubocop/cop/style/redundant_parentheses.rb +25 -22
  162. data/lib/rubocop/cop/style/redundant_percent_q.rb +4 -1
  163. data/lib/rubocop/cop/style/redundant_return.rb +3 -1
  164. data/lib/rubocop/cop/style/redundant_self.rb +2 -2
  165. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  166. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
  167. data/lib/rubocop/cop/style/regexp_literal.rb +29 -0
  168. data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
  169. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  170. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  171. data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
  172. data/lib/rubocop/cop/style/semicolon.rb +2 -0
  173. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  174. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
  175. data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
  176. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
  177. data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
  178. data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
  179. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  180. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  181. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  182. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  183. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  184. data/lib/rubocop/cop/team.rb +86 -35
  185. data/lib/rubocop/cop/variable_force/branch.rb +2 -2
  186. data/lib/rubocop/directive_comment.rb +2 -1
  187. data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -2
  188. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  189. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  190. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
  191. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  192. data/lib/rubocop/formatter.rb +22 -21
  193. data/lib/rubocop/lsp/diagnostic.rb +1 -0
  194. data/lib/rubocop/lsp/routes.rb +10 -3
  195. data/lib/rubocop/lsp/runtime.rb +1 -2
  196. data/lib/rubocop/mcp/server.rb +200 -0
  197. data/lib/rubocop/options.rb +17 -4
  198. data/lib/rubocop/path_util.rb +14 -2
  199. data/lib/rubocop/plugin/loader.rb +1 -1
  200. data/lib/rubocop/result_cache.rb +22 -10
  201. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  202. data/lib/rubocop/rspec/shared_contexts.rb +32 -2
  203. data/lib/rubocop/runner.rb +78 -51
  204. data/lib/rubocop/server/cache.rb +5 -7
  205. data/lib/rubocop/server/core.rb +2 -0
  206. data/lib/rubocop/target_finder.rb +14 -7
  207. data/lib/rubocop/target_ruby.rb +18 -12
  208. data/lib/rubocop/version.rb +2 -2
  209. data/lib/rubocop.rb +21 -96
  210. metadata +25 -5
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for `map { |x| x.to_s }.join` and similar calls where the
7
+ # `map` is redundant because `Array#join` implicitly calls `#to_s` on
8
+ # each element.
9
+ #
10
+ # @safety
11
+ # This cop is unsafe because it cannot guarantee that the receiver
12
+ # is an `Array` by static analysis. If the receiver does not have
13
+ # an `Array#join`-compatible implementation (i.e. one that calls
14
+ # `#to_s` on elements), the correction may change behavior.
15
+ #
16
+ # @example
17
+ # # bad
18
+ # array.map(&:to_s).join(', ')
19
+ #
20
+ # # bad
21
+ # array.map { |x| x.to_s }.join(', ')
22
+ #
23
+ # # bad
24
+ # array.collect(&:to_s).join
25
+ #
26
+ # # good
27
+ # array.join(', ')
28
+ #
29
+ # # good
30
+ # array.join
31
+ #
32
+ class MapJoin < Base
33
+ extend AutoCorrector
34
+ include RangeHelp
35
+
36
+ MSG = 'Remove redundant `%<method>s(&:to_s)` before `join`.'
37
+ RESTRICT_ON_SEND = %i[join].freeze
38
+
39
+ # map(&:to_s).join(...)
40
+ # @!method map_to_s_join?(node)
41
+ def_node_matcher :map_to_s_join?, <<~PATTERN
42
+ (call
43
+ $(call _ ${:map :collect} (block_pass (sym :to_s)))
44
+ :join ...)
45
+ PATTERN
46
+
47
+ # map { |x| x.to_s }.join(...)
48
+ # @!method map_to_s_block_join?(node)
49
+ def_node_matcher :map_to_s_block_join?, <<~PATTERN
50
+ (call
51
+ $(block
52
+ (call _ ${:map :collect})
53
+ (args (arg _x))
54
+ (send (lvar _x) :to_s))
55
+ :join ...)
56
+ PATTERN
57
+
58
+ # map { _1.to_s }.join(...)
59
+ # @!method map_to_s_numblock_join?(node)
60
+ def_node_matcher :map_to_s_numblock_join?, <<~PATTERN
61
+ (call
62
+ $(numblock
63
+ (call _ ${:map :collect})
64
+ 1
65
+ (send (lvar :_1) :to_s))
66
+ :join ...)
67
+ PATTERN
68
+
69
+ # map { it.to_s }.join(...)
70
+ # @!method map_to_s_itblock_join?(node)
71
+ def_node_matcher :map_to_s_itblock_join?, <<~PATTERN
72
+ (call
73
+ $(itblock
74
+ (call _ ${:map :collect})
75
+ :it
76
+ (send (lvar :it) :to_s))
77
+ :join ...)
78
+ PATTERN
79
+
80
+ def on_send(node)
81
+ map_to_s_join?(node) { |m, n| register_offense(node, m, n) } ||
82
+ map_to_s_block_join?(node) { |m, n| register_offense(node, m, n) } ||
83
+ map_to_s_numblock_join?(node) { |m, n| register_offense(node, m, n) } ||
84
+ map_to_s_itblock_join?(node) { |m, n| register_offense(node, m, n) }
85
+ end
86
+ alias on_csend on_send
87
+
88
+ private
89
+
90
+ def register_offense(join_node, map_node, method_name)
91
+ map_send = map_node.any_block_type? ? map_node.send_node : map_node
92
+ message = format(MSG, method: method_name)
93
+
94
+ add_offense(map_send.loc.selector, message: message) do |corrector|
95
+ remove_map_call(corrector, join_node, map_node, map_send)
96
+ end
97
+ end
98
+
99
+ def remove_map_call(corrector, join_node, map_node, map_send)
100
+ receiver = map_send.receiver
101
+ if receiver
102
+ corrector.replace(removal_range(receiver, map_node, map_send), '')
103
+ else
104
+ corrector.replace(no_receiver_range(map_node, join_node), '')
105
+ end
106
+ end
107
+
108
+ def removal_range(receiver, map_node, map_send)
109
+ start_pos = if receiver.last_line < map_send.loc.dot.line
110
+ receiver.source_range.end_pos
111
+ else
112
+ map_send.loc.dot.begin_pos
113
+ end
114
+ range_between(start_pos, map_node.source_range.end_pos)
115
+ end
116
+
117
+ def no_receiver_range(map_node, join_node)
118
+ range_between(map_node.source_range.begin_pos, join_node.loc.dot.end_pos)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -33,16 +33,18 @@ module RuboCop
33
33
  end
34
34
 
35
35
  def included_macros_list
36
- cop_config.fetch('IncludedMacros', []).map(&:to_sym)
36
+ @included_macros_list ||= cop_config.fetch('IncludedMacros', []).map(&:to_sym).freeze
37
37
  end
38
38
 
39
39
  def included_macro_patterns
40
- cop_config.fetch('IncludedMacroPatterns', [])
40
+ @included_macro_patterns ||=
41
+ cop_config.fetch('IncludedMacroPatterns', [])
42
+ .map { |pattern| Regexp.new(pattern) }.freeze
41
43
  end
42
44
 
43
45
  def matches_included_macro_pattern?(method_name)
44
46
  included_macro_patterns.any? do |pattern|
45
- Regexp.new(pattern).match?(method_name.to_s)
47
+ pattern.match?(method_name.to_s)
46
48
  end
47
49
  end
48
50
 
@@ -13,6 +13,12 @@ module RuboCop
13
13
  # array, while `method_defined?` will do direct method lookup, which is much
14
14
  # faster and consumes less memory.
15
15
  #
16
+ # NOTE: `constants.include?` is not handled by this cop because
17
+ # `Module#const_defined?` has different lookup behavior than
18
+ # `Module#constants` - `const_defined?` searches up to `Object`
19
+ # (top-level constants like `String`, `Integer`, etc.) while
20
+ # `constants` does not, which can cause behavior changes after autocorrection.
21
+ #
16
22
  # @example
17
23
  # # bad
18
24
  # Array.instance_methods.include?(:size)
@@ -28,27 +34,17 @@ module RuboCop
28
34
  #
29
35
  # # bad
30
36
  # Array.class_variables.include?(:foo)
31
- # Array.constants.include?(:foo)
32
37
  # Array.private_instance_methods.include?(:foo)
33
38
  # Array.protected_instance_methods.include?(:foo)
34
39
  # Array.public_instance_methods.include?(:foo)
35
- # Array.included_modules.include?(:foo)
36
40
  #
37
41
  # # good
38
42
  # Array.class_variable_defined?(:foo)
39
- # Array.const_defined?(:foo)
40
43
  # Array.private_method_defined?(:foo)
41
44
  # Array.protected_method_defined?(:foo)
42
45
  # Array.public_method_defined?(:foo)
43
- # Array.include?(:foo)
44
- #
45
- # @example AllowedMethods: [included_modules]
46
- #
47
- # # good
48
- # Array.included_modules.include?(:foo)
49
46
  #
50
47
  class ModuleMemberExistenceCheck < Base
51
- include AllowedMethods
52
48
  extend AutoCorrector
53
49
 
54
50
  MSG = 'Use `%<replacement>s` instead.'
@@ -63,15 +59,13 @@ module RuboCop
63
59
 
64
60
  METHOD_REPLACEMENTS = {
65
61
  class_variables: :class_variable_defined?,
66
- constants: :const_defined?,
67
- included_modules: :include?,
68
62
  instance_methods: :method_defined?,
69
63
  private_instance_methods: :private_method_defined?,
70
64
  protected_instance_methods: :protected_method_defined?,
71
65
  public_instance_methods: :public_method_defined?
72
66
  }.freeze
73
67
 
74
- METHODS_WITHOUT_INHERIT_PARAM = Set[:class_variables, :included_modules].freeze
68
+ METHODS_WITHOUT_INHERIT_PARAM = Set[:class_variables].freeze
75
69
  METHODS_WITH_INHERIT_PARAM =
76
70
  (METHOD_REPLACEMENTS.keys.to_set - METHODS_WITHOUT_INHERIT_PARAM).freeze
77
71
 
@@ -81,7 +75,6 @@ module RuboCop
81
75
  return unless (parent = node.parent)
82
76
  return unless module_member_inclusion?(parent)
83
77
  return unless simple_method_argument?(node) && simple_method_argument?(parent)
84
- return if allowed_method?(node.method_name)
85
78
 
86
79
  offense_range = node.location.selector.join(parent.source_range.end)
87
80
  replacement = replacement_for(node, parent)
@@ -3,7 +3,9 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of the `then` keyword in multi-line if statements.
6
+ # Checks for uses of the `then` keyword in multi-line `if` statements.
7
+ # In multi-line `if` statements, `then` is redundant because the newline
8
+ # already separates the condition from the body.
7
9
  #
8
10
  # @example
9
11
  # # bad
@@ -125,7 +125,7 @@ module RuboCop
125
125
  MSG = 'Freeze mutable objects assigned to constants.'
126
126
 
127
127
  def on_casgn(node)
128
- if node.expression.nil? # This is only the case for `CONST += ...` or similarg66
128
+ if node.expression.nil? # This is only the case for `CONST += ...` or similar
129
129
  parent = node.parent
130
130
  return unless parent.or_asgn_type? # We only care about `CONST ||= ...`
131
131
 
@@ -4,9 +4,8 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for comparison of something with nil using `==` and
7
- # `nil?`.
8
- #
9
- # Supported styles are: predicate, comparison.
7
+ # `nil?`. Enforcing a consistent style (either the `nil?`
8
+ # predicate or `==` comparison) improves readability.
10
9
  #
11
10
  # @example EnforcedStyle: predicate (default)
12
11
  #
@@ -43,7 +43,7 @@ module RuboCop
43
43
  { ({return next break} nil) (nil) }
44
44
  PATTERN
45
45
 
46
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
46
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
47
47
  return unless node.lambda_or_proc?
48
48
  return unless nil_return?(node.body)
49
49
 
@@ -121,17 +121,11 @@ module RuboCop
121
121
  end
122
122
 
123
123
  def autocorrect_comparison(corrector, node)
124
- expr = node.source
125
-
126
- new_code = if include_semantic_changes?
127
- expr.sub(/\s*!=\s*nil/, '')
128
- else
129
- expr.sub(/^(\S*)\s*!=\s*nil/, '!\1.nil?')
130
- end
131
-
132
- return if expr == new_code
133
-
134
- corrector.replace(node, new_code)
124
+ if include_semantic_changes?
125
+ corrector.replace(node, node.receiver.source)
126
+ else
127
+ corrector.replace(node, "!#{node.receiver.source}.nil?")
128
+ end
135
129
  end
136
130
 
137
131
  def autocorrect_non_nil(corrector, node, inner_node)
@@ -4,6 +4,8 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for uses of the keyword `not` instead of `!`.
7
+ # The `not` keyword has lower precedence than `!`, which can
8
+ # lead to surprising behavior and often requires parentheses.
7
9
  #
8
10
  # @example
9
11
  #
@@ -4,7 +4,8 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for big numeric literals without `_` between groups
7
- # of digits in them.
7
+ # of digits in them. Underscores make large numbers easier to
8
+ # read by visually separating groups of digits.
8
9
  #
9
10
  # Additional allowed patterns can be added by adding regexps to
10
11
  # the `AllowedPatterns` configuration. All regexps are treated
@@ -116,7 +117,7 @@ module RuboCop
116
117
  end
117
118
 
118
119
  def allowed_numbers
119
- cop_config.fetch('AllowedNumbers', []).map(&:to_s)
120
+ @allowed_numbers ||= cop_config.fetch('AllowedNumbers', []).map(&:to_s).freeze
120
121
  end
121
122
 
122
123
  def allowed_patterns
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks that each source file defines at most one top-level class or module.
7
+ #
8
+ # Keeping one class or module per file makes it easier to find and navigate
9
+ # code, and follows the convention used by most Ruby projects.
10
+ #
11
+ # Classes and modules listed in `AllowedClasses` are not counted toward the
12
+ # limit. This is useful for small ancillary classes like custom exception
13
+ # classes that logically belong with the main class.
14
+ #
15
+ # @example
16
+ # # bad - Multiple top-level classes
17
+ # class Foo
18
+ # end
19
+ #
20
+ # class Bar
21
+ # end
22
+ #
23
+ # # bad - Multiple top-level modules
24
+ # module Foo
25
+ # end
26
+ #
27
+ # module Bar
28
+ # end
29
+ #
30
+ # # bad - A top-level class and a top-level module
31
+ # class Foo
32
+ # end
33
+ #
34
+ # module Bar
35
+ # end
36
+ #
37
+ # # good - A single top-level class
38
+ # class Foo
39
+ # end
40
+ #
41
+ # # good - A single top-level module
42
+ # module Foo
43
+ # end
44
+ #
45
+ # # good - Nested classes within a single top-level class
46
+ # class Foo
47
+ # class Bar
48
+ # end
49
+ # end
50
+ #
51
+ # # good - Multiple classes within a single top-level module
52
+ # module Foo
53
+ # class Bar
54
+ # end
55
+ #
56
+ # class Baz
57
+ # end
58
+ # end
59
+ #
60
+ # @example AllowedClasses: ['AllowedClass']
61
+ # # good
62
+ # class Foo
63
+ # end
64
+ #
65
+ # class AllowedClass
66
+ # end
67
+ #
68
+ class OneClassPerFile < Base
69
+ include RangeHelp
70
+
71
+ MSG = 'Do not define multiple classes/modules at the top level in a single file.'
72
+
73
+ def on_new_investigation
74
+ @top_level_definitions = []
75
+ end
76
+
77
+ def on_class(node)
78
+ check_top_level(node)
79
+ end
80
+
81
+ def on_module(node)
82
+ check_top_level(node)
83
+ end
84
+
85
+ private
86
+
87
+ def check_top_level(node)
88
+ return unless top_level_definition?(node)
89
+ return if allowed_class?(node)
90
+
91
+ @top_level_definitions << node
92
+ return unless @top_level_definitions.length > 1
93
+
94
+ add_offense(range_between(node.source_range.begin_pos, node.loc.name.end_pos))
95
+ end
96
+
97
+ def top_level_definition?(node)
98
+ if node.parent&.begin_type?
99
+ node.parent.root?
100
+ else
101
+ node.root?
102
+ end
103
+ end
104
+
105
+ def allowed_class?(node)
106
+ allowed_classes.include?(node.identifier.short_name)
107
+ end
108
+
109
+ def allowed_classes
110
+ @allowed_classes ||= cop_config.fetch('AllowedClasses', []).map(&:intern)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -3,9 +3,10 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of if/then/else/end constructs on a single line.
7
- # `AlwaysCorrectToMultiline` config option can be set to true to autocorrect all offenses to
8
- # multi-line constructs. When `AlwaysCorrectToMultiline` is false (default case) the
6
+ # Checks for uses of `if/then/else/end` constructs on a single line.
7
+ # A ternary operator (`?:`) or multi-line `if` is more readable.
8
+ # `AlwaysCorrectToMultiline` config option can be set to `true` to autocorrect all offenses to
9
+ # multi-line constructs. When `AlwaysCorrectToMultiline` is `false` (default case) the
9
10
  # autocorrect will first try converting them to ternary operators.
10
11
  #
11
12
  # @example
@@ -4,6 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for simple usages of parallel assignment.
7
+ # Parallel assignment is less readable than individual
8
+ # assignments and makes it harder to follow what each
9
+ # variable is being set to.
10
+ #
7
11
  # This will only complain when the number of variables
8
12
  # being assigned matched the number of assigning variables.
9
13
  #