rubocop 1.65.0 → 1.66.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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +67 -67
  3. data/config/default.yml +18 -2
  4. data/exe/rubocop +4 -3
  5. data/lib/rubocop/comment_config.rb +1 -1
  6. data/lib/rubocop/config.rb +5 -1
  7. data/lib/rubocop/config_loader.rb +14 -8
  8. data/lib/rubocop/config_loader_resolver.rb +1 -2
  9. data/lib/rubocop/config_validator.rb +1 -1
  10. data/lib/rubocop/cop/base.rb +4 -0
  11. data/lib/rubocop/cop/cop.rb +2 -2
  12. data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -0
  13. data/lib/rubocop/cop/documentation.rb +18 -1
  14. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +2 -1
  15. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  16. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +11 -1
  17. data/lib/rubocop/cop/layout/assignment_indentation.rb +3 -2
  18. data/lib/rubocop/cop/layout/block_alignment.rb +30 -12
  19. data/lib/rubocop/cop/layout/condition_position.rb +0 -4
  20. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  21. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +8 -3
  22. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +0 -3
  23. data/lib/rubocop/cop/layout/line_length.rb +14 -14
  24. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +0 -2
  25. data/lib/rubocop/cop/lint/ambiguous_operator.rb +0 -2
  26. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +0 -2
  27. data/lib/rubocop/cop/lint/boolean_symbol.rb +0 -2
  28. data/lib/rubocop/cop/lint/circular_argument_reference.rb +0 -13
  29. data/lib/rubocop/cop/lint/debugger.rb +0 -4
  30. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +0 -10
  31. data/lib/rubocop/cop/lint/duplicate_case_condition.rb +0 -4
  32. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +0 -4
  33. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -10
  34. data/lib/rubocop/cop/lint/each_with_object_argument.rb +0 -4
  35. data/lib/rubocop/cop/lint/else_layout.rb +0 -2
  36. data/lib/rubocop/cop/lint/empty_conditional_body.rb +27 -6
  37. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -11
  38. data/lib/rubocop/cop/lint/empty_interpolation.rb +0 -4
  39. data/lib/rubocop/cop/lint/empty_when.rb +0 -2
  40. data/lib/rubocop/cop/lint/ensure_return.rb +1 -6
  41. data/lib/rubocop/cop/lint/float_out_of_range.rb +0 -4
  42. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +0 -10
  43. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +5 -7
  44. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +0 -7
  45. data/lib/rubocop/cop/lint/interpolation_check.rb +0 -4
  46. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  47. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +0 -4
  48. data/lib/rubocop/cop/lint/loop.rb +6 -12
  49. data/lib/rubocop/cop/lint/nested_method_definition.rb +0 -6
  50. data/lib/rubocop/cop/lint/next_without_accumulator.rb +0 -4
  51. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +0 -5
  52. data/lib/rubocop/cop/lint/percent_string_array.rb +0 -4
  53. data/lib/rubocop/cop/lint/percent_symbol_array.rb +0 -4
  54. data/lib/rubocop/cop/lint/rand_one.rb +0 -4
  55. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +3 -1
  56. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
  57. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +0 -4
  58. data/lib/rubocop/cop/lint/require_parentheses.rb +0 -4
  59. data/lib/rubocop/cop/lint/rescue_exception.rb +0 -4
  60. data/lib/rubocop/cop/lint/return_in_void_context.rb +0 -2
  61. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +0 -4
  62. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +6 -10
  63. data/lib/rubocop/cop/lint/unified_integer.rb +0 -4
  64. data/lib/rubocop/cop/lint/unreachable_code.rb +0 -5
  65. data/lib/rubocop/cop/lint/useless_assignment.rb +19 -16
  66. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +0 -4
  67. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +77 -0
  68. data/lib/rubocop/cop/lint/useless_setter_call.rb +0 -4
  69. data/lib/rubocop/cop/lint/void.rb +30 -8
  70. data/lib/rubocop/cop/metrics/block_length.rb +6 -5
  71. data/lib/rubocop/cop/metrics/class_length.rb +6 -5
  72. data/lib/rubocop/cop/metrics/method_length.rb +6 -5
  73. data/lib/rubocop/cop/metrics/module_length.rb +6 -5
  74. data/lib/rubocop/cop/mixin/annotation_comment.rb +0 -2
  75. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +19 -9
  76. data/lib/rubocop/cop/mixin/line_length_help.rb +7 -2
  77. data/lib/rubocop/cop/mixin/string_literals_help.rb +12 -0
  78. data/lib/rubocop/cop/naming/accessor_method_name.rb +5 -0
  79. data/lib/rubocop/cop/naming/predicate_name.rb +52 -26
  80. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +10 -1
  81. data/lib/rubocop/cop/style/alias.rb +1 -1
  82. data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -3
  83. data/lib/rubocop/cop/style/def_with_parentheses.rb +0 -2
  84. data/lib/rubocop/cop/style/each_for_simple_loop.rb +0 -1
  85. data/lib/rubocop/cop/style/empty_else.rb +6 -5
  86. data/lib/rubocop/cop/style/empty_heredoc.rb +1 -14
  87. data/lib/rubocop/cop/style/empty_literal.rb +31 -22
  88. data/lib/rubocop/cop/style/eval_with_location.rb +12 -11
  89. data/lib/rubocop/cop/style/file_read.rb +2 -5
  90. data/lib/rubocop/cop/style/file_write.rb +2 -5
  91. data/lib/rubocop/cop/style/format_string_token.rb +2 -2
  92. data/lib/rubocop/cop/style/global_std_stream.rb +7 -1
  93. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  94. data/lib/rubocop/cop/style/identical_conditional_branches.rb +1 -1
  95. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +0 -1
  96. data/lib/rubocop/cop/style/if_with_semicolon.rb +45 -6
  97. data/lib/rubocop/cop/style/in_pattern_then.rb +6 -2
  98. data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
  99. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  100. data/lib/rubocop/cop/style/map_into_array.rb +12 -5
  101. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  102. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -2
  103. data/lib/rubocop/cop/style/missing_else.rb +0 -4
  104. data/lib/rubocop/cop/style/multiline_when_then.rb +0 -4
  105. data/lib/rubocop/cop/style/multiple_comparison.rb +3 -11
  106. data/lib/rubocop/cop/style/numeric_predicate.rb +2 -2
  107. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  108. data/lib/rubocop/cop/style/parallel_assignment.rb +5 -4
  109. data/lib/rubocop/cop/style/quoted_symbols.rb +0 -2
  110. data/lib/rubocop/cop/style/redundant_condition.rb +3 -3
  111. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +46 -0
  112. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -1
  113. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -24
  114. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  115. data/lib/rubocop/cop/style/sole_nested_conditional.rb +21 -2
  116. data/lib/rubocop/cop/style/while_until_do.rb +0 -2
  117. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  118. data/lib/rubocop/cop/style/zero_length_predicate.rb +5 -1
  119. data/lib/rubocop/cop/team.rb +6 -2
  120. data/lib/rubocop/cop/variable_force.rb +13 -1
  121. data/lib/rubocop/core_ext/string.rb +2 -6
  122. data/lib/rubocop/ext/regexp_node.rb +9 -31
  123. data/lib/rubocop/formatter/junit_formatter.rb +70 -23
  124. data/lib/rubocop/lockfile.rb +6 -4
  125. data/lib/rubocop/options.rb +3 -1
  126. data/lib/rubocop/remote_config.rb +5 -1
  127. data/lib/rubocop/result_cache.rb +2 -8
  128. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  129. data/lib/rubocop/server/cache.rb +1 -1
  130. data/lib/rubocop/target_ruby.rb +7 -3
  131. data/lib/rubocop/version.rb +1 -1
  132. data/lib/rubocop/yaml_duplication_checker.rb +1 -0
  133. data/lib/rubocop.rb +7 -1
  134. metadata +8 -26
