rubocop 1.69.2 → 1.75.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 (349) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +154 -23
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +3 -1
  7. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  8. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  9. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  10. data/lib/rubocop/cli.rb +1 -1
  11. data/lib/rubocop/comment_config.rb +2 -2
  12. data/lib/rubocop/config.rb +52 -10
  13. data/lib/rubocop/config_loader.rb +52 -9
  14. data/lib/rubocop/config_loader_resolver.rb +36 -10
  15. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  16. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  17. data/lib/rubocop/config_obsoletion.rb +46 -2
  18. data/lib/rubocop/config_validator.rb +20 -9
  19. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  20. data/lib/rubocop/cop/base.rb +6 -0
  21. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  23. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  24. data/lib/rubocop/cop/internal_affairs/example_description.rb +7 -3
  25. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  26. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  27. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  28. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  29. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  30. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  31. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  32. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  33. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  34. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  35. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  36. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  37. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  38. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  39. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  40. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  41. data/lib/rubocop/cop/internal_affairs.rb +6 -16
  42. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  43. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  44. data/lib/rubocop/cop/layout/block_alignment.rb +4 -1
  45. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  46. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  47. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  48. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  49. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  50. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  51. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  52. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +28 -1
  53. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  54. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  55. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  56. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  57. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  58. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  59. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  60. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  61. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  62. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  63. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  64. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -1
  65. data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
  66. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  67. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  68. data/lib/rubocop/cop/layout/line_length.rb +9 -4
  69. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  70. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  71. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  72. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  73. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +4 -4
  74. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  75. data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -11
  76. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +2 -2
  77. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  78. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  79. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  80. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  81. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  82. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  83. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  84. data/lib/rubocop/cop/layout/space_around_operators.rb +7 -4
  85. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  86. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  87. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  88. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  89. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  90. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  91. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  92. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  93. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  94. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  95. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  96. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  97. data/lib/rubocop/cop/lint/debugger.rb +3 -3
  98. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  99. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
  100. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  101. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  102. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  103. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  104. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  105. data/lib/rubocop/cop/lint/float_comparison.rb +6 -8
  106. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  107. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +2 -2
  108. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  109. data/lib/rubocop/cop/lint/literal_as_condition.rb +103 -9
  110. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  111. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  112. data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -3
  113. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  114. data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -4
  115. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  116. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  117. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  118. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
  119. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  120. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  121. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  122. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  123. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  124. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  125. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +258 -0
  126. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  127. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  128. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  129. data/lib/rubocop/cop/lint/return_in_void_context.rb +4 -11
  130. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
  131. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
  132. data/lib/rubocop/cop/lint/shared_mutable_default.rb +76 -0
  133. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  134. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  135. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  136. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  137. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  138. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +3 -1
  139. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  140. data/lib/rubocop/cop/lint/unreachable_code.rb +2 -1
  141. data/lib/rubocop/cop/lint/unreachable_loop.rb +6 -6
  142. data/lib/rubocop/cop/lint/useless_access_modifier.rb +5 -4
  143. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  144. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  145. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  146. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  147. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  148. data/lib/rubocop/cop/lint/void.rb +12 -9
  149. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  150. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  151. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  152. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  153. data/lib/rubocop/cop/metrics/method_length.rb +9 -1
  154. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  155. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  156. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  157. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  158. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  159. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  160. data/lib/rubocop/cop/mixin/check_line_breakable.rb +13 -13
  161. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
  162. data/lib/rubocop/cop/mixin/comments_help.rb +4 -2
  163. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  164. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  165. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  166. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  167. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +22 -22
  168. data/lib/rubocop/cop/mixin/hash_subset.rb +203 -0
  169. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  170. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  171. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  172. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
  173. data/lib/rubocop/cop/mixin/range_help.rb +15 -3
  174. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  175. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  176. data/lib/rubocop/cop/mixin/string_help.rb +2 -2
  177. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  178. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  179. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -3
  180. data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
  181. data/lib/rubocop/cop/naming/method_name.rb +64 -8
  182. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  183. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  184. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  185. data/lib/rubocop/cop/registry.rb +9 -6
  186. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  187. data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
  188. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  189. data/lib/rubocop/cop/style/and_or.rb +1 -1
  190. data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
  191. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  192. data/lib/rubocop/cop/style/array_intersect.rb +39 -28
  193. data/lib/rubocop/cop/style/block_delimiters.rb +9 -21
  194. data/lib/rubocop/cop/style/class_and_module_children.rb +35 -10
  195. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  196. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  197. data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
  198. data/lib/rubocop/cop/style/commented_keyword.rb +10 -3
  199. data/lib/rubocop/cop/style/comparable_between.rb +75 -0
  200. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  201. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
  202. data/lib/rubocop/cop/style/documentation.rb +1 -1
  203. data/lib/rubocop/cop/style/double_negation.rb +4 -4
  204. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  205. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  206. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  207. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  208. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  209. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  210. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  211. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  212. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  213. data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
  214. data/lib/rubocop/cop/style/exponential_notation.rb +3 -3
  215. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  216. data/lib/rubocop/cop/style/float_division.rb +8 -4
  217. data/lib/rubocop/cop/style/for.rb +1 -0
  218. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  219. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  220. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  221. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -8
  222. data/lib/rubocop/cop/style/hash_except.rb +24 -148
  223. data/lib/rubocop/cop/style/hash_fetch_chain.rb +105 -0
  224. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  225. data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
  226. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  227. data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
  228. data/lib/rubocop/cop/style/if_unless_modifier.rb +5 -5
  229. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  230. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  231. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  232. data/lib/rubocop/cop/style/inverse_methods.rb +15 -11
  233. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  234. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  235. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  236. data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
  237. data/lib/rubocop/cop/style/keyword_parameters_order.rb +14 -8
  238. data/lib/rubocop/cop/style/lambda.rb +1 -0
  239. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  240. data/lib/rubocop/cop/style/map_into_array.rb +2 -1
  241. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  242. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  243. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +22 -15
  244. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  245. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  246. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -4
  247. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  248. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  249. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  250. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  251. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  252. data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
  253. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  254. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  255. data/lib/rubocop/cop/style/next.rb +44 -0
  256. data/lib/rubocop/cop/style/object_then.rb +14 -15
  257. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  258. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  259. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  260. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  261. data/lib/rubocop/cop/style/proc.rb +2 -2
  262. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  263. data/lib/rubocop/cop/style/raise_args.rb +14 -12
  264. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  265. data/lib/rubocop/cop/style/redundant_begin.rb +2 -1
  266. data/lib/rubocop/cop/style/redundant_condition.rb +47 -2
  267. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +16 -5
  268. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  269. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  270. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  271. data/lib/rubocop/cop/style/redundant_format.rb +257 -0
  272. data/lib/rubocop/cop/style/redundant_freeze.rb +3 -3
  273. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  274. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
  275. data/lib/rubocop/cop/style/redundant_parentheses.rb +30 -15
  276. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  277. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  278. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  279. data/lib/rubocop/cop/style/redundant_self.rb +1 -0
  280. data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
  281. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  282. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  283. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  284. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  285. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  286. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  287. data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
  288. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  289. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  290. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  291. data/lib/rubocop/cop/style/single_line_do_end_block.rb +4 -3
  292. data/lib/rubocop/cop/style/single_line_methods.rb +6 -7
  293. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  294. data/lib/rubocop/cop/style/sole_nested_conditional.rb +41 -106
  295. data/lib/rubocop/cop/style/string_concatenation.rb +2 -2
  296. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  297. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  298. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  299. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  300. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  301. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -1
  302. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  303. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  304. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  305. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  306. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  307. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  308. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  309. data/lib/rubocop/cop/util.rb +12 -5
  310. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  311. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  312. data/lib/rubocop/cop/variable_force/variable.rb +9 -2
  313. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  314. data/lib/rubocop/cop/variable_force.rb +1 -1
  315. data/lib/rubocop/cops_documentation_generator.rb +25 -14
  316. data/lib/rubocop/directive_comment.rb +45 -11
  317. data/lib/rubocop/ext/regexp_node.rb +0 -1
  318. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  319. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  320. data/lib/rubocop/lsp/logger.rb +2 -2
  321. data/lib/rubocop/lsp/routes.rb +7 -23
  322. data/lib/rubocop/lsp/runtime.rb +18 -50
  323. data/lib/rubocop/lsp/server.rb +0 -2
  324. data/lib/rubocop/lsp/stdin_runner.rb +85 -0
  325. data/lib/rubocop/options.rb +28 -12
  326. data/lib/rubocop/path_util.rb +15 -8
  327. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  328. data/lib/rubocop/plugin/load_error.rb +26 -0
  329. data/lib/rubocop/plugin/loader.rb +100 -0
  330. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  331. data/lib/rubocop/plugin.rb +46 -0
  332. data/lib/rubocop/rake_task.rb +4 -1
  333. data/lib/rubocop/result_cache.rb +13 -13
  334. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  335. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  336. data/lib/rubocop/rspec/shared_contexts.rb +39 -1
  337. data/lib/rubocop/rspec/support.rb +4 -2
  338. data/lib/rubocop/runner.rb +10 -7
  339. data/lib/rubocop/server/cache.rb +35 -2
  340. data/lib/rubocop/server/cli.rb +2 -2
  341. data/lib/rubocop/target_finder.rb +1 -0
  342. data/lib/rubocop/target_ruby.rb +16 -1
  343. data/lib/rubocop/version.rb +30 -8
  344. data/lib/rubocop.rb +16 -1
  345. data/lib/ruby_lsp/rubocop/addon.rb +75 -0
  346. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +65 -0
  347. metadata +59 -16
  348. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  349. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -3,16 +3,24 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Use a consistent style for named format string tokens.
