rubocop 1.71.2 → 1.75.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 (205) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +118 -21
  4. data/config/internal_affairs.yml +20 -0
  5. data/config/obsoletion.yml +3 -1
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  7. data/lib/rubocop/cli.rb +1 -1
  8. data/lib/rubocop/comment_config.rb +1 -1
  9. data/lib/rubocop/config.rb +39 -6
  10. data/lib/rubocop/config_loader.rb +48 -9
  11. data/lib/rubocop/config_loader_resolver.rb +24 -9
  12. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
  13. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  14. data/lib/rubocop/config_obsoletion.rb +46 -2
  15. data/lib/rubocop/config_validator.rb +2 -1
  16. data/lib/rubocop/cop/internal_affairs/example_description.rb +7 -3
  17. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  18. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
  19. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +2 -1
  20. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
  21. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  22. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  23. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  24. data/lib/rubocop/cop/internal_affairs.rb +2 -16
  25. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  26. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  27. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  28. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  29. data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
  30. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  31. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +3 -3
  32. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +27 -1
  33. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
  34. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  35. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  36. data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
  37. data/lib/rubocop/cop/layout/line_length.rb +8 -4
  38. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
  39. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  40. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  41. data/lib/rubocop/cop/layout/redundant_line_break.rb +9 -5
  42. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -5
  43. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  44. data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
  45. data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
  46. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
  47. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  48. data/lib/rubocop/cop/lint/debugger.rb +2 -2
  49. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  50. data/lib/rubocop/cop/lint/duplicate_methods.rb +2 -17
  51. data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
  52. data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
  53. data/lib/rubocop/cop/lint/float_comparison.rb +1 -6
  54. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  55. data/lib/rubocop/cop/lint/literal_as_condition.rb +103 -9
  56. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  57. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  58. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
  59. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  60. data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
  61. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  62. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +261 -0
  63. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
  64. data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
  65. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  66. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +8 -1
  67. data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
  68. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  69. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  70. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
  71. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  72. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  73. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -0
  74. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  75. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -0
  76. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +71 -0
  77. data/lib/rubocop/cop/lint/void.rb +7 -0
  78. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  79. data/lib/rubocop/cop/metrics/method_length.rb +1 -0
  80. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  81. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  82. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  83. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  84. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  85. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
  86. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  87. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  88. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
  89. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  90. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
  91. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +0 -1
  92. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +18 -18
  93. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
  94. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  95. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
  96. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  97. data/lib/rubocop/cop/mixin/range_help.rb +15 -3
  98. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  99. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  100. data/lib/rubocop/cop/mixin/trailing_comma.rb +12 -0
  101. data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
  102. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  103. data/lib/rubocop/cop/naming/method_name.rb +64 -8
  104. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  105. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  106. data/lib/rubocop/cop/registry.rb +9 -6
  107. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  108. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  109. data/lib/rubocop/cop/style/array_intersect.rb +39 -28
  110. data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
  111. data/lib/rubocop/cop/style/class_and_module_children.rb +29 -7
  112. data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
  113. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  114. data/lib/rubocop/cop/style/combinable_loops.rb +1 -0
  115. data/lib/rubocop/cop/style/commented_keyword.rb +10 -3
  116. data/lib/rubocop/cop/style/comparable_between.rb +75 -0
  117. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -0
  118. data/lib/rubocop/cop/style/double_negation.rb +2 -2
  119. data/lib/rubocop/cop/style/empty_literal.rb +4 -0
  120. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  121. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  122. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  123. data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
  124. data/lib/rubocop/cop/style/for.rb +1 -0
  125. data/lib/rubocop/cop/style/format_string_token.rb +38 -11
  126. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
  127. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  128. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  129. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -2
  130. data/lib/rubocop/cop/style/hash_fetch_chain.rb +105 -0
  131. data/lib/rubocop/cop/style/hash_syntax.rb +3 -0
  132. data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
  133. data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -2
  134. data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
  135. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  136. data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
  137. data/lib/rubocop/cop/style/it_block_parameter.rb +100 -0
  138. data/lib/rubocop/cop/style/keyword_parameters_order.rb +13 -7
  139. data/lib/rubocop/cop/style/lambda.rb +1 -0
  140. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  141. data/lib/rubocop/cop/style/map_into_array.rb +1 -0
  142. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -4
  143. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  144. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  145. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
  146. data/lib/rubocop/cop/style/next.rb +44 -0
  147. data/lib/rubocop/cop/style/object_then.rb +1 -0
  148. data/lib/rubocop/cop/style/proc.rb +1 -0
  149. data/lib/rubocop/cop/style/raise_args.rb +8 -8
  150. data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
  151. data/lib/rubocop/cop/style/redundant_condition.rb +57 -0
  152. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
  153. data/lib/rubocop/cop/style/redundant_format.rb +257 -0
  154. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  155. data/lib/rubocop/cop/style/redundant_parentheses.rb +20 -5
  156. data/lib/rubocop/cop/style/redundant_self.rb +1 -0
  157. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  158. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  159. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
  160. data/lib/rubocop/cop/style/return_nil.rb +2 -2
  161. data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
  162. data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
  163. data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
  164. data/lib/rubocop/cop/style/sole_nested_conditional.rb +41 -106
  165. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  166. data/lib/rubocop/cop/style/super_arguments.rb +1 -2
  167. data/lib/rubocop/cop/style/symbol_proc.rb +2 -0
  168. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -0
  169. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  170. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  171. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  172. data/lib/rubocop/cop/util.rb +2 -2
  173. data/lib/rubocop/cop/utils/format_string.rb +10 -5
  174. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  175. data/lib/rubocop/cop/variable_force/variable.rb +2 -7
  176. data/lib/rubocop/cop/variable_force.rb +1 -1
  177. data/lib/rubocop/cops_documentation_generator.rb +12 -1
  178. data/lib/rubocop/directive_comment.rb +36 -3
  179. data/lib/rubocop/ext/regexp_node.rb +0 -1
  180. data/lib/rubocop/lsp/runtime.rb +6 -4
  181. data/lib/rubocop/lsp/server.rb +0 -2
  182. data/lib/rubocop/lsp/stdin_runner.rb +3 -1
  183. data/lib/rubocop/magic_comment.rb +8 -0
  184. data/lib/rubocop/options.rb +26 -11
  185. data/lib/rubocop/path_util.rb +4 -0
  186. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  187. data/lib/rubocop/plugin/load_error.rb +26 -0
  188. data/lib/rubocop/plugin/loader.rb +100 -0
  189. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  190. data/lib/rubocop/plugin.rb +46 -0
  191. data/lib/rubocop/rake_task.rb +4 -1
  192. data/lib/rubocop/rspec/cop_helper.rb +13 -1
  193. data/lib/rubocop/rspec/shared_contexts.rb +35 -0
  194. data/lib/rubocop/rspec/support.rb +3 -0
  195. data/lib/rubocop/runner.rb +5 -1
  196. data/lib/rubocop/server/cache.rb +47 -11
  197. data/lib/rubocop/server/cli.rb +2 -2
  198. data/lib/rubocop/target_finder.rb +1 -1
  199. data/lib/rubocop/target_ruby.rb +1 -1
  200. data/lib/rubocop/version.rb +30 -8
  201. data/lib/rubocop.rb +10 -1
  202. data/lib/ruby_lsp/rubocop/addon.rb +7 -10
  203. data/lib/ruby_lsp/rubocop/{wraps_built_in_lsp_runtime.rb → runtime_adapter.rb} +25 -10
  204. metadata +43 -12
  205. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