@@ -44,7 +44,6 @@ module RuboCop
44
44
  # # good
45
45
  # foo == bar
46
46
  #
47
- # @example
48
47
  # # bad
49
48
  # if foo.do_something?
50
49
  # true
@@ -18,6 +18,7 @@ module RuboCop
18
18
  extend AutoCorrector
19
19
 
20
20
  MSG_IF_ELSE = 'Do not use `if %<expr>s;` - use `if/else` instead.'
21
+ MSG_NEWLINE = 'Do not use `if %<expr>s;` - use a newline instead.'
21
22
  MSG_TERNARY = 'Do not use `if %<expr>s;` - use a ternary operator instead.'
22
23
 
23
24
  def on_normal_if_unless(node)
@@ -26,20 +27,47 @@ module RuboCop
26
27
  beginning = node.loc.begin
27
28
  return unless beginning&.is?(';')
28
29
 
29
- message = node.else_branch&.if_type? ? MSG_IF_ELSE : MSG_TERNARY
30
+ message = message(node)
30
31
 
31
- add_offense(node, message: format(message, expr: node.condition.source)) do |corrector|
32
- corrector.replace(node, autocorrect(node))
32
+ add_offense(node, message: message) do |corrector|
33
+ autocorrect(corrector, node)
33
34
  end