6
+ # Use a consistent style for tokens within a format string.
7
7
  #
8
- # NOTE: `unannotated` style cop only works for strings
9
- # which are passed as arguments to those methods:
10
- # `printf`, `sprintf`, `format`, `%`.
11
- # The reason is that _unannotated_ format is very similar
12
- # to encoded URLs or Date/Time formatting strings.
8
+ # By default, all strings are evaluated. In some cases, this may be undesirable,
9
+ # as they could be used as arguments to a method that does not consider
10
+ # them to be tokens, but rather other identifiers or just part of the string.
13
11
  #
14
- # This cop's allowed methods can be customized with `AllowedMethods`.
15
- # By default, there are no allowed methods.
12
+ # `AllowedMethods` or `AllowedPatterns` can be configured with in order to mark specific
13
+ # methods as always allowed, thereby avoiding an offense from the cop. By default, there
14
+ # are no allowed methods.
15
+ #
16
+ # Additionally, the cop can be made conservative by configuring it with
17
+ # `Mode: conservative` (default `aggressive`). In this mode, tokens (regardless
18
+ # of `EnforcedStyle`) are only considered if used in the format string argument to the
19
+ # methods `printf`, `sprintf`, `format` and `%`.
20
+ #
21
+ # NOTE: Tokens in the `unannotated` style (eg. `%s`) are always treated as if
22
+ # configured with `Conservative: true`. This is done in order to prevent false positives,
23
+ # because this format is very similar to encoded URLs or Date/Time formatting strings.
16
24
  #
