rubocop 1.69.2 → 1.71.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +36 -2
  5. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  6. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  7. data/lib/rubocop/comment_config.rb +1 -1
  8. data/lib/rubocop/config.rb +13 -4
  9. data/lib/rubocop/config_loader.rb +4 -0
  10. data/lib/rubocop/config_loader_resolver.rb +14 -3
  11. data/lib/rubocop/config_validator.rb +18 -8
  12. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  13. data/lib/rubocop/cop/base.rb +6 -0
  14. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  15. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  16. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  17. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  18. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  19. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  20. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  21. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  22. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  23. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  24. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  25. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  26. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  27. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  28. data/lib/rubocop/cop/internal_affairs.rb +4 -0
  29. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  31. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  32. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  33. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  34. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -5
  35. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  36. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  37. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  38. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  39. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  40. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  41. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  42. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  43. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  44. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  45. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
  46. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  47. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  48. data/lib/rubocop/cop/layout/line_length.rb +1 -0
  49. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  50. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  51. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  52. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  53. data/lib/rubocop/cop/layout/redundant_line_break.rb +7 -6
  54. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  55. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  56. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  57. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  58. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  59. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  60. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  61. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
  62. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  63. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  64. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  65. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  66. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  67. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  68. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  69. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  70. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  71. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  72. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  73. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  74. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  75. data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
  76. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  77. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  78. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  79. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  80. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  81. data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
  82. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  83. data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -4
  84. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  85. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  86. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  87. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
  88. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  89. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  90. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  91. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  92. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  93. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
  94. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  95. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  96. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  97. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  98. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  99. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  100. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  101. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  102. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  103. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  104. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  105. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  106. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  107. data/lib/rubocop/cop/lint/void.rb +4 -3
  108. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  109. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  110. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  111. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  112. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  113. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  114. data/lib/rubocop/cop/mixin/check_line_breakable.rb +11 -11
  115. data/lib/rubocop/cop/mixin/comments_help.rb +3 -1
  116. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  117. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  118. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
  119. data/lib/rubocop/cop/mixin/hash_subset.rb +188 -0
  120. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  121. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
  122. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  123. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  124. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  125. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  126. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
  127. data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
  128. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  129. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  130. data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
  131. data/lib/rubocop/cop/style/and_or.rb +1 -1
  132. data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
  133. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  134. data/lib/rubocop/cop/style/block_delimiters.rb +7 -20
  135. data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
  136. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  137. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  138. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  139. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  140. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
  141. data/lib/rubocop/cop/style/documentation.rb +1 -1
  142. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  143. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  144. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  145. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  146. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  147. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  148. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  149. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  150. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  151. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  152. data/lib/rubocop/cop/style/float_division.rb +8 -4
  153. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  154. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -6
  155. data/lib/rubocop/cop/style/hash_except.rb +24 -148
  156. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  157. data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
  158. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  159. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  160. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  161. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  162. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  163. data/lib/rubocop/cop/style/inverse_methods.rb +6 -6
  164. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  165. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  166. data/lib/rubocop/cop/style/map_into_array.rb +1 -1
  167. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  168. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  169. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +19 -12
  170. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  171. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  172. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  173. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  174. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  175. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  176. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  177. data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
  178. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  179. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  180. data/lib/rubocop/cop/style/object_then.rb +13 -15
  181. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  182. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  183. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  184. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  185. data/lib/rubocop/cop/style/proc.rb +1 -2
  186. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  187. data/lib/rubocop/cop/style/raise_args.rb +6 -4
  188. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  189. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  190. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  191. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  192. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  193. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  194. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  195. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  196. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  197. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
  198. data/lib/rubocop/cop/style/redundant_parentheses.rb +10 -10
  199. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  200. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  201. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  202. data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
  203. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  204. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  205. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  206. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  207. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  208. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  209. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  210. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  211. data/lib/rubocop/cop/style/single_line_methods.rb +3 -4
  212. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  213. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -2
  214. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  215. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  216. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  217. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  218. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  219. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  220. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  221. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  222. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  223. data/lib/rubocop/cop/util.rb +11 -4
  224. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  225. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  226. data/lib/rubocop/cops_documentation_generator.rb +13 -13
  227. data/lib/rubocop/directive_comment.rb +9 -8
  228. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  229. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  230. data/lib/rubocop/lsp/logger.rb +2 -2
  231. data/lib/rubocop/lsp/routes.rb +7 -23
  232. data/lib/rubocop/lsp/runtime.rb +15 -49
  233. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  234. data/lib/rubocop/options.rb +2 -1
  235. data/lib/rubocop/path_util.rb +11 -8
  236. data/lib/rubocop/result_cache.rb +13 -13
  237. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  238. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  239. data/lib/rubocop/rspec/support.rb +1 -2
  240. data/lib/rubocop/runner.rb +5 -6
  241. data/lib/rubocop/target_finder.rb +1 -0
  242. data/lib/rubocop/target_ruby.rb +15 -0
  243. data/lib/rubocop/version.rb +1 -1
  244. data/lib/rubocop.rb +6 -0
  245. data/lib/ruby_lsp/rubocop/addon.rb +78 -0
  246. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
  247. metadata +23 -11
  248. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -10,8 +10,10 @@ module RuboCop