34
35
  end
35
36
 
36
37
  private
37
38
 
38
- def autocorrect(node)
39
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
40
+ def message(node)
41
+ template = if node.if_branch&.begin_type?
42
+ MSG_NEWLINE
43
+ elsif node.else_branch&.if_type? || node.else_branch&.begin_type? ||
44
+ use_block_in_branches?(node)
45
+ MSG_IF_ELSE
46
+ else
47
+ MSG_TERNARY
48
+ end
49
+
50
+ format(template, expr: node.condition.source)
51
+ end
52
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
53
+
54
+ def autocorrect(corrector, node)
55
+ if node.branches.compact.any?(&:begin_type?) || use_block_in_branches?(node)
56
+ corrector.replace(node.loc.begin, "\n")
57
+ else
58
+ corrector.replace(node, replacement(node))
59
+ end
60
+ end
61
+
62
+ def use_block_in_branches?(node)
63
+ node.branches.compact.any? { |branch| branch.block_type? || branch.numblock_type? }
64
+ end
65
+
66
+ def replacement(node)
39
67
  return correct_elsif(node) if node.else_branch&.if_type?
40
68
 
41
- then_code = node.if_branch ? node.if_branch.source : 'nil'
42
- else_code = node.else_branch ? node.else_branch.source : 'nil'
69
+ then_code = node.if_branch ? build_expression(node.if_branch) : 'nil'
70
+ else_code = node.else_branch ? build_expression(node.else_branch) : 'nil'
43
71
 
44
72
  "#{node.condition.source} ? #{then_code} : #{else_code}"
45
73
  end
@@ -53,6 +81,17 @@ module RuboCop
53
81
  RUBY
54
82
  end
55
83
 
84
+ # rubocop:disable Metrics/AbcSize
85
+ def build_expression(expr)
86
+ return expr.source if !expr.call_type? || expr.parenthesized? || expr.arguments.empty?
87
+
88
+ method = expr.source_range.begin.join(expr.loc.selector.end)
89
+ arguments = expr.first_argument.source_range.begin.join(expr.source_range.end)
90
+
91
+ "#{method.source}(#{arguments.source})"
92
+ end
93
+ # rubocop:enable Metrics/AbcSize
94
+
56
95
  def build_else_branch(second_condition)
57
96
  result = <<~RUBY
58
97
  elsif #{second_condition.condition.source}
@@ -44,11 +44,15 @@ module RuboCop
44
44
  private
45
45
 
46
46
  def alternative_pattern_source(pattern)
47
+ collect_alternative_patterns(pattern).join(' | ')
48
+ end
49
+
50
+ def collect_alternative_patterns(pattern)
47
51
  return pattern.children.map(&:source) unless pattern.children.first.match_alt_type?
48
52
 