17
25
  # @example EnforcedStyle: annotated (default)
18
26
  #
@@ -82,6 +90,20 @@ module RuboCop
82
90
  # # good
83
91
  # redirect('foo/%{bar_id}')
84
92
  #
93
+ # @example Mode: conservative, EnforcedStyle: annotated
94
+ # # In `conservative` mode, offenses are only registered for strings
95
+ # # given to a known formatting method.
96
+ #
97
+ # # good
98
+ # "%{greeting}"
99
+ # foo("%{greeting}")
100
+ #
101
+ # # bad
102
+ # format("%{greeting}", greeting: 'Hello')
103
+ # printf("%{greeting}", greeting: 'Hello')
104
+ # sprintf("%{greeting}", greeting: 'Hello')
105
+ # "%{greeting}" % { greeting: 'Hello' }
106
+ #
85
107
  class FormatStringToken < Base
86
108
  include ConfigurableEnforcedStyle
87
109
  include AllowedMethods
@@ -153,8 +175,9 @@ module RuboCop
153
175
  corrector.replace(token_range, correction)
154
176
  end
155
177
 
156
- def unannotated_format?(node, detected_style)
157
- detected_style == :unannotated && !format_string_in_typical_context?(node)
178
+ def allowed_string?(node, detected_style)
179
+ (detected_style == :unannotated || conservative?) &&
180
+ !format_string_in_typical_context?(node)
158
181
  end
159
182
 
160
183
  def message(detected_style)
@@ -203,7 +226,7 @@ module RuboCop
203
226
  def collect_detections(node)
204
227
  detections = []
205
228
  tokens(node) do |detected_sequence, token_range|
206
- unless unannotated_format?(node, detected_sequence.style)
229
+ unless allowed_string?(node, detected_sequence.style)
207
230
  detections << [detected_sequence, token_range]
208
231
  end
209
232
  end
@@ -222,6 +245,10 @@ module RuboCop
222
245
  def max_unannotated_placeholders_allowed
223
246
  cop_config['MaxUnannotatedPlaceholdersAllowed']
224
247
  end
248
+
249
+ def conservative?
250
+ cop_config.fetch('Mode', :aggressive).to_sym == :conservative
251
+ end
225
252
  end
226
253
  end
227
254
  end
@@ -151,7 +151,7 @@ module RuboCop
151
151
 
152
152
  def frozen_string_literal_comment(processed_source)
153
153
  processed_source.tokens.find do |token|