10
10
  # (`Hash#except` was added in Ruby 3.0.)
11
11
  #
12
12
  # For safe detection, it is limited to commonly used string and symbol comparisons
13
- # when used `==`.
14
- # And do not check `Hash#delete_if` and `Hash#keep_if` to change receiver object.
13
+ # when using `==` or `!=`.
14
+ #
15
+ # This cop doesn't check for `Hash#delete_if` and `Hash#keep_if` because they
16
+ # modify the receiver.
15
17
  #
16
18
  # @safety
17
19
  # This cop is unsafe because it cannot be guaranteed that the receiver
@@ -30,6 +32,21 @@ module RuboCop
30
32
  # {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].include?(k) }
31
33
  # {foo: 1, bar: 2, baz: 3}.filter {|k, v| !%i[bar].include?(k) }
32
34
  #
35
+ # # good
36
+ # {foo: 1, bar: 2, baz: 3}.except(:bar)
37
+ #
38
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
39
+ #
40
+ # # good
41
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].exclude?(k) }
42
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].exclude?(k) }
43
+ #
44
+ # # good
45
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| k.in?(%i[bar]) }
46
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| !k.in?(%i[bar]) }
47
+ #
48
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
49
+ #
33
50
  # # bad
34
51
  # {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].exclude?(k) }
35
52
  # {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].exclude?(k) }
@@ -42,161 +59,20 @@ module RuboCop
42
59
  # {foo: 1, bar: 2, baz: 3}.except(:bar)
43
60
  #
44
61
  class HashExcept < Base
45
- include RangeHelp
62
+ include HashSubset
46
63
  extend TargetRubyVersion
47
64
  extend AutoCorrector
48
65
 
49
66
  minimum_target_ruby_version 3.0
50
67
 