@@ -57,6 +57,7 @@ module RuboCop
57
57
  check_code_length(node)
58
58
  end
59
59
  alias on_numblock on_block
60
+ alias on_itblock on_block
60
61
 
61
62
  private
62
63
 
@@ -63,6 +63,7 @@ module RuboCop
63
63
  check_code_length(node)
64
64
  end
65
65
  alias on_numblock on_block
66
+ alias on_itblock on_block
66
67
 
67
68
  private
68
69
 
@@ -145,7 +145,7 @@ module RuboCop
145
145
 
146
146
  def extract_body(node)
147
147
  case node.type
148
- when :class, :module, :sclass, :block, :numblock, :def, :defs
148
+ when :class, :module, :sclass, :block, :numblock, :itblock, :def, :defs
149
149
  node.body
150
150
  when :casgn
151
151
  extract_body(node.expression)
@@ -26,6 +26,13 @@ module RuboCop
26
26
  extend NodePattern::Macros
27
27
  include RuboCop::AST::Sexp
28
28
 
29
+ VAR_SETTER_TO_GETTER = {
30
+ lvasgn: :lvar,
31
+ ivasgn: :ivar,
32
+ cvasgn: :cvar,
33
+ gvasgn: :gvar
34
+ }.freeze
35
+
29
36
  # Plug into the calculator