49
- pattern_sources = alternative_pattern_source(pattern.children.first)
53
+ pattern_sources = collect_alternative_patterns(pattern.children.first)
50
54
 
51
- (pattern_sources << pattern.children[1].source).join(' | ')
55
+ pattern_sources << pattern.children[1].source
52
56
  end
53
57
  end
54
58
  end
@@ -72,8 +72,8 @@ module RuboCop
72
72
 
73
73
  private
74
74
 
75
- def invertible?(node)
76
- case node.type
75
+ def invertible?(node) # rubocop:disable Metrics/CyclomaticComplexity
76
+ case node&.type
77
77
  when :begin
78
78
  invertible?(node.children.first)
79
79
  when :send
@@ -105,7 +105,7 @@ module RuboCop
105
105
 
106
106
  # Value object to extract source ranges for the different parts of a magic comment
107
107
  class CommentRange
108
- extend Forwardable
108
+ extend SimpleForwardable
109
109
 
110
110
  DIRECTIVE_REGEXP = Regexp.union(MagicComment::KEYWORDS.map do |_, v|
111
111
  Regexp.new(v, Regexp::IGNORECASE)
@@ -58,12 +58,21 @@ module RuboCop
58
58
  [
59
59
  ^({begin kwbegin} ...)
60
60
  ({block numblock} (send !{nil? self} :each) _
61
- (send (lvar _) {:<< :push :append} _))
61
+ (send (lvar _) {:<< :push :append} {send lvar begin}))
62
62
  ]
63
63
  PATTERN
64
64
 
65
65
  # @!method empty_array_asgn?(node)
66
- def_node_matcher :empty_array_asgn?, '(lvasgn _ (array))'
66
+ def_node_matcher :empty_array_asgn?, <<~PATTERN
67
+ (
68
+ lvasgn _ {
69
+ (array)
70
+ (send (const {nil? cbase} :Array) :[])
71
+ (send (const {nil? cbase} :Array) :new (array)?)
72
+ (send nil? :Array (array))
73
+ }
74
+ )
75
+ PATTERN
67
76
 
68
77
  # @!method lvar_ref?(node, name)
69
78
  def_node_matcher :lvar_ref?, '(lvar %1)'
@@ -138,10 +147,8 @@ module RuboCop
138
147
  false
139
148
  when :begin, :kwbegin
140
149
  !node.right_sibling && return_value_used?(parent)
141
- when :block, :numblock
142
- !parent.void_context?
143
150
  else
144
- true
151
+ !parent.respond_to?(:void_context?) || !parent.void_context?
145
152
  end
146
153
  end
147
154
 
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Enforces the presence (default) or absence of parentheses in
7
- # method calls containing parameters.
7
+ # method calls containing arguments.
8
8
  #
9
9
  # In the default style (require_parentheses), macro methods are allowed.
10
10
  # Additional methods can be added to the `AllowedMethods` or
@@ -5,8 +5,8 @@ module RuboCop
5
5
  module Style
6
6
  # Checks for unwanted parentheses in parameterless method calls.
7
7
  #
8
- # This cop can be customized allowed methods with `AllowedMethods`.
9
- # By default, there are no methods to allowed.
8
+ # This cop's allowed methods can be customized with `AllowedMethods`.
9
+ # By default, there are no allowed methods.
10
10
  #
11
11
  # NOTE: This cop allows the use of `it()` without arguments in blocks,
12
12
  # as in `0.times { it() }`, following `Lint/ItWithoutArgumentsInBlock` cop.
@@ -168,10 +168,6 @@ module RuboCop
168
168
  config.for_cop('Style/UnlessElse')
169
169
  end
170
170
 
171
- def empty_else_cop_enabled?
172
- empty_else_config.fetch('Enabled')
173
- end
174
-
175
171
  def empty_else_style
176
172
  return unless empty_else_config.key?('EnforcedStyle')
177
173
 
@@ -54,10 +54,6 @@ module RuboCop
54
54
 
55
55
  same_line?(when_node, when_node.body)
56
56
  end
57
-
58
- def accept_node_type?(node)
59
- node&.array_type? || node&.hash_type?
60
- end
61
57
  end