51
- MSG = 'Use `%<prefer>s` instead.'
52
- RESTRICT_ON_SEND = %i[reject select filter].freeze
53
-
54
- # @!method bad_method_with_poro?(node)
55
- def_node_matcher :bad_method_with_poro?, <<~PATTERN
56
- (block
57
- (call _ _)
58
- (args
59
- $(arg _)
60
- (arg _))
61
- {
62
- $(send
63
- _ {:== :!= :eql? :include?} _)
64
- (send
65
- $(send
66
- _ {:== :!= :eql? :include?} _) :!)
67
- })
68
- PATTERN
69
-
70
- # @!method bad_method_with_active_support?(node)
71
- def_node_matcher :bad_method_with_active_support?, <<~PATTERN
72
- (block
73
- (send _ _)
74
- (args
75
- $(arg _)
76
- (arg _))
77
- {
78
- $(send
79
- _ {:== :!= :eql? :in? :include? :exclude?} _)
80
- (send
81
- $(send
82
- _ {:== :!= :eql? :in? :include? :exclude?} _) :!)
83
- })
84
- PATTERN
85
-
86
- def on_send(node)
87
- block = node.parent
88
- return unless bad_method?(block) && semantically_except_method?(node, block)
89
-
90
- except_key = except_key(block)
91
- return if except_key.nil? || !safe_to_register_offense?(block, except_key)
92
-
93
- range = offense_range(node)
94
- preferred_method = "except(#{except_key_source(except_key)})"
95
-
96
- add_offense(range, message: format(MSG, prefer: preferred_method)) do |corrector|
97
- corrector.replace(range, preferred_method)
98
- end
99
- end
100
- alias on_csend on_send
101
-
102
68
  private
103
69
 
104
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
105
- def bad_method?(block)
106
- if active_support_extensions_enabled?
107
- bad_method_with_active_support?(block) do |key_arg, send_node|
108
- if send_node.method?(:in?) && send_node.receiver&.source != key_arg.source
109
- return false
110
- end
111
- return true if !send_node.method?(:include?) && !send_node.method?(:exclude?)
112
-
113
- send_node.first_argument&.source == key_arg.source
114
- end
115
- else
116
- bad_method_with_poro?(block) do |key_arg, send_node|
117
- !send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
118
- end
119
- end
120
- end
121
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
122
-
123
- def semantically_except_method?(send, block)
124
- body = block.body
125
-
126
- negated = body.method?('!')
127
- body = body.receiver if negated
128
-
129
- case send.method_name
130
- when :reject
131
- body.method?('==') || body.method?('eql?') || included?(negated, body)
132
- when :select, :filter
133
- body.method?('!=') || not_included?(negated, body)
134
- else
135
- false
136
- end
137
- end
138
-
139
- def included?(negated, body)
140
- if negated
141
- body.method?('exclude?')
142
- else
143
- body.method?('include?') || body.method?('in?')
144
- end
145
- end
146
-
147
- def not_included?(negated, body)
148
- included?(!negated, body)
149
- end
150
-
151
- def safe_to_register_offense?(block, except_key)
152
- extracted = extract_body_if_negated(block.body)
153
- if extracted.method?('in?') || extracted.method?('include?') ||
154
- extracted.method?('exclude?')
155
- return true
156
- end
157
- return true if block.body.method?('eql?')
158
-
159
- except_key.sym_type? || except_key.str_type?
160
- end
161
-
162
- def extract_body_if_negated(body)
163
- return body unless body.method?('!')
164
-
165
- body.receiver
166
- end
167
-
168
- def except_key_source(key)
169
- if key.array_type?
170
- key = if key.percent_literal?
171
- key.each_value.map { |v| decorate_source(v) }
172
- else
173
- key.each_value.map(&:source)
174
- end
175
- return key.join(', ')
176
- end
177
-
178
- key.literal? ? key.source : "*#{key.source}"
179
- end
180
-
181
- def decorate_source(value)
182
- return ":\"#{value.source}\"" if value.dsym_type?
183
- return "\"#{value.source}\"" if value.dstr_type?
184
- return ":#{value.source}" if value.sym_type?
185
-
186
- "'#{value.source}'"
187
- end
188
-
189
- def except_key(node)
190
- key_argument = node.argument_list.first.source
191
- body = extract_body_if_negated(node.body)
192
- lhs, _method_name, rhs = *body
193
- return if [lhs, rhs].map(&:source).none?(key_argument)
194
-
195
- [lhs, rhs].find { |operand| operand.source != key_argument }
70
+ def semantically_subset_method?(node)
71
+ semantically_except_method?(node)
196
72
  end
197
73
 
