rubocop 1.75.8 → 1.81.7

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 (176) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -16
  3. data/config/default.yml +121 -28
  4. data/config/obsoletion.yml +6 -3
  5. data/exe/rubocop +1 -8
  6. data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
  7. data/lib/rubocop/cli.rb +18 -3
  8. data/lib/rubocop/config_loader.rb +4 -39
  9. data/lib/rubocop/config_loader_resolver.rb +5 -4
  10. data/lib/rubocop/config_store.rb +5 -0
  11. data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
  12. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  13. data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
  14. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  15. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  16. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  17. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
  18. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  19. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  20. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  21. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  22. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
  23. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
  24. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  25. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  26. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  27. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  28. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  29. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
  30. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  31. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
  32. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  33. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
  34. data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
  35. data/lib/rubocop/cop/layout/line_length.rb +35 -6
  36. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
  37. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
  38. data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
  39. data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
  40. data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
  41. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
  42. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  43. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  44. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  45. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
  46. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  47. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  48. data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
  49. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  50. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  51. data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
  52. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  53. data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
  54. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
  55. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  56. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  57. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  58. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
  59. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  60. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  61. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  62. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  63. data/lib/rubocop/cop/lint/self_assignment.rb +31 -5
  64. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  65. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  66. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  67. data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
  68. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  69. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  70. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  71. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  72. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  73. data/lib/rubocop/cop/lint/void.rb +7 -0
  74. data/lib/rubocop/cop/message_annotator.rb +1 -1
  75. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  76. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  77. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  78. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  79. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  80. data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
  81. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  82. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  83. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  84. data/lib/rubocop/cop/naming/method_name.rb +129 -13
  85. data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
  86. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  87. data/lib/rubocop/cop/security/eval.rb +2 -1
  88. data/lib/rubocop/cop/security/json_load.rb +33 -11
  89. data/lib/rubocop/cop/security/open.rb +1 -0
  90. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
  91. data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
  92. data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
  93. data/lib/rubocop/cop/style/array_intersect.rb +99 -35
  94. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  95. data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
  96. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  97. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  98. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  99. data/lib/rubocop/cop/style/conditional_assignment.rb +11 -5
  100. data/lib/rubocop/cop/style/constant_visibility.rb +14 -9
  101. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  102. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  103. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  104. data/lib/rubocop/cop/style/endless_method.rb +15 -2
  105. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  106. data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
  107. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  108. data/lib/rubocop/cop/style/float_division.rb +15 -1
  109. data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
  110. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  111. data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
  112. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  113. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  114. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  115. data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
  116. data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
  117. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  118. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
  119. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
  120. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  121. data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
  122. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
  123. data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
  124. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  125. data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
  126. data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
  127. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  128. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  129. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  130. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  131. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  132. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
  133. data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
  134. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
  135. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  136. data/lib/rubocop/cop/style/redundant_self.rb +8 -5
  137. data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
  138. data/lib/rubocop/cop/style/semicolon.rb +23 -7
  139. data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
  140. data/lib/rubocop/cop/style/sole_nested_conditional.rb +40 -3
  141. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  142. data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
  143. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  144. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  145. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  146. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  147. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  148. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  149. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  150. data/lib/rubocop/cop/variable_force.rb +25 -8
  151. data/lib/rubocop/cops_documentation_generator.rb +5 -4
  152. data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
  153. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  154. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  155. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  156. data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
  157. data/lib/rubocop/lsp/diagnostic.rb +25 -24
  158. data/lib/rubocop/lsp/routes.rb +65 -9
  159. data/lib/rubocop/lsp/runtime.rb +2 -2
  160. data/lib/rubocop/lsp/server.rb +2 -2
  161. data/lib/rubocop/lsp/stdin_runner.rb +0 -16
  162. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  163. data/lib/rubocop/result_cache.rb +14 -12
  164. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  165. data/lib/rubocop/runner.rb +6 -4
  166. data/lib/rubocop/server/cache.rb +4 -2
  167. data/lib/rubocop/server/client_command/base.rb +10 -0
  168. data/lib/rubocop/server/client_command/exec.rb +2 -1
  169. data/lib/rubocop/server/client_command/start.rb +11 -1
  170. data/lib/rubocop/target_finder.rb +9 -9
  171. data/lib/rubocop/target_ruby.rb +10 -1
  172. data/lib/rubocop/version.rb +1 -1
  173. data/lib/rubocop.rb +12 -1
  174. data/lib/ruby_lsp/rubocop/addon.rb +25 -10
  175. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  176. metadata +18 -7