30
37
  def initialize(node, discount_repeated_attributes: false)
31
38
  super(node)
@@ -114,13 +121,6 @@ module RuboCop
114
121
  calls.fetch(value) { yield [calls, value] }
115
122
  end
116
123
 
117
- VAR_SETTER_TO_GETTER = {
118
- lvasgn: :lvar,
119
- ivasgn: :ivar,
120
- cvasgn: :cvar,
121
- gvasgn: :gvar
122
- }.freeze
123
-
124
124
  # @returns `[receiver, method | nil]` for the given setter `node`
125
125
  # or `nil` if it is not a setter.
126
126
  def setter_to_getter(node)
@@ -5,10 +5,10 @@ module RuboCop
5
5
  # This module checks for nodes that should be aligned to the left or right.
6
6
  # This amount is determined by the instance variable @column_delta.
7
7
  module Alignment
8
- private
9
-
10
8
  SPACE = ' '
11
9
 
10
+ private
11
+
12
12
  attr_reader :column_delta
13
13
 
14
14
  def configured_indentation_width
@@ -18,12 +18,12 @@ module RuboCop
18
18
  end
19
19
 
20
20
  # @deprecated Use allowed_line? instead
21
- def ignored_line?
21
+ def ignored_line?(line)
22
22
  warn Rainbow(<<~WARNING).yellow, uplevel: 1
23
23
  `ignored_line?` is deprecated. Use `allowed_line?` instead.
24
24
  WARNING
25
25
 
26
- allowed_line?
26
+ allowed_line?(line)
27
27
  end
28
28
 
29
29
  def matches_allowed_pattern?(line)
@@ -31,12 +31,12 @@ module RuboCop
31
31
  end
32
32
 
33
33
  # @deprecated Use matches_allowed_pattern? instead
34
- def matches_ignored_pattern?
34
+ def matches_ignored_pattern?(line)
35
35
  warn Rainbow(<<~WARNING).yellow, uplevel: 1
36
36
  `matches_ignored_pattern?` is deprecated. Use `matches_allowed_pattern?` instead.
37
37
  WARNING
38
38
 
39
- matches_allowed_pattern?
39
+ matches_allowed_pattern?(line)
40
40
  end
41
41
 
42
42
  def allowed_patterns
@@ -48,7 +48,7 @@ module RuboCop
48
48
 
49
49
  args = process_args(node.arguments)
50
50
  return extract_breakable_node_from_elements(node, args, max)
51
- elsif node.def_type?
51
+ elsif node.any_def_type?
52
52
  return extract_breakable_node_from_elements(node, node.arguments, max)
53
53
  elsif node.type?(:array, :hash)