198
- def offense_range(node)
199
- range_between(node.loc.selector.begin_pos, node.parent.loc.end.end_pos)
74
+ def preferred_method_name
75
+ 'except'
200
76
  end
201
77
  end
202
78
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
7
+ # that can be replaced with `Hash#slice` method.
8
+ #
9
+ # This cop should only be enabled on Ruby version 2.5 or higher.
10
+ # (`Hash#slice` was added in Ruby 2.5.)
11
+ #
12
+ # For safe detection, it is limited to commonly used string and symbol comparisons
13
+ # when using `==` or `!=`.
14
+ #
15
+ # This cop doesn't check for `Hash#delete_if` and `Hash#keep_if` because they
16
+ # modify the receiver.
17
+ #
18
+ # @safety
19
+ # This cop is unsafe because it cannot be guaranteed that the receiver
20
+ # is a `Hash` or responds to the replacement method.
21
+ #
22
+ # @example
23
+ #
24
+ # # bad
25
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| k == :bar }
26
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| k != :bar }
27
+ # {foo: 1, bar: 2, baz: 3}.filter {|k, v| k == :bar }
28
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| k.eql?(:bar) }
29
+ #
30
+ # # bad
31
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].include?(k) }
32
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].include?(k) }
33
+ # {foo: 1, bar: 2, baz: 3}.filter {|k, v| %i[bar].include?(k) }
34
+ #
35
+ # # good
36
+ # {foo: 1, bar: 2, baz: 3}.slice(:bar)
37
+ #
38
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
39
+ #
40
+ # # good
41
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].exclude?(k) }
42
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].exclude?(k) }
43
+ #
44
+ # # good
45
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| k.in?(%i[bar]) }
46
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| !k.in?(%i[bar]) }
47
+ #
48
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
49
+ #
50
+ # # bad
51
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].exclude?(k) }
52
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].exclude?(k) }
53
+ #
54
+ # # bad
55
+ # {foo: 1, bar: 2, baz: 3}.select {|k, v| k.in?(%i[bar]) }
56
+ # {foo: 1, bar: 2, baz: 3}.reject {|k, v| !k.in?(%i[bar]) }
57
+ #
58
+ # # good
59
+ # {foo: 1, bar: 2, baz: 3}.slice(:bar)
60
+ #
61
+ class HashSlice < Base
62
+ include HashSubset
63
+ extend TargetRubyVersion
64
+ extend AutoCorrector
65
+
66
+ minimum_target_ruby_version 2.5
67
+
68
+ private
69
+
70
+ def semantically_subset_method?(node)
71
+ semantically_slice_method?(node)
72
+ end
73
+
74
+ def preferred_method_name
75
+ 'slice'
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -137,6 +137,7 @@ module RuboCop
137
137
  MSG_19 = 'Use the new Ruby 1.9 hash syntax.'
138
138
  MSG_NO_MIXED_KEYS = "Don't mix styles in the same hash."
139
139
  MSG_HASH_ROCKETS = 'Use hash rockets syntax.'
140
+ NO_MIXED_KEYS_STYLES = %i[ruby19_no_mixed_keys no_mixed_keys].freeze
140
141
 
141
142
  def on_hash(node)
142
143
  pairs = node.pairs
@@ -196,7 +197,7 @@ module RuboCop
196
197
  def autocorrect(corrector, node)
197
198
  if style == :hash_rockets || force_hash_rockets?(node.parent.pairs)
198
199
  autocorrect_hash_rockets(corrector, node)
199
- elsif style == :ruby19_no_mixed_keys || style == :no_mixed_keys
200
+ elsif NO_MIXED_KEYS_STYLES.include?(style)
200
201
  autocorrect_no_mixed_keys(corrector, node)
201
202
  else
202
203
  autocorrect_ruby19(corrector, node)
@@ -208,7 +209,7 @@ module RuboCop
208
209
  end
209
210
 