62
58
  end
63
59
  end
@@ -56,12 +56,10 @@ module RuboCop
56
56
  'in a conditional, use `Array#include?` instead.'
57
57
 
58
58
  def on_new_investigation
59
- @last_comparison = nil
59
+ reset_comparison
60
60
  end
61
61
 
62
62
  def on_or(node)
63
- reset_comparison if switch_comparison?(node)
64
-
65
63
  root_of_or_node = root_of_or_node(node)
66
64
 
67
65
  return unless node == root_of_or_node
@@ -74,9 +72,9 @@ module RuboCop
74
72
  prefer_method = "[#{elements}].include?(#{variables_in_node(node).first})"
75
73
 
76
74
  corrector.replace(node, prefer_method)
77
- end
78
75
 
79
- @last_comparison = node
76
+ reset_comparison
77
+ end
80
78
  end
81
79
 
82
80
  private
@@ -147,12 +145,6 @@ module RuboCop
147
145
  end
148
146
  end
149
147
 
150
- def switch_comparison?(node)
151
- return true if @last_comparison.nil?
152
-
153
- @last_comparison.descendants.none?(node)
154
- end
155
-
156
148
  def reset_comparison
157
149
  @compared_elements = []
158
150
  @allowed_method_comparison = false
@@ -8,8 +8,8 @@ module RuboCop
8
8
  # These can be replaced by their respective predicate methods.
9
9
  # This cop can also be configured to do the reverse.
10
10
  #
11
- # This cop can be customized allowed methods with `AllowedMethods`.
12
- # By default, there are no methods to allowed.
11
+ # This cop's allowed methods can be customized with `AllowedMethods`.
12
+ # By default, there are no allowed methods.
13
13
  #
14
14
  # This cop disregards `#nonzero?` as its value is truthy or falsey,
15
15
  # but not `true` and `false`, and thus not always interchangeable with
@@ -42,7 +42,7 @@ module RuboCop
42
42
  def on_normal_if_unless(node)
43
43
  return unless node.single_line?
44
44
  return unless node.else_branch
45
- return if node.elsif?
45
+ return if node.elsif? || node.if_branch&.begin_type?
46
46
 
47
47
  message = message(node)
48
48
  add_offense(node, message: message) do |corrector|
@@ -211,15 +211,16 @@ module RuboCop
211
211
  protected
212
212
 
213
213
  def assignment
214
- @new_elements.map { |lhs, rhs| "#{lhs.source} = #{source(rhs)}" }
214
+ @new_elements.map { |lhs, rhs| "#{lhs.source} = #{source(rhs, rhs.loc)}" }
215
215
  end
216
216
 
217
217
  private
218
218
 
219
- def source(node)
220
- if node.str_type? && node.loc.begin.nil?
219
+ def source(node, loc)
220
+ # __FILE__ is treated as a StrNode but has no begin
221
+ if node.str_type? && loc.respond_to?(:begin) && loc.begin.nil?
221
222
  "'#{node.source}'"
222
- elsif node.sym_type? && node.loc.begin.nil?
223
+ elsif node.sym_type? && loc.begin.nil?
223
224
  ":#{node.source}"
224
225
  else
225
226
  node.source
@@ -98,8 +98,6 @@ module RuboCop
98
98
 
99
99
  def style
100
100
  return super unless super == :same_as_string_literals
101
-
102
- string_literals_config = config.for_cop('Style/StringLiterals')
103
101
  return :single_quotes unless string_literals_config['Enabled']
104
102
 
105
103
  string_literals_config['EnforcedStyle'].to_sym
@@ -12,7 +12,6 @@ module RuboCop
12
12
  # # good
13
13
  # a = b || c
14
14
  #
15
- # @example
16
15
  # # bad
17
16
  # if b
18
17
  # b
@@ -40,9 +39,9 @@ module RuboCop
40
39
  splat block_pass forwarded_restarg forwarded_kwrestarg forwarded_args
41
40
  ].freeze
42
41
 