54
54
  return extract_breakable_node_from_elements(node, node.children, max)
@@ -220,7 +220,7 @@ module RuboCop
220
220
 
221
221
  # @api private
222
222
  def already_on_multiple_lines?(node)
223
- return node.first_line != node.last_argument.last_line if node.def_type?
223
+ return node.first_line != node.last_argument.last_line if node.any_def_type?
224
224
 
225
225
  !node.single_line?
226
226
  end
@@ -35,12 +35,12 @@ module RuboCop
35
35
  comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
36
36
 
37
37
  comment_line_numbers.any? do |comment_line_number|
38
- comment_line_number >= node.first_line && comment_line_number <= node.last_line
38
+ comment_line_number.between?(node.first_line, node.last_line)
39
39
  end
40
40
  end
41
41
 
42
42
  def safe_to_split?(node)
43
- node.each_descendant(:if, :case, :kwbegin, :def, :defs).none? &&
43
+ node.each_descendant(:if, :case, :kwbegin, :any_def).none? &&
44
44
  node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
45
45
  node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
46
46
  end
@@ -82,7 +82,7 @@ module RuboCop
82
82
  next_sibling.source_range
83
83
  next_sibling.loc.line
84
84
  elsif (parent = node.parent)
85
- if parent.loc.respond_to?(:end) && parent.loc.end
85
+ if parent.loc?(:end)
86
86
  parent.loc.end.line
87
87
  else
88
88
  parent.loc.line
@@ -19,7 +19,7 @@ module RuboCop
19
19
 
20
20
  # @!method non_public_modifier?(node)
21
21
  def_node_matcher :non_public_modifier?, <<~PATTERN
22
- (send nil? {:private :protected :private_class_method} ({def defs} ...))
22
+ (send nil? {:private :protected :private_class_method} (any_def ...))
23
23
  PATTERN
24
24
  end
25
25
  end
@@ -21,7 +21,7 @@ module RuboCop
21
21
 
22
22
  # @!method empty_line_required?(node)
23
23
  def_node_matcher :empty_line_required?,
24
- '{def defs class module (send nil? {:private :protected :public})}'
24
+ '{any_def class module (send nil? {:private :protected :public})}'
25
25
 
26
26
  def check(node, body, adjusted_first_line: nil)
27
27
  return if valid_body_style?(body)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This module encapsulates the ability to forbid certain identifiers in a cop.
6
+ module ForbiddenIdentifiers
7
+ SIGILS = '@$' # if a variable starts with a sigil it will be removed
8
+
9
+ def forbidden_identifier?(name)
10
+ name = name.to_s.delete(SIGILS)
11
+
12
+ forbidden_identifiers.any? && forbidden_identifiers.include?(name)
13
+ end
14
+
15
+ def forbidden_identifiers
16
+ cop_config.fetch('ForbiddenIdentifiers', [])
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This module encapsulates the ability to forbid certain patterns in a cop.
6
+ module ForbiddenPattern
7
+ def forbidden_pattern?(name)
8
+ forbidden_patterns.any? { |pattern| Regexp.new(pattern).match?(name) }
9
+ end
10
+
11
+ def forbidden_patterns
12
+ cop_config.fetch('ForbiddenPatterns', [])
13
+ end
14
+ end
15
+ end
16
+ end
@@ -6,7 +6,6 @@ module RuboCop
6
6
  module FrozenStringLiteral
7
7
  module_function
8
8
 
9
- FROZEN_STRING_LITERAL_REGEXP = /#\s*frozen[-_]?string[-_]?literal:/i.freeze
10
9
  FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
11
10
  FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
12
11
 
@@ -11,6 +11,24 @@ module RuboCop
11
11
  DO_NOT_MIX_OMIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{OMIT_HASH_VALUE_MSG}"
12
12
  DO_NOT_MIX_EXPLICIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{EXPLICIT_HASH_VALUE_MSG}"
13
13
 