154
- token.text.start_with?(FROZEN_STRING_LITERAL)
154
+ token.text.start_with?(FROZEN_STRING_LITERAL_REGEXP)
155
155
  end
156
156
  end
157
157
 
@@ -135,6 +135,7 @@ module RuboCop
135
135
  on_def(node)
136
136
  end
137
137
  alias on_numblock on_block
138
+ alias on_itblock on_block
138
139
 
139
140
  def on_if(node)
140
141
  return if accepted_form?(node)
@@ -213,7 +214,7 @@ module RuboCop
213
214
  if_branch = node.if_branch
214
215
  else_branch = node.else_branch
215
216
 
216
- corrector.replace(node.loc.begin, "\n") if node.loc.begin&.is?('then')
217
+ corrector.replace(node.loc.begin, "\n") if node.then?
217
218
 
218
219
  if if_branch&.send_type? && heredoc?(if_branch.last_argument)
219
220
  autocorrect_heredoc_argument(corrector, node, if_branch, else_branch, guard)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of `each_key` and `each_value` Hash methods.
6
+ # Checks for uses of `each_key` and `each_value` `Hash` methods.
7
7
  #
8
8
  # NOTE: If you have an array of two-element arrays, you can put
9
9
  # parentheses around the block arguments to indicate that you're not
@@ -44,7 +44,7 @@ module RuboCop
44
44
 
45
45
  # @!method kv_each(node)
46
46
  def_node_matcher :kv_each, <<~PATTERN
47
- ({block numblock} $(call (call _ ${:keys :values}) :each) ...)
47
+ (any_block $(call (call _ ${:keys :values}) :each) ...)
48
48
  PATTERN
49
49
 
50
50
  # @!method each_arguments(node)
@@ -74,6 +74,7 @@ module RuboCop
74
74
  check_unused_block_args(node, key, value)
75
75
  end
76
76
  alias on_numblock on_block
77
+ alias on_itblock on_block
77
78
 
78
79
  # rubocop:disable Metrics/AbcSize
79
80
  def check_unused_block_args(node, key, value)
@@ -128,8 +129,8 @@ module RuboCop
128
129
  lvar_sources = node.body.each_descendant(:lvar).map(&:source)
129
130
 
130
131
  if block_arg.mlhs_type?
131
- block_arg.each_descendant(:arg, :restarg).all? do |block_arg|
132
- lvar_sources.none?(block_arg.source.delete_prefix('*'))
132
+ block_arg.each_descendant(:arg, :restarg).all? do |descendant|
133
+ lvar_sources.none?(descendant.source.delete_prefix('*'))
133
134
  end
134
135
  else
135
136
  lvar_sources.none?(block_arg.source.delete_prefix('*'))
@@ -162,10 +163,7 @@ module RuboCop
162
163
 
163
164
  def use_array_converter_method_as_preceding?(node)
164
165
  return false unless (preceding_method = node.children.first.children.first)
165
- unless preceding_method.call_type? ||
166
- preceding_method.block_type? || preceding_method.numblock_type?
167
- return false
168
- end
166
+ return false unless preceding_method.type?(:call, :any_block)
169
167
 
170
168
  ARRAY_CONVERTER_METHODS.include?(preceding_method.method_name)
171
169
  end