210
211
  def word_symbol_pair?(pair)
211
- return false unless pair.key.sym_type? || pair.key.dsym_type?
212
+ return false unless pair.key.type?(:sym, :dsym)
212
213
 
213
214
  acceptable_19_syntax_symbol?(pair.key.source)
214
215
  end
@@ -272,7 +273,9 @@ module RuboCop
272
273
  end
273
274
 
274
275
  def argument_without_space?(node)
275
- node.argument? && node.source_range.begin_pos == node.parent.loc.selector.end_pos
276
+ return false if !node.argument? || !node.parent.loc.selector
277
+
278
+ node.source_range.begin_pos == node.parent.loc.selector.end_pos
276
279
  end
277
280
 
278
281
  def autocorrect_hash_rockets(corrector, pair_node)
@@ -203,17 +203,36 @@ module RuboCop
203
203
  corrector.remove(range)
204
204
  next if inserted_expression
205
205
 
206
- if insert_position == :after_condition
207
- corrector.insert_after(node, "\n#{expression.source}")
206
+ if node.parent&.assignment?
207
+ correct_assignment(corrector, node, expression, insert_position)
208
208
  else
209
- corrector.insert_before(node, "#{expression.source}\n")
209
+ correct_no_assignment(corrector, node, expression, insert_position)
210
210
  end
211
+
211
212
  inserted_expression = true
212
213
  end
213
214
  end
214
215
  end
215
216
  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
216
217
 
218
+ def correct_assignment(corrector, node, expression, insert_position)
219
+ if insert_position == :after_condition
220
+ assignment = node.parent.source_range.with(end_pos: node.source_range.begin_pos)
221
+ corrector.remove(assignment)
222
+ corrector.insert_after(node, "\n#{assignment.source}#{expression.source}")
223
+ else
224
+ corrector.insert_before(node.parent, "#{expression.source}\n")
225
+ end
226
+ end
227
+
228
+ def correct_no_assignment(corrector, node, expression, insert_position)
229
+ if insert_position == :after_condition
230
+ corrector.insert_after(node, "\n#{expression.source}")
231
+ else
232
+ corrector.insert_before(node, "#{expression.source}\n")
233
+ end
234
+ end
235
+
217
236
  def last_child_of_parent?(node)
218
237
  return true unless (parent = node.parent)
219
238
 
@@ -103,7 +103,7 @@ module RuboCop
103
103
 
104
104
  def defined_argument_is_undefined?(if_node, defined_node)
105
105
  defined_argument = defined_node.first_argument
106
- return false unless defined_argument.lvar_type? || defined_argument.send_type?
106
+ return false unless defined_argument.type?(:lvar, :send)
107
107
 
108
108
  if_node.left_siblings.none? do |sibling|
109
109
  sibling.respond_to?(:lvasgn_type?) && sibling.lvasgn_type? &&
@@ -112,11 +112,11 @@ module RuboCop
112
112
  end
113
113
 
114
114
  def pattern_matching_nodes(condition)
115
- if condition.match_pattern_type? || condition.match_pattern_p_type?
115
+ if condition.type?(:match_pattern, :match_pattern_p)
116
116
  [condition]
117
117
  else
118
118
  condition.each_descendant.select do |node|
119
- node.match_pattern_type? || node.match_pattern_p_type?
119
+ node.type?(:match_pattern, :match_pattern_p)
120
120
  end
121
121
  end
122
122
  end
@@ -67,7 +67,7 @@ module RuboCop
67
67
 
68
68
  # @!method if_with_boolean_literal_branches?(node)
69
69
  def_node_matcher :if_with_boolean_literal_branches?, <<~PATTERN