14
+ DefNode = Struct.new(:node) do
15
+ def selector
16
+ if node.loc.respond_to?(:selector)
17
+ node.loc.selector
18
+ else
19
+ node.loc.keyword
20
+ end
21
+ end
22
+
23
+ def first_argument
24
+ node.first_argument
25
+ end
26
+
27
+ def last_argument
28
+ node.last_argument
29
+ end
30
+ end
31
+
14
32
  def on_hash_for_mixed_shorthand(hash_node)
15
33
  return if ignore_mixed_hash_shorthand_syntax?(hash_node)
16
34
 
@@ -212,24 +230,6 @@ module RuboCop
212
230
  register_offense(pair_node, OMIT_HASH_VALUE_MSG, replacement)
213
231
  end
214
232
  end
215
-
216
- DefNode = Struct.new(:node) do
217
- def selector
218
- if node.loc.respond_to?(:selector)
219
- node.loc.selector
220
- else
221
- node.loc.keyword
222
- end
223
- end
224
-
225
- def first_argument
226
- node.first_argument
227
- end
228
-
229
- def last_argument
230
- node.last_argument
231
- end
232
- end
233
233
  end
234
234
  end
235
235
  # rubocop:enable Metrics/ModuleLength
@@ -23,7 +23,7 @@ module RuboCop
23
23
  (call _ _)