@@ -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,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Use `Hash#dig` instead of chaining potentially null `fetch` calls.
7
+ #
8
+ # When `fetch(identifier, nil)` calls are chained on a hash, the expectation
9
+ # is that each step in the chain returns either `nil` or another hash,
10
+ # and in both cases, these can be simplified with a single call to `dig` with
11
+ # multiple arguments.
12
+ #
13
+ # If the 2nd parameter is `{}` or `Hash.new`, an offense will also be registered,
14
+ # as long as the final call in the chain is a nil value. If a non-nil value is given,
15
+ # the chain will not be registered as an offense, as the default value cannot be safely
16
+ # given with `dig`.
17
+ #
18
+ # NOTE: See `Style/DigChain` for replacing chains of `dig` calls with
19
+ # a single method call.
20
+ #
21
+ # @safety
22
+ # This cop is unsafe because it cannot be guaranteed that the receiver
23
+ # is a `Hash` or that `fetch` or `dig` have the expected standard implementation.
24
+ #
25
+ # @example
26
+ # # bad
27
+ # hash.fetch('foo', nil)&.fetch('bar', nil)
28
+ #
29
+ # # bad
30
+ # # earlier members of the chain can return `{}` as long as the final `fetch`
31
+ # # has `nil` as a default value
32
+ # hash.fetch('foo', {}).fetch('bar', nil)
33
+ #
34
+ # # good
35
+ # hash.dig('foo', 'bar')
36
+ #
37
+ # # ok - not handled by the cop since the final `fetch` value is non-nil
38
+ # hash.fetch('foo', {}).fetch('bar', {})
39
+ #
40
+ class HashFetchChain < Base
41
+ extend AutoCorrector
42
+ extend TargetRubyVersion
43
+ include IgnoredNode
44
+
45
+ MSG = 'Use `%<replacement>s` instead.'
46
+ RESTRICT_ON_SEND = %i[fetch].freeze
47
+
48
+ minimum_target_ruby_version 2.3
49
+
50
+ # @!method diggable?(node)
51
+ def_node_matcher :diggable?, <<~PATTERN
52
+ (call _ :fetch $_arg {nil (hash) (send (const {nil? cbase} :Hash) :new)})
53
+ PATTERN
54
+
55
+ def on_send(node)
56
+ return if ignored_node?(node)
57
+ return if last_fetch_non_nil?(node)
58
+
59
+ last_replaceable_node, arguments = inspect_chain(node)
60
+ return unless last_replaceable_node
61
+ return unless arguments.size > 1
62
+
63
+ range = last_replaceable_node.selector.join(node.loc.end)
64
+ replacement = replacement(arguments)
65
+ message = format(MSG, replacement: replacement)
66
+
67
+ add_offense(range, message: message) do |corrector|
68
+ corrector.replace(range, replacement)
69
+ end
70
+ end
71
+ alias on_csend on_send
72
+
73
+ private
74
+
75
+ def last_fetch_non_nil?(node)
76
+ # When chaining `fetch` methods, `fetch(x, {})` is acceptable within
77
+ # the chain, as long as the last method in the chain has a `nil`
78
+ # default value.
79
+
80
+ return false unless node.method?(:fetch)
81
+
82
+ !node.last_argument&.nil_type?
83
+ end
84
+
85
+ def inspect_chain(node)
86
+ arguments = []
87
+
88
+ while (arg = diggable?(node))
89
+ arguments.unshift(arg)
90
+ ignore_node(node)
91
+ last_replaceable_node = node
92
+ node = node.receiver
93
+ end
94
+
95
+ [last_replaceable_node, arguments]
96
+ end
97
+
98
+ def replacement(arguments)
99
+ values = arguments.map(&:source).join(', ')
100
+ "dig(#{values})"
101
+ end
102
+ end
103
+ end
104
+ end
105
+ 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
 
@@ -97,34 +97,31 @@ module RuboCop
97
97
  else
98
98
  correct_to_elsif_from_if_inside_else_form(corrector, node, node.condition)
99
99
  end
100
-
101
- corrector.remove(range_by_whole_lines(find_end_range(node), include_final_newline: true))
102
- return unless (if_branch = node.if_branch)
103
-
104
- range = range_by_whole_lines(if_branch.source_range, include_final_newline: true)
105
- corrector.remove(range)
106
100
  end
107
101
 
108
102
  def correct_to_elsif_from_modifier_form(corrector, node)
109
- corrector.replace(node.parent.loc.else, <<~RUBY.chop)
110
- elsif #{node.condition.source}
111
- #{indent(node.if_branch)}#{node.if_branch.source}
112
- end
113
- RUBY
103
+ corrector.replace(node.parent.loc.else, "elsif #{node.condition.source}")
104
+
105
+ condition_range = range_between(
106
+ node.if_branch.source_range.end_pos, node.condition.source_range.end_pos
107
+ )
108
+ corrector.remove(condition_range)
114
109
  end
115
110
 
116
- def correct_to_elsif_from_if_inside_else_form(corrector, node, condition)
111
+ def correct_to_elsif_from_if_inside_else_form(corrector, node, condition) # rubocop:disable Metrics/AbcSize
117
112
  corrector.replace(node.parent.loc.else, "elsif #{condition.source}")
118
113
 
119
114
  if_condition_range = if_condition_range(node, condition)
120
115
 
121
116
  if (if_branch = node.if_branch)
122
- corrector.replace(if_condition_range, if_branch.source)
117
+ corrector.replace(if_condition_range, range_with_comments(if_branch).source)
118
+ corrector.remove(range_with_comments_and_lines(if_branch))
123
119
  else
124
120
  corrector.remove(range_by_whole_lines(if_condition_range, include_final_newline: true))
125
121
  end
126
122
 
127
123
  corrector.remove(condition)
124
+ corrector.remove(range_by_whole_lines(find_end_range(node), include_final_newline: true))
128
125
  end
129
126
 
130
127
  def then?(node)