42
+ # rubocop:disable Metrics/AbcSize
43
43
  def on_if(node)
44
- return if node.elsif_conditional?
45
- return unless offense?(node)
44
+ return if node.modifier_form? || node.elsif_conditional? || !offense?(node)
46
45
 
47
46
  message = message(node)
48
47
 
@@ -58,6 +57,7 @@ module RuboCop
58
57
  end
59
58
  end
60
59
  end
60
+ # rubocop:enable Metrics/AbcSize
61
61
 
62
62
  private
63
63
 
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Before Ruby 3.0, interpolated strings followed the frozen string literal
7
+ # magic comment which sometimes made it necessary to explicitly unfreeze them.
8
+ # Ruby 3.0 changed interpolated strings to always be unfrozen which makes
9
+ # unfreezing them redundant.
10
+ #
11
+ # @example
12
+ # # bad
13
+ # +"#{foo} bar"
14
+ #
15
+ # # bad
16
+ # "#{foo} bar".dup
17
+ #
18
+ # # good
19
+ # "#{foo} bar"
20
+ #
21
+ class RedundantInterpolationUnfreeze < Base
22
+ include FrozenStringLiteral
23
+ extend AutoCorrector
24
+ extend TargetRubyVersion
25
+
26
+ MSG = "Don't unfreeze interpolated strings as they are already unfrozen."
27
+
28
+ RESTRICT_ON_SEND = %i[+@ dup].freeze
29
+
30
+ minimum_target_ruby_version 3.0
31
+
32
+ def on_send(node)
33
+ return if node.arguments?
34
+ return unless (receiver = node.receiver)
35
+ return unless receiver.dstr_type?
36
+ return if uninterpolated_string?(receiver) || uninterpolated_heredoc?(receiver)
37
+
38
+ add_offense(node.loc.selector) do |corrector|
39
+ corrector.remove(node.loc.selector)
40
+ corrector.remove(node.loc.dot) unless node.unary_operation?
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -33,6 +33,7 @@ module RuboCop
33
33
  # 'foo'.sub('f', 'x')
34
34
  # 'foo'.sub!('f', 'x')
35
35
  class RedundantRegexpArgument < Base
36
+ include StringLiteralsHelp
36
37
  extend AutoCorrector
37
38
 
38
39
  MSG = 'Use string `%<prefer>s` as argument instead of regexp `%<current>s`.'
@@ -71,8 +72,10 @@ module RuboCop
71
72
  if new_argument.include?('"')
72
73
  new_argument.gsub!("'", "\\\\'")
73
74
  quote = "'"
74
- else
75
+ elsif new_argument.include?('\\')
75
76
  quote = '"'
77
+ else
78
+ quote = enforce_double_quotes? ? '"' : "'"
76
79
  end
77
80
 
78
81
  "#{quote}#{new_argument}#{quote}"
@@ -95,30 +95,14 @@ module RuboCop
95
95
  delimiters.include?(char)
96
96
  end
97
97
 
98
- if Gem::Version.new(Regexp::Parser::VERSION) >= Gem::Version.new('2.0')
99
- def each_escape(node)
100
- node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
101
- yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
102
-
103
- if expr.type == :set
104
- char_class_depth + (event == :enter ? 1 : -1)
105
- else
106
- char_class_depth
107
- end
108
- end
109
- end
110
- # Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
111
- # It's for compatibility with regexp_parser 1.8 and will never be maintained.
112
- else
113
- def each_escape(node)
114
- node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
115
- yield(expr.text[1], expr.start_index, !char_class_depth.zero?) if expr.type == :escape
116
-
117
- if expr.type == :set
118
- char_class_depth + (event == :enter ? 1 : -1)
119
- else
120
- char_class_depth
121
- end
98
+ def each_escape(node)
99
+ node.parsed_tree&.traverse&.reduce(0) do |char_class_depth, (event, expr)|
100
+ yield(expr.text[1], expr.ts, !char_class_depth.zero?) if expr.type == :escape
101
+
102
+ if expr.type == :set
103
+ char_class_depth + (event == :enter ? 1 : -1)
104
+ else
105
+ char_class_depth
122
106
  end