@@ -48,6 +48,11 @@ module RuboCop
48
48
  MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
49
49
  'either `#public_constant` or `#private_constant`.'
50
50
 
51
+ # @!method visibility_declaration_for(node)
52
+ def_node_matcher :visibility_declaration_for, <<~PATTERN
53
+ (send nil? {:public_constant :private_constant} $...)
54
+ PATTERN
55
+
51
56
  def on_casgn(node)
52
57
  return unless class_or_module_scope?(node)
53
58
  return if visibility_declaration?(node)
@@ -77,20 +82,20 @@ module RuboCop
77
82
  end
78
83
  end
79
84
 
85
+ # rubocop:disable Metrics/AbcSize
80
86
  def visibility_declaration?(node)
81
87
  node.parent.each_child_node(:send).any? do |child|
82
- visibility_declaration_for?(child, node.name)
83
- end
84
- end
88
+ next false unless (arguments = visibility_declaration_for(child))
85
89
 
86
- # @!method visibility_declaration_for?(node, const_name)
87
- def_node_matcher :visibility_declaration_for?, <<~PATTERN
88
- (send nil? {:public_constant :private_constant} ({sym str} #match_name?(%1)))
89
- PATTERN
90
+ arguments = arguments.first.children.first.to_a if arguments.first&.splat_type?
91
+ constant_values = arguments.map do |argument|
92
+ argument.value.to_sym if argument.respond_to?(:value)
93
+ end
90
94
 
91
- def match_name?(name, constant_name)
92
- name.to_sym == constant_name.to_sym
95
+ constant_values.include?(node.name)
96
+ end
93
97
  end
98
+ # rubocop:enable Metrics/AbcSize
94
99
  end
95
100
  end
96
101
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Check for chained `dig` calls that can be collapsed into a single `dig`.
6
+ # Checks for chained `dig` calls that can be collapsed into a single `dig`.
7
7
  #
8
8
  # @safety
9
9
  # This cop is unsafe because it cannot be guaranteed that the receiver
@@ -96,7 +96,7 @@ module RuboCop
96
96
  elsif last_child.type?(:pair, :hash) || last_child.parent.array_type?
97
97
  false
98
98
  else
99
- last_child.last_line <= node.last_line
99
+ last_child.first_line <= node.first_line
100
100
  end
101
101
  end
102
102
 
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for empty strings being assigned inside string interpolation.
7
+ #
8
+ # Empty strings are a meaningless outcome inside of string interpolation, so we remove them.
9
+ # Alternatively, when configured to do so, we prioritise using empty strings.
10
+ #
11
+ # While this cop would also apply to variables that are only going to be used as strings,
12
+ # RuboCop can't detect that, so we only check inside of string interpolation.
13
+ #
14
+ # @example EnforcedStyle: trailing_conditional (default)
15
+ # # bad
16
+ # "#{condition ? 'foo' : ''}"
17
+ #
18
+ # # good
19
+ # "#{'foo' if condition}"
20
+ #
21
+ # # bad
22
+ # "#{condition ? '' : 'foo'}"
23
+ #
24
+ # # good
25
+ # "#{'foo' unless condition}"
26
+ #
27
+ # @example EnforcedStyle: ternary
28
+ # # bad
29
+ # "#{'foo' if condition}"
30
+ #
31
+ # # good
32
+ # "#{condition ? 'foo' : ''}"
33
+ #
34
+ # # bad
35
+ # "#{'foo' unless condition}"
36
+ #
37
+ # # good
38
+ # "#{condition ? '' : 'foo'}"
39
+ #
40
+ class EmptyStringInsideInterpolation < Base
41
+ include ConfigurableEnforcedStyle
42
+ include Interpolation
43
+ extend AutoCorrector
44
+
45
+ MSG_TRAILING_CONDITIONAL = 'Do not use trailing conditionals in string interpolation.'
46
+ MSG_TERNARY = 'Do not return empty strings in string interpolation.'
47
+
48
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
49
+ def on_interpolation(node)
50
+ node.each_child_node(:if) do |child_node|
51
+ if style == :trailing_conditional
52
+ if empty_if_outcome?(child_node)
53
+ ternary_style_autocorrect(child_node, child_node.else_branch.source, 'unless')
54
+ end
55
+
56
+ if empty_else_outcome?(child_node)
57
+ ternary_style_autocorrect(child_node, child_node.if_branch.source, 'if')
58
+ end
59
+ elsif style == :ternary
60
+ next unless child_node.modifier_form?
61
+
62
+ ternary_component = if child_node.unless?
63
+ "'' : #{child_node.if_branch.source}"
64
+ else
65
+ "#{child_node.if_branch.source} : ''"
66
+ end
67
+
68
+ add_offense(node, message: MSG_TRAILING_CONDITIONAL) do |corrector|
69
+ corrector.replace(node, "\#{#{child_node.condition.source} ? #{ternary_component}}")
70
+ end
71
+ end
72
+ end
73
+ end
74
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
75
+
76
+ private
77
+
78
+ def empty_if_outcome?(node)
79
+ empty_branch_outcome?(node.if_branch)
80
+ end
81
+
82
+ def empty_else_outcome?(node)
83
+ empty_branch_outcome?(node.else_branch)
84
+ end
85
+
86
+ def empty_branch_outcome?(branch)
87
+ return false unless branch
88
+
89
+ branch.nil_type? || (branch.str_type? && branch.value.empty?)
90
+ end
91
+
92
+ def ternary_style_autocorrect(node, outcome, condition)
93
+ add_offense(node, message: MSG_TERNARY) do |corrector|
94
+ corrector.replace(node, "#{outcome} #{condition} #{node.condition.source}")
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -144,7 +144,7 @@ module RuboCop
144
144
  MSG_REQUIRE_ALWAYS = 'Use endless method definitions.'
145
145
 
146
146
  def on_def(node)
147
- return if node.assignment_method?
147
+ return if node.assignment_method? || use_heredoc?(node)
148
148
 
149
149
  case style
150
150
  when :allow_single_line, :allow_always
@@ -198,6 +198,13 @@ module RuboCop
198
198
  add_offense(node) { |corrector| correct_to_multiline(corrector, node) }
199
199
  end
200
200
 
201
+ def use_heredoc?(node)
202
+ return false unless (body = node.body)
203
+ return true if body.str_type? && body.heredoc?
204
+
205
+ body.each_descendant(:str).any?(&:heredoc?)
206
+ end
207
+
201
208
  def correct_to_multiline(corrector, node)
202
209
  replacement = <<~RUBY.strip
203
210
  def #{node.method_name}#{arguments(node)}
@@ -225,7 +232,13 @@ module RuboCop
225
232
  def too_long_when_made_endless?(node)
226
233
  return false unless config.cop_enabled?('Layout/LineLength')
227
234
 
228
- endless_replacement(node).length > config.for_cop('Layout/LineLength')['Max']
235
+ offset = modifier_offset(node)
236
+
237
+ endless_replacement(node).length + offset > config.for_cop('Layout/LineLength')['Max']
238
+ end
239
+
240
+ def modifier_offset(node)
241
+ same_line?(node.parent, node) ? node.loc.column - node.parent.loc.column : 0
229
242
  end
230
243
  end
231
244
  end
@@ -56,7 +56,7 @@ module RuboCop
56
56
 
57
57
  def initialize(config = nil, options = nil)
58
58
  super
59
- @def_nodes = Set.new
59
+ @def_nodes = Set.new.compare_by_identity
60
60
  end
61
61
 
62
62
  def on_yield(node)
@@ -59,6 +59,7 @@ module RuboCop
59
59
  #
60
60
  class ExponentialNotation < Base
61
61
  include ConfigurableEnforcedStyle
62
+
62
63
  MESSAGES = {
63
64
  scientific: 'Use a mantissa >= 1 and < 10.',
64
65
  engineering: 'Use an exponent divisible by 3 and a mantissa >= 0.1 and < 1000.',
@@ -87,7 +88,7 @@ module RuboCop
87
88
  true
88
89
  end
89
90
 
90
- def integral(node)
91
+ def integral?(node)
91
92
  mantissa, = node.source.split('e')
92
93
  /^-?[1-9](\d*[1-9])?$/.match?(mantissa)
93
94
  end
@@ -101,7 +102,7 @@ module RuboCop
101
102
  when :engineering
102
103
  !engineering?(node)
103
104
  when :integral
104
- !integral(node)
105
+ !integral?(node)
105
106
  else
106
107
  false
107
108
  end
@@ -9,7 +9,20 @@ module RuboCop
9
9
  # On the other hand, `ENV.fetch` raises `KeyError` or returns the explicitly
10
10
  # specified default value.
11
11
  #
12
- # @example
12
+ # @example DefaultToNil: true (default)
13
+ # # bad
14
+ # ENV['X']
15
+ # x = ENV['X']
16
+ #
17
+ # # good
18
+ # ENV.fetch('X', nil)
19
+ # x = ENV.fetch('X', nil)
20
+ #
21
+ # # also good
22
+ # !ENV['X']
23
+ # ENV['X'].some_method # (e.g. `.nil?`)
24
+ #
25
+ # @example DefaultToNil: false
13
26
  # # bad
14
27
  # ENV['X']
15
28
  # x = ENV['X']
@@ -25,7 +38,8 @@ module RuboCop
25
38
  class FetchEnvVar < Base
26
39
  extend AutoCorrector
27
40
 
28
- MSG = 'Use `ENV.fetch(%<key>s)` or `ENV.fetch(%<key>s, nil)` instead of `ENV[%<key>s]`.'
41
+ MSG_WITH_NIL = 'Use `ENV.fetch(%<key>s, nil)` instead of `ENV[%<key>s]`.'
42
+ MSG_WITHOUT_NIL = 'Use `ENV.fetch(%<key>s)` instead of `ENV[%<key>s]`.'
29
43
  RESTRICT_ON_SEND = [:[]].freeze
30
44
 
31
45
  # @!method env_with_bracket?(node)
@@ -37,7 +51,7 @@ module RuboCop
37
51
  env_with_bracket?(node) do |name_node|
38
52
  break unless offensive?(node)
39
53
 
40
- message = format(MSG, key: name_node.source)
54
+ message = format(offense_message, key: name_node.source)
41
55
  add_offense(node, message: message) do |corrector|
42
56
  corrector.replace(node, new_code(name_node))
43
57
  end
@@ -46,6 +60,14 @@ module RuboCop
46
60
 
47
61
  private
48
62
 
63
+ def default_to_nil?
64
+ cop_config.fetch('DefaultToNil', true)
65
+ end
66
+
67
+ def offense_message
68
+ default_to_nil? ? MSG_WITH_NIL : MSG_WITHOUT_NIL
69
+ end
70
+
49
71
  def allowed_var?(node)
50
72
  env_key_node = node.children.last
51
73
  env_key_node.str_type? && cop_config['AllowedVars'].include?(env_key_node.value)
@@ -53,12 +75,12 @@ module RuboCop
53
75
 
54
76
  def used_as_flag?(node)
55
77
  return false if node.root?
56
- return true if used_if_condition_in_body(node)
78
+ return true if used_if_condition_in_body?(node)
57
79
 
58
80
  node.parent.send_type? && (node.parent.prefix_bang? || node.parent.comparison_method?)
59
81
  end
60
82
 
61
- def used_if_condition_in_body(node)
83
+ def used_if_condition_in_body?(node)
62
84
  if_node = node.ancestors.find(&:if_type?)
63
85
 
64
86
  return false unless (condition = if_node&.condition)
@@ -125,7 +147,11 @@ module RuboCop
125
147
  end
126
148
 
127
149
  def new_code(name_node)
128
- "ENV.fetch(#{name_node.source}, nil)"
150
+ if default_to_nil?
151
+ "ENV.fetch(#{name_node.source}, nil)"
152
+ else
153
+ "ENV.fetch(#{name_node.source})"
154
+ end
129
155
  end
130
156
  end
131
157
  end
@@ -7,9 +7,12 @@ module RuboCop
7
7
  # It is recommended to either always use `fdiv` or coerce one side only.
8
8
  # This cop also provides other options for code consistency.
9
9
  #
10
+ # For `Regexp.last_match` and nth reference (e.g., `$1`), it assumes that the value
11
+ # is a string matched by a regular expression, and allows conversion with `#to_f`.
12
+ #
10
13
  # @safety
11
14
  # This cop is unsafe, because if the operand variable is a string object
12
- # then `.to_f` will be removed and an error will occur.
15
+ # then `#to_f` will be removed and an error will occur.
13
16
  #
14
17
  # [source,ruby]
15
18
  # ----
@@ -84,6 +87,14 @@ module RuboCop
84
87
  (send !nil? :to_f)
85
88
  PATTERN
86
89
 
90
+ # @!method regexp_last_match?(node)
91
+ def_node_matcher :regexp_last_match?, <<~PATTERN
92
+ {
93
+ (send (const {nil? cbase} :Regexp) :last_match int)
94
+ (:nth_ref _)
95
+ }
96
+ PATTERN
97
+
87
98
  def on_send(node)
88
99
  return unless offense_condition?(node)
89
100
 
@@ -104,6 +115,9 @@ module RuboCop
104
115
  private
105
116
 
106
117
  def offense_condition?(node)
118
+ return false if regexp_last_match?(node.receiver.receiver) ||
119
+ regexp_last_match?(node.first_argument.receiver)
120
+
107
121
  case style
108
122
  when :left_coerce
109
123
  right_coerce?(node)
@@ -44,17 +44,17 @@ module RuboCop
44
44
  class HashConversion < Base
45
45
  extend AutoCorrector
46
46
 
47
- MSG_TO_H = 'Prefer ary.to_h to Hash[ary].'
48
- MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to Hash[arg1, arg2, ...].'
49
- MSG_LITERAL_HASH_ARG = 'Prefer literal hash to Hash[key: value, ...].'
50
- MSG_SPLAT = 'Prefer array_of_pairs.to_h to Hash[*array].'
47
+ MSG_TO_H = 'Prefer `ary.to_h` to `Hash[ary]`.'
48
+ MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to `Hash[arg1, arg2, ...]`.'
49
+ MSG_LITERAL_HASH_ARG = 'Prefer literal hash to `Hash[key: value, ...]`.'
50
+ MSG_SPLAT = 'Prefer `array_of_pairs.to_h` to `Hash[*array]`.'
51
51
  RESTRICT_ON_SEND = %i[[]].freeze
52
52
 
53
53
  # @!method hash_from_array?(node)
54
54
  def_node_matcher :hash_from_array?, '(send (const {nil? cbase} :Hash) :[] ...)'
55
55
 
56
56
  def on_send(node)
57
- return unless hash_from_array?(node)
57
+ return if part_of_ignored_node?(node) || !hash_from_array?(node)
58
58
 
59
59
  # There are several cases:
60
60
  # If there is one argument:
@@ -63,7 +63,8 @@ module RuboCop
63
63
  # If there is 0 or 2+ arguments:
64
64
  # Hash[a1, a2, a3, a4] => {a1 => a2, a3 => a4}
65
65
  # ...but don't suggest correction if there is odd number of them (it is a bug)
66
- node.arguments.count == 1 ? single_argument(node) : multi_argument(node)
66
+ node.arguments.one? ? single_argument(node) : multi_argument(node)
67
+ ignore_node(node)
67
68
  end
68
69
 
69
70
  private
@@ -111,7 +112,12 @@ module RuboCop
111
112
  end
112
113
 
113
114
  def requires_parens?(node)
114
- (node.call_type? && node.arguments.any? && !node.parenthesized?) || node.operator_keyword?
115
+ if node.call_type?
116
+ return false if node.method?(:[])
117
+ return true if node.arguments.any? && !node.parenthesized?
118
+ end
119
+
120
+ node.operator_keyword?
115
121
  end
116
122
 
117
123
  def multi_argument(node)
@@ -122,7 +128,9 @@ module RuboCop
122
128
  corrector.replace(node, args_to_hash(node.arguments))
123
129
 
124
130
  parent = node.parent
125
- add_parentheses(parent, corrector) if parent&.send_type? && !parent.parenthesized?
131
+ if parent&.send_type? && !parent.method?(:to_h) && !parent.parenthesized?
132
+ add_parentheses(parent, corrector)
133
+ end
126
134
  end
127
135
  end
128
136
  end
@@ -212,7 +212,7 @@ module RuboCop
212
212
  end
213
213
 
214
214
  def word_symbol_pair?(pair)
215
- return false unless pair.key.type?(:sym, :dsym)
215
+ return false unless pair.key.any_sym_type?
216
216
 
217
217
  acceptable_19_syntax_symbol?(pair.key.source)
218
218
  end
@@ -132,12 +132,10 @@ module RuboCop
132
132
  end
133
133
 
134
134
  def pattern_matching_nodes(condition)
135
- if condition.type?(:match_pattern, :match_pattern_p)
135
+ if condition.any_match_pattern_type?
136
136
  [condition]
137
137
  else
138
- condition.each_descendant.select do |node|
139
- node.type?(:match_pattern, :match_pattern_p)
140
- end
138
+ condition.each_descendant.select(&:any_match_pattern_type?)
141
139
  end
142
140
  end
143
141
 
@@ -225,8 +223,17 @@ module RuboCop
225
223
 
226
224
  def too_long_line_based_on_allow_uri?(line)
227
225
  if allow_uri?
228
- uri_range = find_excessive_uri_range(line)
229
- return false if uri_range && allowed_uri_position?(line, uri_range)
226
+ uri_range = find_excessive_range(line, :uri)
227
+ return false if uri_range && allowed_position?(line, uri_range)
228
+ end
229
+
230
+ true
231
+ end
232
+
233
+ def too_long_line_based_on_allow_qualified_name?(line)
234
+ if allow_qualified_name?
235
+ namespace_range = find_excessive_range(line, :namespace)
236
+ return false if namespace_range && allowed_position?(line, namespace_range)
230
237
  end
231
238
 
232
239
  true
@@ -68,7 +68,7 @@ module RuboCop
68
68
  end
69
69
 
70
70
  def autocorrect(corrector, node)
71
- if node.type?(:while_post, :until_post)
71
+ if node.post_condition_loop?
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))
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Check for usages of not (`not` or `!`) called on a method
6
+ # Checks for usages of not (`not` or `!`) called on a method
7
7
  # when an inverse of that method can be used instead.
8
8
  #
9
9
  # Methods that can be inverted by a not (`not` or `!`) should be defined
@@ -3,33 +3,90 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for assignments to a local `it` variable inside a block
6
+ # Checks for local variables and method parameters named `it`,
7
7
  # where `it` can refer to the first anonymous parameter as of Ruby 3.4.
8
+ # Use a meaningful variable name instead.
8
9
  #
9
- # Although Ruby allows reassigning `it` in these cases, it could
10
+ # NOTE: Although Ruby allows reassigning `it` in these cases, it could
10
11
  # 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
12
  #
14
13
  # @example
15
14
  # # bad
16
- # foo { it = 5 }
17
- # foo { |bar| it = bar }
18
- # foo { it = _2 }
15
+ # it = 5
19
16
  #
20
- # # good - use a different variable name
21
- # foo { var = 5 }
22
- # foo { |bar| var = bar }
23
- # foo { bar = _2 }
17
+ # # good
18
+ # var = 5
19
+ #
20
+ # # bad
21
+ # def foo(it)
22
+ # end
23
+ #
24
+ # # good
25
+ # def foo(arg)
26
+ # end
27
+ #
28
+ # # bad
29
+ # def foo(it = 5)
30
+ # end
31
+ #
32
+ # # good
33
+ # def foo(arg = 5)
34
+ # end
35
+ #
36
+ # # bad
37
+ # def foo(*it)
38
+ # end
39
+ #
40
+ # # good
41
+ # def foo(*args)
42
+ # end
43
+ #
44
+ # # bad
45
+ # def foo(it:)
46
+ # end
47
+ #
48
+ # # good
49
+ # def foo(arg:)
50
+ # end
51
+ #
52
+ # # bad
53
+ # def foo(it: 5)
54
+ # end
55
+ #
56
+ # # good
57
+ # def foo(arg: 5)
58
+ # end
59
+ #
60
+ # # bad
61
+ # def foo(**it)
62
+ # end
63
+ #
64
+ # # good
65
+ # def foo(**kwargs)
66
+ # end
67
+ #
68
+ # # bad
69
+ # def foo(&it)
70
+ # end
71
+ #
72
+ # # good
73
+ # def foo(&block)
74
+ # end
24
75
  class ItAssignment < Base
25
76
  MSG = '`it` is the default block parameter; consider another name.'
26
77
 
27
78
  def on_lvasgn(node)
28
79
  return unless node.name == :it
29
- return unless node.each_ancestor(:any_block).any?
30
80
 
31
81
  add_offense(node.loc.name)
32
82
  end
83
+ alias on_arg on_lvasgn
84
+ alias on_optarg on_lvasgn
85
+ alias on_restarg on_lvasgn
86
+ alias on_blockarg on_lvasgn
87
+ alias on_kwarg on_lvasgn
88
+ alias on_kwoptarg on_lvasgn
89
+ alias on_kwrestarg on_lvasgn
33
90
  end
34
91
  end
35
92
  end
@@ -5,15 +5,28 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for blocks with one argument where `it` block parameter can be used.
7
7
  #
8
- # It provides three `EnforcedStyle` options:
8
+ # It provides four `EnforcedStyle` options:
9
9
  #
10
- # 1. `only_numbered_parameters` (default) ... Detects only numbered block parameters.
11
- # 2. `always` ... Always uses the `it` block parameter.
12
- # 3. `disallow` ... Disallows the `it` block parameter.
10
+ # 1. `allow_single_line` (default) ... Always uses the `it` block parameter in a single line.
11
+ # 2. `only_numbered_parameters` ... Detects only numbered block parameters.
12
+ # 3. `always` ... Always uses the `it` block parameter.
13
+ # 4. `disallow` ... Disallows the `it` block parameter.
13
14
  #
14
- # A single numbered parameter is detected when `only_numbered_parameters` or `always`.
15
+ # A single numbered parameter is detected when `allow_single_line`,
16
+ # `only_numbered_parameters`, or `always`.
15
17
  #
16
- # @example EnforcedStyle: only_numbered_parameters (default)
18
+ # @example EnforcedStyle: allow_single_line (default)
19
+ # # bad
20
+ # block do
21
+ # do_something(it)
22
+ # end
23
+ # block { do_something(_1) }
24
+ #
25
+ # # good
26
+ # block { do_something(it) }
27
+ # block { |named_param| do_something(named_param) }
28
+ #
29
+ # @example EnforcedStyle: only_numbered_parameters
17
30
  # # bad
18
31
  # block { do_something(_1) }
19
32
  #
@@ -42,8 +55,9 @@ module RuboCop
42
55
  extend TargetRubyVersion
43
56
  extend AutoCorrector
44
57
 
45
- MSG_USE_IT_BLOCK_PARAMETER = 'Use `it` block parameter.'
46
- MSG_AVOID_IT_BLOCK_PARAMETER = 'Avoid using `it` block parameter.'
58
+ MSG_USE_IT_PARAMETER = 'Use `it` block parameter.'
59
+ MSG_AVOID_IT_PARAMETER = 'Avoid using `it` block parameter.'
60
+ MSG_AVOID_IT_PARAMETER_MULTILINE = 'Avoid using `it` block parameter for multi-line blocks.'
47
61
 
48
62
  minimum_target_ruby_version 3.4
49
63
 
@@ -57,7 +71,7 @@ module RuboCop
57
71
  variables = find_block_variables(node, node.first_argument.source)
58
72
 
59
73
  variables.each do |variable|
60
- add_offense(variable, message: MSG_USE_IT_BLOCK_PARAMETER) do |corrector|
74
+ add_offense(variable, message: MSG_USE_IT_PARAMETER) do |corrector|
61
75
  corrector.remove(node.arguments)
62
76
  corrector.replace(variable, 'it')
63
77
  end
@@ -71,26 +85,33 @@ module RuboCop
71
85
  variables = find_block_variables(node, '_1')
72
86
 
73
87
  variables.each do |variable|
74
- add_offense(variable, message: MSG_USE_IT_BLOCK_PARAMETER) do |corrector|
88
+ add_offense(variable, message: MSG_USE_IT_PARAMETER) do |corrector|
75
89
  corrector.replace(variable, 'it')
76
90
  end
77
91
  end
78
92
  end
79
93
 
80
94
  def on_itblock(node)
81
- return unless style == :disallow
95
+ case style
96
+ when :allow_single_line
97
+ return if node.single_line?
82
98
 
83
- variables = find_block_variables(node, 'it')
99
+ add_offense(node, message: MSG_AVOID_IT_PARAMETER_MULTILINE)
100
+ when :disallow
101
+ variables = find_block_variables(node, 'it')
84
102
 
85
- variables.each do |variable|
86
- add_offense(variable, message: MSG_AVOID_IT_BLOCK_PARAMETER)
103
+ variables.each do |variable|
104
+ add_offense(variable, message: MSG_AVOID_IT_PARAMETER)
105
+ end
87
106
  end
88
107
  end
89
108
 
90
109
  private
91
110
 
92
111
  def find_block_variables(node, block_argument_name)
93
- node.each_descendant(:lvar).select do |descendant|
112
+ return [] unless node.body
113
+
114
+ node.body.each_descendant(:lvar).select do |descendant|
94
115
  descendant.source == block_argument_name
95
116
  end
96
117
  end