24
24
  (args
25
25
  $(arg _key)
26
- (arg _))
26
+ $(arg _))
27
27
  {
28
28
  $(send
29
29
  {(lvar _key) $_ _ | _ $_ (lvar _key)})
@@ -67,7 +67,7 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def extracts_hash_subset?(block)
70
- block_with_first_arg_check?(block) do |key_arg, send_node, method|
70
+ block_with_first_arg_check?(block) do |key_arg, value_arg, send_node, method|
71
71
  # Only consider methods that have one argument
72
72
  return false unless send_node.arguments.one?
73
73
 
@@ -76,15 +76,22 @@ module RuboCop
76
76
 
77
77
  case method
78
78
  when :include?, :exclude?
79
- send_node.first_argument.source == key_arg.source
79
+ slices_key?(send_node, :first_argument, key_arg, value_arg)
80
80
  when :in?
81
- send_node.receiver.source == key_arg.source
81
+ slices_key?(send_node, :receiver, key_arg, value_arg)
82
82
  else
83
83
  true
84
84
  end
85
85
  end
86
86
  end
87
87
 
88
+ def slices_key?(send_node, method, key_arg, value_arg)
89
+ return false if using_value_variable?(send_node, value_arg)
90
+
91
+ node = method == :receiver ? send_node.receiver : send_node.first_argument
92
+ node.source == key_arg.source
93
+ end
94
+
88
95
  def range_include?(send_node)
89
96
  # When checking `include?`, `exclude?` and `in?` for offenses, if the receiver
90
97
  # or first argument is a range, an offense should not be registered.
@@ -97,6 +104,14 @@ module RuboCop
97
104
  receiver.range_type?
98
105
  end
99
106
 
107
+ def using_value_variable?(send_node, value_arg)
108
+ # If the receiver of `include?` or `exclude?`, or the first argument of `in?` is the
109
+ # hash value block argument, an offense should not be registered.
110
+ # ie. `v.include?(k)` or `k.in?(v)`
111
+ (send_node.receiver.lvar_type? && send_node.receiver.name == value_arg.name) ||
112
+ (send_node.first_argument.lvar_type? && send_node.first_argument.name == value_arg.name)
113
+ end
114
+
100
115
  def supported_subset_method?(method)
101
116
  if active_support_extensions_enabled?
102
117
  ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
@@ -9,6 +9,80 @@ module RuboCop
9
9
 
10
10
  RESTRICT_ON_SEND = %i[[] to_h].freeze
11
11
 
12
+ # Internal helper class to hold match data
13
+ Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
14
+ def noop_transformation?
15
+ transforming_body_expr.lvar_type? &&
16
+ transforming_body_expr.children == [transformed_argname]
17
+ end
18
+
19
+ def transformation_uses_both_args?
20
+ transforming_body_expr.descendants.include?(unchanged_body_expr)
21
+ end
22
+
23
+ def use_transformed_argname?
24
+ transforming_body_expr.each_descendant(:lvar).any? do |node|
25
+ node.source == transformed_argname.to_s
26
+ end
27
+ end
28
+ end
29
+
30
+ # Internal helper class to hold autocorrect data
31
+ Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
32
+ def self.from_each_with_object(node, match)
33
+ new(match, node, 0, 0)
34
+ end
35
+
36
+ def self.from_hash_brackets_map(node, match)
37
+ new(match, node.children.last, 'Hash['.length, ']'.length)
38
+ end
39
+
40
+ def self.from_map_to_h(node, match)
41
+ if node.parent&.block_type? && node.parent.send_node == node
42
+ strip_trailing_chars = 0
43
+ else
44
+ map_range = node.children.first.source_range
45
+ node_range = node.source_range
46
+ strip_trailing_chars = node_range.end_pos - map_range.end_pos
47
+ end
48
+
49
+ new(match, node.children.first, 0, strip_trailing_chars)
50
+ end
51
+
52
+ def self.from_to_h(node, match)
53
+ new(match, node, 0, 0)
54
+ end
55
+
56
+ def strip_prefix_and_suffix(node, corrector)
57
+ expression = node.source_range
58
+ corrector.remove_leading(expression, leading)
59
+ corrector.remove_trailing(expression, trailing)
60
+ end
61
+
62
+ def set_new_method_name(new_method_name, corrector)
63
+ range = block_node.send_node.loc.selector
64
+ if (send_end = block_node.send_node.loc.end)
65
+ # If there are arguments (only true in the `each_with_object`
66
+ # case)
67
+ range = range.begin.join(send_end)
68
+ end
69
+ corrector.replace(range, new_method_name)
70
+ end
71
+
72
+ def set_new_arg_name(transformed_argname, corrector)
73
+ corrector.replace(block_node.arguments, "|#{transformed_argname}|")
74
+ end
75
+
76
+ def set_new_body_expression(transforming_body_expr, corrector)
77
+ body_source = transforming_body_expr.source
78
+ if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
79
+ body_source = "{ #{body_source} }"
80
+ end
81
+
82
+ corrector.replace(block_node.body, body_source)
83
+ end
84
+ end
85
+
12
86
  # @!method array_receiver?(node)
13
87
  def_node_matcher :array_receiver?, <<~PATTERN
14
88
  {(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)}
@@ -113,80 +187,6 @@ module RuboCop
113
187
  correction.set_new_arg_name(captures.transformed_argname, corrector)
114
188
  correction.set_new_body_expression(captures.transforming_body_expr, corrector)
115
189
  end
116
-
117
- # Internal helper class to hold match data
118
- Captures = Struct.new(:transformed_argname, :transforming_body_expr, :unchanged_body_expr) do
119
- def noop_transformation?
120
- transforming_body_expr.lvar_type? &&
121
- transforming_body_expr.children == [transformed_argname]
122
- end
123
-
124
- def transformation_uses_both_args?
125
- transforming_body_expr.descendants.include?(unchanged_body_expr)
126
- end
127
-
128
- def use_transformed_argname?
129
- transforming_body_expr.each_descendant(:lvar).any? do |node|
130
- node.source == transformed_argname.to_s
131
- end
132
- end
133
- end
134
-
135
- # Internal helper class to hold autocorrect data
136
- Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
137
- def self.from_each_with_object(node, match)
138
- new(match, node, 0, 0)
139
- end
140
-
141
- def self.from_hash_brackets_map(node, match)
142
- new(match, node.children.last, 'Hash['.length, ']'.length)
143
- end
144
-
145
- def self.from_map_to_h(node, match)
146
- if node.parent&.block_type? && node.parent.send_node == node
147
- strip_trailing_chars = 0
148
- else
149
- map_range = node.children.first.source_range
150
- node_range = node.source_range
151
- strip_trailing_chars = node_range.end_pos - map_range.end_pos
152
- end
153
-
154
- new(match, node.children.first, 0, strip_trailing_chars)
155
- end
156
-
157
- def self.from_to_h(node, match)
158
- new(match, node, 0, 0)
159
- end
160
-
161
- def strip_prefix_and_suffix(node, corrector)
162
- expression = node.source_range
163
- corrector.remove_leading(expression, leading)
164
- corrector.remove_trailing(expression, trailing)
165
- end
166
-
167
- def set_new_method_name(new_method_name, corrector)
168
- range = block_node.send_node.loc.selector
169
- if (send_end = block_node.send_node.loc.end)
170
- # If there are arguments (only true in the `each_with_object`
171
- # case)
172
- range = range.begin.join(send_end)
173
- end
174
- corrector.replace(range, new_method_name)
175
- end
176
-
177
- def set_new_arg_name(transformed_argname, corrector)
178
- corrector.replace(block_node.arguments, "|#{transformed_argname}|")
179
- end
180
-
181
- def set_new_body_expression(transforming_body_expr, corrector)
182
- body_source = transforming_body_expr.source
183
- if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
184
- body_source = "{ #{body_source} }"
185
- end
186
-
187
- corrector.replace(block_node.body, body_source)
188
- end
189
- end
190
190
  end
191
191
  end
192
192
  end
@@ -30,6 +30,7 @@ module RuboCop
30
30
  end
31
31
 
32
32
  alias on_numblock on_block
33
+ alias on_itblock on_block
33
34
 
34
35
  private
35
36
 
@@ -21,7 +21,7 @@ module RuboCop
21
21
  end
22
22
 
23
23
  def begin_source(node)
24
- node.loc.begin.source if node.loc.respond_to?(:begin) && node.loc.begin
24
+ node.loc.begin.source if node.loc?(:begin)
25
25
  end
26
26
 
27
27
  def type(node)
@@ -4,9 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  # Methods that calculate and return Parser::Source::Ranges
6
6
  module RangeHelp
7
- private
8
-
9
7
  BYTE_ORDER_MARK = 0xfeff # The Unicode codepoint
8
+ NOT_GIVEN = Module.new
9
+
10
+ private
10
11
 
11
12
  def source_range(source_buffer, line_number, column, length = 1)
12
13
  if column.is_a?(Range)
@@ -33,6 +34,18 @@ module RuboCop
33
34
  range_between(node.loc.begin.end_pos, node.loc.end.begin_pos)
34
35
  end
35
36
 
37
+ # A range containing the first to the last argument
38
+ # of a method call or method definition.
39
+ # def foo(a, b:)
40
+ # ^^^^^
41
+ # bar(1, 2, 3, &blk)
42
+ # ^^^^^^^^^^^^^
43
+ # baz { |x, y:, z:| }
44
+ # ^^^^^^^^^
45
+ def arguments_range(node)
46
+ node.first_argument.source_range.join(node.last_argument.source_range)
47
+ end
48
+
36
49
  def range_between(start_pos, end_pos)
37
50
  Parser::Source::Range.new(processed_source.buffer, start_pos, end_pos)
38
51
  end
@@ -51,7 +64,6 @@ module RuboCop
51
64
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
52
65
  end
53
66
 
54
- NOT_GIVEN = Module.new
55
67
  def range_with_surrounding_space(range_positional = NOT_GIVEN, # rubocop:disable Metrics/ParameterLists
56
68
  range: NOT_GIVEN, side: :both, newlines: true,
57
69
  whitespace: false, continuations: false,
@@ -10,7 +10,7 @@ module RuboCop
10
10
  def on_str(node)
11
11
  # Constants like __FILE__ are handled as strings,
12
12
  # but don't respond to begin.
13
- return unless node.loc.respond_to?(:begin) && node.loc.begin
13
+ return unless node.loc?(:begin)
14
14
  return if part_of_ignored_node?(node)
15
15
 
16
16
  if offense?(node)
@@ -29,7 +29,7 @@ module RuboCop
29
29
  min = required_minimum_ruby_version || 0
30
30
  max = required_maximum_ruby_version || Float::INFINITY
31
31
 
32
- min <= version && max >= version
32
+ version.between?(min, max)
33
33
  end
34
34
  end
35
35
  end
@@ -4,6 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  # Common methods shared by Style/TrailingCommaInArguments,
6
6
  # Style/TrailingCommaInArrayLiteral and Style/TrailingCommaInHashLiteral
7
+ # rubocop:disable Metrics/ModuleLength
7
8
  module TrailingComma
8
9
  include ConfigurableEnforcedStyle
9
10
  include RangeHelp
@@ -57,6 +58,8 @@ module RuboCop
57
58
  ', unless each item is on its own line'
58
59
  when :consistent_comma
59
60
  ', unless items are split onto multiple lines'
61
+ when :diff_comma
62
+ ', unless that item immediately precedes a newline'
60
63
  else
61
64
  ''
62
65
  end
@@ -68,6 +71,8 @@ module RuboCop
68
71
  multiline?(node) && no_elements_on_same_line?(node)
69
72
  when :consistent_comma
70
73
  multiline?(node) && !method_name_and_arguments_on_same_line?(node)
74
+ when :diff_comma
75
+ multiline?(node) && last_item_precedes_newline?(node)
71
76
  else
72
77
  false
73
78
  end
@@ -130,6 +135,12 @@ module RuboCop
130
135
  range1.last_line == range2.line
131
136
  end
132
137
 
138
+ def last_item_precedes_newline?(node)
139
+ after_last_item =
140
+ range_between(node.children.last.source_range.end_pos, node.loc.end.begin_pos)
141
+ after_last_item.source =~ /\A,?\s*\n/
142
+ end
143
+
133
144
  def avoid_comma(kind, comma_begin_pos, extra_info)
134
145
  range = range_between(comma_begin_pos, comma_begin_pos + 1)
135
146
  article = kind.include?('array') ? 'an' : 'a'
@@ -205,5 +216,6 @@ module RuboCop
205
216
  false
206
217
  end
207
218
  end
219
+ # rubocop:enable Metrics/ModuleLength
208
220
  end
209
221
  end
@@ -14,10 +14,10 @@ module RuboCop
14
14
  # autocorrected.
15
15
  #
16
16
  # [NOTE]
17
- # --
17
+ # ====
18
18
  # Because of a bug in Ruby 3.3.0, when a block is referenced inside of another block,
19
19
  # no offense will be registered until Ruby 3.4:
20
-
20
+ #
21
21
  # [source,ruby]
22
22
  # ----
23
23
  # def foo(&block)
@@ -25,7 +25,7 @@ module RuboCop
25
25
  # block_method { bar(&block) }
26
26
  # end
27
27
  # ----
28
- # --
28
+ # ====
29
29
  #
30
30
  # @example EnforcedStyle: anonymous (default)
31
31
  #
@@ -242,7 +242,7 @@ module RuboCop
242
242
  def find_definition(node)
243
243
  # Methods can be defined in a `def` or `defs`,
244
244
  # or dynamically via a `block` node.
245
- node.each_ancestor(:def, :defs, :block).each do |ancestor|
245
+ node.each_ancestor(:any_def, :block).each do |ancestor|
246
246
  method_node, method_name = method_definition?(ancestor)
247
247
  return [method_node, method_name] if method_node
248
248
  end