123
107
  end
124
108
  end
@@ -17,9 +17,9 @@ module RuboCop
17
17
  # `foo&.bar` can start returning `nil` as well as what the method
18
18
  # returns.
19
19
  #
20
- # The default for `MaxChainLength` is `2`
20
+ # The default for `MaxChainLength` is `2`.
21
21
  # We have limited the cop to not register an offense for method chains
22
- # that exceed this option is set.
22
+ # that exceed this option's value.
23
23
  #
24
24
  # @safety
25
25
  # Autocorrection is unsafe because if a value is `false`, the resulting
@@ -159,7 +159,13 @@ module RuboCop
159
159
  node_to_check = condition&.block_type? ? condition.send_node : condition
160
160
  return unless wrap_condition?(node_to_check)
161
161
 
162
- corrector.wrap(condition, '(', ')')
162
+ if condition.call_type?
163
+ source = parenthesized_method_arguments(condition)
164
+
165
+ corrector.replace(condition, source)
166
+ else
167
+ corrector.wrap(condition, '(', ')')
168
+ end
163
169
  end
164
170
 
165
171
  def correct_for_outer_condition_modify_form_style(corrector, node, if_branch)
@@ -236,7 +242,20 @@ module RuboCop
236
242
  end
237
243
 
238
244
  def replace_condition(condition)
239
- wrap_condition?(condition) ? "(#{condition.source})" : condition.source
245
+ return condition.source unless wrap_condition?(condition)
246
+
247
+ if condition.call_type?
248
+ parenthesized_method_arguments(condition)
249
+ else
250
+ "(#{condition.source})"
251
+ end
252
+ end
253
+
254
+ def parenthesized_method_arguments(node)
255
+ method_call = node.source_range.begin.join(node.loc.selector.end).source
256
+ arguments = node.first_argument.source_range.begin.join(node.source_range.end).source
257
+
258
+ "#{method_call}(#{arguments})"
240
259
  end
241
260
 
242
261
  def allow_modifier?
@@ -17,8 +17,6 @@ module RuboCop
17
17
  # do_something(x.pop)
18
18
  # end
19
19
  #
20
- # @example
21
- #
22
20
  # # bad
23
21
  # until x.empty? do
24
22
  # do_something(x.pop)
@@ -16,7 +16,6 @@ module RuboCop
16
16
  # # good
17
17
  # x += 1 while x < 10
18
18
  #
19
- # @example
20
19
  # # bad
21
20
  # until x > 10
22
21
  # x += 1
@@ -47,7 +47,11 @@ module RuboCop
47
47
  check_zero_length_comparison(node)
48
48
  check_nonzero_length_comparison(node)
49
49
  end
50
- alias on_csend on_send
50
+
51
+ def on_csend(node)
52
+ check_zero_length_predicate(node)
53
+ check_zero_length_comparison(node)
54
+ end
51
55
 
52
56
  private
53
57
 
@@ -120,8 +120,12 @@ module RuboCop
120
120
  end
121
121
 
122
122
  def external_dependency_checksum
123
- keys = cops.filter_map(&:external_dependency_checksum)
124
- Digest::SHA1.hexdigest(keys.join)
123
+ # The external dependency checksums are cached per RuboCop team so that
124
+ # the checksums don't need to be recomputed for each file.
125
+ @external_dependency_checksum ||= begin
126
+ keys = cops.filter_map(&:external_dependency_checksum)
127
+ Digest::SHA1.hexdigest(keys.join)
128
+ end
125
129
  end
126
130
 
127
131
  private
@@ -27,7 +27,10 @@ module RuboCop
27
27
  class VariableForce < Force # rubocop:disable Metrics/ClassLength
28
28
  VARIABLE_ASSIGNMENT_TYPE = :lvasgn
29
29
  REGEXP_NAMED_CAPTURE_TYPE = :match_with_lvasgn