70
- (if #return_boolean_value? {(true) (false) | (false) (true)})
70
+ (if #return_boolean_value? <true false>)
71
71
  PATTERN
72
72
  # @!method double_negative?(node)
73
73
  def_node_matcher :double_negative?, '(send (send _ :!) :!)'
@@ -42,7 +42,7 @@ module RuboCop
42
42
  def message(node)
43
43
  template = if require_newline?(node)
44
44
  MSG_NEWLINE
45
- elsif node.else_branch&.if_type? || node.else_branch&.begin_type? ||
45
+ elsif node.else_branch&.type?(:if, :begin) ||
46
46
  use_masgn_or_block_in_branches?(node)
47
47
  MSG_IF_ELSE
48
48
  else
@@ -66,7 +66,7 @@ module RuboCop
66
66
 
67
67
  def use_masgn_or_block_in_branches?(node)
68
68
  node.branches.compact.any? do |branch|
69
- branch.masgn_type? || branch.block_type? || branch.numblock_type?
69
+ branch.type?(:masgn, :any_block)
70
70
  end
71
71
  end
72
72
 
@@ -68,7 +68,7 @@ module RuboCop
68
68
  end
69
69
 
70
70
  def autocorrect(corrector, node)
71
- if node.while_post_type? || node.until_post_type?
71
+ if node.type?(:while_post, :until_post)
72
72
  replace_begin_end_with_modifier(corrector, node)
73
73
  elsif node.modifier_form?
74
74
  replace_source(corrector, node.source_range, modifier_replacement(node))
@@ -60,18 +60,18 @@ module RuboCop
60
60
  def_node_matcher :inverse_candidate?, <<~PATTERN
61
61
  {
62
62
  (send $(call $(...) $_ $...) :!)
63
- (send ({block numblock} $(call $(...) $_) $...) :!)
63
+ (send (any_block $(call $(...) $_) $...) :!)
64
64
  (send (begin $(call $(...) $_ $...)) :!)
65
65
  }
66
66
  PATTERN
67
67
 
68
68
  # @!method inverse_block?(node)
69
69
  def_node_matcher :inverse_block?, <<~PATTERN
70
- ({block numblock} $(call (...) $_) ... { $(call ... :!)
71
- $(send (...) {:!= :!~} ...)
72
- (begin ... $(call ... :!))
73
- (begin ... $(send (...) {:!= :!~} ...))
74
- })
70
+ (any_block $(call (...) $_) ... { $(call ... :!)
71
+ $(send (...) {:!= :!~} ...)
72
+ (begin ... $(call ... :!))
73
+ (begin ... $(send (...) {:!= :!~} ...))
74
+ })
75
75
  PATTERN
76
76
 
77
77
  def on_send(node)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for assignments to a local `it` variable inside a block
7
+ # where `it` can refer to the first anonymous parameter as of Ruby 3.4.
8
+ #
9
+ # Although Ruby allows reassigning `it` in these cases, it could
10
+ # cause confusion if `it` is used as a block parameter elsewhere.
11
+ # For consistency, this also applies to numblocks and blocks with
12
+ # parameters, even though `it` cannot be used in those cases.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # foo { it = 5 }
17
+ # foo { |bar| it = bar }
18
+ # foo { it = _2 }
19
+ #
20
+ # # good - use a different variable name
21
+ # foo { var = 5 }
22
+ # foo { |bar| var = bar }
23
+ # foo { bar = _2 }
24
+ class ItAssignment < Base
25
+ MSG = '`it` is the default block parameter; consider another name.'
26
+
27
+ def on_lvasgn(node)
28
+ return unless node.name == :it
29
+ return unless node.each_ancestor(:any_block).any?
30
+
31
+ add_offense(node.loc.name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -57,7 +57,7 @@ module RuboCop
57
57
 
58
58
  def append_newline_to_last_kwoptarg(arguments, corrector)
59
59
  last_argument = arguments.last
60
- return if last_argument.kwrestarg_type? || last_argument.blockarg_type?
60
+ return if last_argument.type?(:kwrestarg, :blockarg)
61
61
 
62
62
  last_kwoptarg = arguments.reverse.find(&:kwoptarg_type?)
63
63
  corrector.insert_after(last_kwoptarg, "\n") unless arguments.parent.block_type?
@@ -72,7 +72,7 @@ module RuboCop
72
72
  def_node_matcher :each_block_with_push?, <<-PATTERN
73
73
  [
74
74
  ^({begin kwbegin block} ...)
75
- ({block numblock} (send !{nil? self} :each) _
75
+ (any_block (send !{nil? self} :each) _
76
76
  (send (lvar _) {:<< :push :append} #suitable_argument_node?))
77
77
  ]
78
78
  PATTERN
@@ -40,7 +40,7 @@ module RuboCop
40
40
  # @!method map_to_h(node)
41
41
  def_node_matcher :map_to_h, <<~PATTERN
42
42
  {
43
- $(call ({block numblock} $(call _ {:map :collect}) ...) :to_h)
43
+ $(call (any_block $(call _ {:map :collect}) ...) :to_h)
44
44
  $(call $(call _ {:map :collect} (block_pass sym)) :to_h)
45
45
  }
46
46
  PATTERN
@@ -33,8 +33,8 @@ module RuboCop
33
33
  # @!method map_to_set?(node)
34
34
  def_node_matcher :map_to_set?, <<~PATTERN
35
35
  {
36
- $(send ({block numblock} $(send _ {:map :collect}) ...) :to_set)
37
- $(send $(send _ {:map :collect} (block_pass sym)) :to_set)
36
+ $(call (any_block $(call _ {:map :collect}) ...) :to_set)
37
+ $(call $(call _ {:map :collect} (block_pass sym)) :to_set)
38
38
  }
39
39
  PATTERN
40
40
 
@@ -49,6 +49,7 @@ module RuboCop
49
49
  autocorrect(corrector, to_set_node, map_node)
50
50
  end
51
51
  end
52
+ alias on_csend on_send
52
53
 
53
54
  private
54
55
 
@@ -111,9 +111,7 @@ module RuboCop
111
111
  parent = node.parent&.block_type? ? node.parent.parent : node.parent
112
112
  return false unless parent
113
113
 
114
- parent.pair_type? ||
115
- parent.array_type? ||
116
- parent.range_type? ||
114
+ parent.type?(:pair, :array, :range) ||
117
115
  splat?(parent) ||
118
116
  ternary_if?(parent)
119
117
  end
@@ -128,46 +126,48 @@ module RuboCop
128
126
  end
129
127
 
130
128
  def call_in_optional_arguments?(node)
131
- node.parent && (node.parent.optarg_type? || node.parent.kwoptarg_type?)
129
+ node.parent&.type?(:optarg, :kwoptarg)
132
130
  end
133
131
 
134
132
  def call_in_single_line_inheritance?(node)
135
133
  node.parent&.class_type? && node.parent.single_line?
136
134
  end
137
135
 
138
- def call_with_ambiguous_arguments?(node) # rubocop:disable Metrics/PerceivedComplexity
136
+ # rubocop:disable Metrics/PerceivedComplexity
137
+ def call_with_ambiguous_arguments?(node)
139
138
  call_with_braced_block?(node) ||
140
139
  call_in_argument_with_block?(node) ||
141
140
  call_as_argument_or_chain?(node) ||
142
141
  call_in_match_pattern?(node) ||
143
142
  hash_literal_in_arguments?(node) ||
143
+ ambiguous_range_argument?(node) ||
144
144
  node.descendants.any? do |n|
145
- n.forwarded_args_type? || n.block_type? || n.numblock_type? ||
145
+ n.type?(:forwarded_args, :any_block) ||
146
146
  ambiguous_literal?(n) || logical_operator?(n)
147
147
  end
148
148
  end
149
+ # rubocop:enable Metrics/PerceivedComplexity
149
150
 
150
151
  def call_with_braced_block?(node)
151
- (node.call_type? || node.super_type?) && node.block_node&.braces?
152
+ node.type?(:call, :super) && node.block_node&.braces?
152
153
  end
153
154
 
154
155
  def call_in_argument_with_block?(node)
155
156
  parent = node.parent&.block_type? && node.parent.parent
156
157
  return false unless parent
157
158
 
158
- parent.call_type? || parent.super_type? || parent.yield_type?
159
+ parent.type?(:call, :super, :yield)
159
160
  end
160
161
 
161
162
  def call_as_argument_or_chain?(node)
162
- node.parent &&
163
- (node.parent.call_type? || node.parent.super_type? || node.parent.yield_type?) &&
163
+ node.parent&.type?(:call, :super, :yield) &&
164
164
  !assigned_before?(node.parent, node)
165
165
  end
166
166
 
167
167
  def call_in_match_pattern?(node)
168
168
  return false unless (parent = node.parent)
169
169
 
170
- parent.match_pattern_type? || parent.match_pattern_p_type?
170
+ parent.type?(:match_pattern, :match_pattern_p)
171
171
  end
172
172
 
173
173
  def hash_literal_in_arguments?(node)
@@ -177,6 +177,13 @@ module RuboCop
177
177
  end
178
178
  end
179
179
 
180
+ def ambiguous_range_argument?(node)
181
+ return true if (first_arg = node.first_argument)&.range_type? && first_arg.begin.nil?
182
+ return true if (last_arg = node.last_argument)&.range_type? && last_arg.end.nil?
183
+
184
+ false
185
+ end
186
+
180
187
  def allowed_multiline_call_with_parentheses?(node)
181
188
  cop_config['AllowParenthesesInMultilineCall'] && node.multiline?
182
189
  end
@@ -195,7 +202,7 @@ module RuboCop
195
202
  end
196
203
 
197
204
  def splat?(node)
198
- node.splat_type? || node.kwsplat_type? || node.block_pass_type?
205
+ node.type?(:splat, :kwsplat, :block_pass)
199
206
  end
200
207
 
201
208
  def ternary_if?(node)
@@ -61,6 +61,8 @@ module RuboCop
61
61
  # https://bugs.ruby-lang.org/issues/18396.
62
62
  # - Parentheses are required in anonymous arguments, keyword arguments
63
63
  # and block passing in Ruby 3.2.
64
+ # - Parentheses are required when the first argument is a beginless range or
65
+ # the last argument is an endless range.
64
66
  #
65
67
  # @example EnforcedStyle: require_parentheses (default)
66
68
  #
@@ -45,6 +45,7 @@ module RuboCop
45
45
  register_offense(node)
46
46
  end
47
47
  # rubocop:enable Metrics/CyclomaticComplexity
48
+ alias on_csend on_send
48
49
 
49
50
  private
50
51
 
@@ -100,7 +101,7 @@ module RuboCop
100
101
  # `obj.method ||= value` parses as (or-asgn (send ...) ...)
101
102
  # which IS an `asgn_node`. Similarly, `obj.method += value` parses
102
103
  # as (op-asgn (send ...) ...), which is also an `asgn_node`.
103
- next if asgn_node.shorthand_asgn? && asgn_node.lhs.send_type?
104
+ next if asgn_node.shorthand_asgn? && asgn_node.lhs.call_type?
104
105
 
105
106
  yield asgn_node
106
107
  end
@@ -40,10 +40,8 @@ module RuboCop
40
40
  def on_send(node)
41
41
  return if ignored_node?(node)
42
42
 
43
- receiver = node.receiver
44
-
45
- return unless (receiver&.block_type? || receiver&.numblock_type?) &&
46
- receiver.loc.end.is?('end')
43
+ return unless (receiver = node.receiver)
44
+ return unless receiver.any_block_type? && receiver.loc.end.is?('end')
47
45
 
48
46
  range = range_between(receiver.loc.end.begin_pos, node.source_range.end_pos)
49
47