30
- VARIABLE_ASSIGNMENT_TYPES = [VARIABLE_ASSIGNMENT_TYPE, REGEXP_NAMED_CAPTURE_TYPE].freeze
30
+ PATTERN_MATCH_VARIABLE_TYPE = :match_var
31
+ VARIABLE_ASSIGNMENT_TYPES = [
32
+ VARIABLE_ASSIGNMENT_TYPE, REGEXP_NAMED_CAPTURE_TYPE, PATTERN_MATCH_VARIABLE_TYPE
33
+ ].freeze
31
34
 
32
35
  ARGUMENT_DECLARATION_TYPES = [
33
36
  :arg, :optarg, :restarg,
@@ -112,6 +115,7 @@ module RuboCop
112
115
  NODE_HANDLER_METHOD_NAMES = [
113
116
  [VARIABLE_ASSIGNMENT_TYPE, :process_variable_assignment],
114
117
  [REGEXP_NAMED_CAPTURE_TYPE, :process_regexp_named_captures],
118
+ [PATTERN_MATCH_VARIABLE_TYPE, :process_pattern_match_variable],
115
119
  [MULTIPLE_ASSIGNMENT_TYPE, :process_variable_multiple_assignment],
116
120
  [VARIABLE_REFERENCE_TYPE, :process_variable_referencing],
117
121
  [RESCUE_TYPE, :process_rescue],
@@ -175,6 +179,14 @@ module RuboCop
175
179
  skip_children!
176
180
  end
177
181
 
182
+ def process_pattern_match_variable(node)
183
+ name = node.children.first
184
+
185
+ variable_table.declare_variable(name, node) unless variable_table.variable_exist?(name)
186
+
187
+ skip_children!
188
+ end
189
+
178
190
  def regexp_captured_names(node)
179
191
  regexp = node.to_regexp
180
192
 
@@ -9,12 +9,8 @@ class String
9
9
  # @return [Boolean] true is the string is blank, false otherwise
10
10
  #
11
11
  # @example
12
- # ''.blank? #=> true
13
- #
14
- # @example
15
- # ' '.blank? #=> true
16
- #
17
- # @example
12
+ # ''.blank? #=> true
13
+ # ' '.blank? #=> true
18
14
  # ' test'.blank? #=> false
19
15
  def blank?
20
16
  empty? || lstrip.empty?
@@ -15,39 +15,17 @@ module RuboCop
15
15
  # see `ext/regexp_parser`.
16
16
  attr_reader :parsed_tree
17
17
 
18
- if Gem::Version.new(Regexp::Parser::VERSION) >= Gem::Version.new('2.0')
19
- def assign_properties(*)
20
- super
18
+ def assign_properties(*)
19
+ super
21
20
 
22
- str = with_interpolations_blanked
23
- @parsed_tree = begin
24
- Regexp::Parser.parse(str, options: options)
25
- rescue StandardError
26
- nil
27
- end
28
- origin = loc.begin.end
29
- @parsed_tree&.each_expression(true) { |e| e.origin = origin }
30
- end
31
- # Please remove this `else` branch when support for regexp_parser 1.8 will be dropped.
32
- # It's for compatibility with regexp_parser 1.8 and will never be maintained.
33
- else
34
- def assign_properties(*)
35
- super
36
-
37
- str = with_interpolations_blanked
38
- begin
39
- @parsed_tree = Regexp::Parser.parse(str, options: options)
40
- rescue StandardError
41
- @parsed_tree = nil
42
- else
43
- origin = loc.begin.end
44
- source = @parsed_tree.to_s
45
- @parsed_tree.each_expression(true) do |e|
46
- e.origin = origin
47
- e.source = source
48
- end
49
- end
21
+ str = with_interpolations_blanked
22
+ @parsed_tree = begin
23
+ Regexp::Parser.parse(str, options: options)
24
+ rescue StandardError
25
+ nil
50
26
  end
27
+ origin = loc.begin.end
28
+ @parsed_tree&.each_expression(true) { |e| e.origin = origin }
51
29
  end
52
30
 
53
31
  def each_capture(named: ANY)