rubocop 1.51.0 → 1.52.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +20 -2
  4. data/lib/rubocop/cop/base.rb +1 -1
  5. data/lib/rubocop/cop/lint/inherit_exception.rb +7 -0
  6. data/lib/rubocop/cop/lint/missing_super.rb +3 -0
  7. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +2 -2
  8. data/lib/rubocop/cop/lint/useless_assignment.rb +3 -1
  9. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  10. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  11. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  12. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  13. data/lib/rubocop/cop/style/collection_compact.rb +6 -0
  14. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  15. data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -2
  16. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  17. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -2
  18. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  19. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  20. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  21. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  22. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  23. data/lib/rubocop/cop/style/require_order.rb +2 -1
  24. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  25. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  26. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  27. data/lib/rubocop/cop/variable_force/assignment.rb +16 -1
  28. data/lib/rubocop/cop/variable_force.rb +1 -0
  29. data/lib/rubocop/server/client_command/exec.rb +2 -1
  30. data/lib/rubocop/version.rb +8 -4
  31. data/lib/rubocop.rb +4 -0
  32. metadata +11 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0863dd1792c6296e51bcdbbc4503423cbc61f66c40a7120b405f4eaf999349be'
4
- data.tar.gz: a4998dfeef1e7f82ffac34fb409494859b28afba9ce6bb007f6ca5870a5e371b
3
+ metadata.gz: 5301525d37bb844594d465a40a1e5643646f2b85a3bbd7258ce92af20c1d82bd
4
+ data.tar.gz: 3a1ba98652dc97a41f5ee5828160a9a74b59c806b3da618742e879a92d5ba596
5
5
  SHA512:
6
- metadata.gz: 1ff6067cf16502e16e5bf6691717f97b5f0cf34bdd03e0d893ee90185af1a26d5622c394b5b586530a9d596f8f92cdff4b5eb351d305fc8a2206906f903c9606
7
- data.tar.gz: 2ab3c9a30731adbd8818bfce7fba9f346ac8f66a3b0a52fe2ee65094a7ed580f617fa776664f59df71d6229cf35e3e9ad74a557ec6a760dcbc6d85ae1008a2bb
6
+ metadata.gz: 939d1acac3b8dd67e286c2a10c2cf4f81d2c7029eda506b186546198dbdaa1726fe9d70c32bb6ea09d22de3dcdc4224b4e4e061b590f5b0bced0e7f693fa29fe
7
+ data.tar.gz: 1b449beeac25c4475ff5deb915b045349283e35f1aff9bd526e9dda73a957a44df8e7ba7ec3c8a1b3c360a5bbc05120ca4cdbda62f15be0c4c0b45f46882bc9e
data/README.md CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
53
  in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 1.51', require: false
56
+ gem 'rubocop', '~> 1.52', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -2484,10 +2484,9 @@ Lint/UselessRuby2Keywords:
2484
2484
  Lint/UselessSetterCall:
2485
2485
  Description: 'Checks for useless setter call to a local variable.'
2486
2486
  Enabled: true
2487
- SafeAutoCorrect: false
2487
+ Safe: false
2488
2488
  VersionAdded: '0.13'
2489
2489
  VersionChanged: '1.2'
2490
- Safe: false
2491
2490
 
2492
2491
  Lint/UselessTimes:
2493
2492
  Description: 'Checks for useless `Integer#times` calls.'
@@ -3363,6 +3362,7 @@ Style/CollectionCompact:
3363
3362
  Safe: false
3364
3363
  VersionAdded: '1.2'
3365
3364
  VersionChanged: '1.3'
3365
+ AllowedReceivers: []
3366
3366
 
3367
3367
  # Align with the style guide.
3368
3368
  Style/CollectionMethods:
@@ -4383,6 +4383,7 @@ Style/MultipleComparison:
4383
4383
  VersionAdded: '0.49'
4384
4384
  VersionChanged: '1.1'
4385
4385
  AllowMethodComparison: true
4386
+ ComparisonsThreshold: 2
4386
4387
 
4387
4388
  Style/MutableConstant:
4388
4389
  Description: 'Do not assign mutable objects to constants.'
@@ -4805,6 +4806,11 @@ Style/RedundantArgument:
4805
4806
  # String#chomp!
4806
4807
  chomp!: "\n"
4807
4808
 
4809
+ Style/RedundantArrayConstructor:
4810
+ Description: 'Checks for the instantiation of array using redundant `Array` constructor.'
4811
+ Enabled: pending
4812
+ VersionAdded: '1.52'
4813
+
4808
4814
  Style/RedundantAssignment:
4809
4815
  Description: 'Checks for redundant assignment before returning.'
4810
4816
  Enabled: true
@@ -4876,6 +4882,13 @@ Style/RedundantFileExtensionInRequire:
4876
4882
  Enabled: true
4877
4883
  VersionAdded: '0.88'
4878
4884
 
4885
+ Style/RedundantFilterChain:
4886
+ Description: >-
4887
+ Identifies usages of `any?`, `empty?`, `none?` or `one?` predicate methods chained to
4888
+ `select`/`filter`/`find_all` and change them to use predicate method instead.
4889
+ Enabled: pending
4890
+ VersionAdded: '1.52'
4891
+
4879
4892
  Style/RedundantFreeze:
4880
4893
  Description: "Checks usages of Object#freeze on immutable objects."
4881
4894
  Enabled: true
@@ -4923,6 +4936,11 @@ Style/RedundantRegexpCharacterClass:
4923
4936
  Enabled: true
4924
4937
  VersionAdded: '0.85'
4925
4938
 
4939
+ Style/RedundantRegexpConstructor:
4940
+ Description: 'Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.'
4941
+ Enabled: pending
4942
+ VersionAdded: '1.52'
4943
+
4926
4944
  Style/RedundantRegexpEscape:
4927
4945
  Description: 'Checks for redundant escapes in Regexps.'
4928
4946
  Enabled: true
@@ -284,7 +284,7 @@ module RuboCop
284
284
  # @api private
285
285
  def self.callbacks_needed
286
286
  @callbacks_needed ||= public_instance_methods.select do |m|
287
- m.match?(/^on_|^after_/) &&
287
+ m.start_with?(/on_|after_/) &&
288
288
  !Base.method_defined?(m) # exclude standard "callbacks" like 'on_begin_investigation'
289
289
  end
290
290
  end
@@ -58,6 +58,7 @@ module RuboCop
58
58
 
59
59
  def on_class(node)
60
60
  return unless node.parent_class && exception_class?(node.parent_class)
61
+ return if inherit_exception_class_with_omitted_namespace?(node)
61
62
 
62
63
  message = message(node.parent_class)
63
64
 
@@ -87,6 +88,12 @@ module RuboCop
87
88
  class_node.const_name == 'Exception'
88
89
  end
89
90
 
91
+ def inherit_exception_class_with_omitted_namespace?(class_node)
92
+ return false if class_node.parent_class.namespace&.cbase_type?
93
+
94
+ class_node.left_siblings.any? { |sibling| exception_class?(sibling.identifier) }
95
+ end
96
+
90
97
  def preferred_base_class
91
98
  PREFERRED_BASE_CLASS[style]
92
99
  end
@@ -11,6 +11,9 @@ module RuboCop
11
11
  # missing method. In other cases, the theoretical ideal handling could be
12
12
  # challenging or verbose for no actual gain.
13
13
  #
14
+ # Autocorrection is not supported because the position of `super` cannot be
15
+ # determined automatically.
16
+ #
14
17
  # @example
15
18
  # # bad
16
19
  # class Employee < Person
@@ -49,7 +49,7 @@ module RuboCop
49
49
  # do_something if attrs&.not_nil_safe_method(:[])
50
50
  #
51
51
  class RedundantSafeNavigation < Base
52
- include AllowedMethods
52
+ include NilMethods
53
53
  include RangeHelp
54
54
  extend AutoCorrector
55
55
 
@@ -63,7 +63,7 @@ module RuboCop
63
63
  PATTERN
64
64
 
65
65
  def on_csend(node)
66
- return unless check?(node) && allowed_method?(node.method_name)
66
+ return unless check?(node) && nil_methods.include?(node.method_name)
67
67
  return if respond_to_nil_specific_method?(node)
68
68
 
69
69
  range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
@@ -132,10 +132,11 @@ module RuboCop
132
132
  node.receiver.nil? && !node.arguments?
133
133
  end
134
134
 
135
+ # rubocop:disable Metrics/AbcSize
135
136
  def autocorrect(corrector, assignment)
136
137
  if assignment.exception_assignment?
137
138
  remove_exception_assignment_part(corrector, assignment.node)
138
- elsif assignment.multiple_assignment?
139
+ elsif assignment.multiple_assignment? || assignment.rest_assignment?
139
140
  rename_variable_with_underscore(corrector, assignment.node)
140
141
  elsif assignment.operator_assignment?
141
142
  remove_trailing_character_from_operator(corrector, assignment.node)
@@ -146,6 +147,7 @@ module RuboCop
146
147
  remove_local_variable_assignment_part(corrector, assignment.node)
147
148
  end
148
149
  end
150
+ # rubocop:enable Metrics/AbcSize
149
151
 
150
152
  def remove_exception_assignment_part(corrector, node)
151
153
  corrector.remove(
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This module encapsulates the ability to allow certain receivers in a cop.
6
+ module AllowedReceivers
7
+ def allowed_receiver?(receiver)
8
+ receiver_name = receiver_name(receiver)
9
+
10
+ allowed_receivers.include?(receiver_name)
11
+ end
12
+
13
+ def receiver_name(receiver)
14
+ if receiver.receiver && !receiver.receiver.const_type?
15
+ return receiver_name(receiver.receiver)
16
+ end
17
+
18
+ if receiver.send_type?
19
+ if receiver.receiver
20
+ "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
21
+ else
22
+ receiver.method_name.to_s
23
+ end
24
+ else
25
+ receiver.source
26
+ end
27
+ end
28
+
29
+ def allowed_receivers
30
+ cop_config.fetch('AllowedReceivers', [])
31
+ end
32
+ end
33
+ end
34
+ end
@@ -20,9 +20,14 @@ module RuboCop
20
20
  # # good
21
21
  # fooBar = 1
22
22
  #
23
+ # @example AllowedIdentifiers: ['fooBar']
24
+ # # good (with EnforcedStyle: snake_case)
25
+ # fooBar = 1
26
+ #
23
27
  # @example AllowedPatterns: ['_v\d+\z']
24
- # # good
28
+ # # good (with EnforcedStyle: camelCase)
25
29
  # :release_v1
30
+ #
26
31
  class VariableName < Base
27
32
  include AllowedIdentifiers
28
33
  include ConfigurableNaming
@@ -92,6 +92,7 @@ module RuboCop
92
92
  comment_line?(processed_source[node.first_line - 2])
93
93
  end
94
94
 
95
+ # rubocop:disable Metrics/CyclomaticComplexity
95
96
  def groupable_accessor?(node)
96
97
  return true unless (previous_expression = node.left_siblings.last)
97
98
 
@@ -104,8 +105,11 @@ module RuboCop
104
105
 
105
106
  return true unless previous_expression.send_type?
106
107
 
107
- previous_expression.attribute_accessor? || previous_expression.access_modifier?
108
+ previous_expression.attribute_accessor? ||
109
+ previous_expression.access_modifier? ||
110
+ node.first_line - previous_expression.last_line > 1 # there is a space between nodes
108
111
  end
112
+ # rubocop:enable Metrics/CyclomaticComplexity
109
113
 
110
114
  def class_send_elements(class_node)
111
115
  class_def = class_node.body
@@ -139,7 +139,7 @@ module RuboCop
139
139
  end
140
140
 
141
141
  def check_style(node, body)
142
- return if node.identifier.children[0]&.cbase_type?
142
+ return if node.identifier.namespace&.cbase_type?
143
143
 
144
144
  if style == :nested
145
145
  check_nested_style(node)
@@ -35,7 +35,12 @@ module RuboCop
35
35
  # # good
36
36
  # hash.compact!
37
37
  #
38
+ # @example AllowedReceivers: ['params']
39
+ # # good
40
+ # params.reject(&:nil?)
41
+ #
38
42
  class CollectionCompact < Base
43
+ include AllowedReceivers
39
44
  include RangeHelp
40
45
  extend AutoCorrector
41
46
  extend TargetRubyVersion
@@ -76,6 +81,7 @@ module RuboCop
76
81
 
77
82
  def on_send(node)
78
83
  return unless (range = offense_range(node))
84
+ return if allowed_receiver?(node.receiver)
79
85
  if (target_ruby_version <= 3.0 || node.method?(:delete_if)) && to_enum_method?(node)
80
86
  return
81
87
  end
@@ -57,7 +57,7 @@ module RuboCop
57
57
  extend AutoCorrector
58
58
 
59
59
  MSG = 'Pass `__FILE__` and `__LINE__` to `%<method_name>s`.'
60
- MSG_EVAL = 'Pass a binding, `__FILE__` and `__LINE__` to `eval`.'
60
+ MSG_EVAL = 'Pass a binding, `__FILE__`, and `__LINE__` to `eval`.'
61
61
  MSG_INCORRECT_FILE = 'Incorrect file for `%<method_name>s`; ' \
62
62
  'use `%<expected>s` instead of `%<actual>s`.'
63
63
  MSG_INCORRECT_LINE = 'Incorrect line number for `%<method_name>s`; ' \
@@ -41,8 +41,7 @@ module RuboCop
41
41
  return unless (regexp = exact_regexp_match(node))
42
42
 
43
43
  parsed_regexp = Regexp::Parser.parse(regexp)
44
- tokens = parsed_regexp.map(&:token)
45
- return unless tokens[0] == :bos && tokens[1] == :literal && tokens[2] == :eos
44
+ return unless exact_match_pattern?(parsed_regexp)
46
45
 
47
46
  prefer = "#{node.receiver.source} #{new_method(node)} '#{parsed_regexp[1].text}'"
48
47
 
@@ -53,6 +52,13 @@ module RuboCop
53
52
 
54
53
  private
55
54
 
55
+ def exact_match_pattern?(parsed_regexp)
56
+ tokens = parsed_regexp.map(&:token)
57
+ return false unless tokens[0] == :bos && tokens[1] == :literal && tokens[2] == :eos
58
+
59
+ !parsed_regexp[1].quantifier
60
+ end
61
+
56
62
  def new_method(node)
57
63
  node.method?(:!~) ? '!=' : '=='
58
64
  end
@@ -28,6 +28,7 @@ module RuboCop
28
28
  # execute(sql).keys.each { |v| p v }
29
29
  # execute(sql).values.each { |v| p v }
30
30
  class HashEachMethods < Base
31
+ include AllowedReceivers
31
32
  include Lint::UnusedArgument
32
33
  extend AutoCorrector
33
34
 
@@ -116,28 +117,6 @@ module RuboCop
116
117
  def kv_range(outer_node)
117
118
  outer_node.receiver.loc.selector.join(outer_node.loc.selector)
118
119
  end
119
-
120
- def allowed_receiver?(receiver)
121
- receiver_name = receiver_name(receiver)
122
-
123
- allowed_receivers.include?(receiver_name)
124
- end
125
-
126
- def receiver_name(receiver)
127
- if receiver.send_type?
128
- if receiver.receiver
129
- "#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
130
- else
131
- receiver.method_name.to_s
132
- end
133
- else
134
- receiver.source
135
- end
136
- end
137
-
138
- def allowed_receivers
139
- cop_config.fetch('AllowedReceivers', [])
140
- end
141
120
  end
142
121
  end
143
122
  end
@@ -135,8 +135,7 @@ module RuboCop
135
135
  end
136
136
 
137
137
  def call_with_braced_block?(node)
138
- (node.send_type? || node.super_type?) &&
139
- ((node.parent&.block_type? || node.parent&.numblock_type?) && node.parent&.braces?)
138
+ (node.send_type? || node.super_type?) && node.block_node&.braces?
140
139
  end
141
140
 
142
141
  def call_as_argument_or_chain?(node)
@@ -40,6 +40,15 @@ module RuboCop
40
40
  #
41
41
  # # good
42
42
  # foo if [b.lightweight, b.heavyweight].include?(a)
43
+ #
44
+ # @example ComparisonsThreshold: 2 (default)
45
+ # # bad
46
+ # foo if a == 'a' || a == 'b'
47
+ #
48
+ # @example ComparisonsThreshold: 3
49
+ # # good
50
+ # foo if a == 'a' || a == 'b'
51
+ #
43
52
  class MultipleComparison < Base
44
53
  extend AutoCorrector
45
54
 
@@ -58,6 +67,7 @@ module RuboCop
58
67
  return unless node == root_of_or_node
59
68
  return unless nested_variable_comparison?(root_of_or_node)
60
69
  return if @allowed_method_comparison
70
+ return if @compared_elements.size < comparisons_threshold
61
71
 
62
72
  add_offense(node) do |corrector|
63
73
  elements = @compared_elements.join(', ')
@@ -151,6 +161,10 @@ module RuboCop
151
161
  def allow_method_comparison?
152
162
  cop_config.fetch('AllowMethodComparison', true)
153
163
  end
164
+
165
+ def comparisons_threshold
166
+ cop_config.fetch('ComparisonsThreshold', 2)
167
+ end
154
168
  end
155
169
  end
156
170
  end
@@ -121,7 +121,7 @@ module RuboCop
121
121
 
122
122
  def allowed_patterns
123
123
  # Convert the patterns to be anchored
124
- super.map { |regexp| Regexp.new(/\A#{regexp}\z/) }
124
+ super.map { |regexp| /\A#{regexp}\z/ }
125
125
  end
126
126
  end
127
127
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for the instantiation of array using redundant `Array` constructor.
7
+ # Autocorrect replaces to array literal which is the simplest and fastest.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Array.new([])
13
+ # Array[]
14
+ # Array([])
15
+ # Array.new(['foo', 'foo', 'foo'])
16
+ # Array['foo', 'foo', 'foo']
17
+ # Array(['foo', 'foo', 'foo'])
18
+ #
19
+ # # good
20
+ # []
21
+ # ['foo', 'foo', 'foo']
22
+ # Array.new(3, 'foo')
23
+ # Array.new(3) { 'foo' }
24
+ #
25
+ class RedundantArrayConstructor < Base
26
+ extend AutoCorrector
27
+
28
+ MSG = 'Remove the redundant `Array` constructor.'
29
+
30
+ RESTRICT_ON_SEND = %i[new [] Array].freeze
31
+
32
+ # @!method redundant_array_constructor(node)
33
+ def_node_matcher :redundant_array_constructor, <<~PATTERN
34
+ {
35
+ (send
36
+ (const {nil? cbase} :Array) :new
37
+ $(array ...))
38
+ (send
39
+ (const {nil? cbase} :Array) :[]
40
+ $...)
41
+ (send
42
+ nil? :Array
43
+ $(array ...))
44
+ }
45
+ PATTERN
46
+
47
+ def on_send(node)
48
+ return unless (array_literal = redundant_array_constructor(node))
49
+
50
+ receiver = node.receiver
51
+ selector = node.loc.selector
52
+
53
+ if node.method?(:new)
54
+ range = receiver.source_range.join(selector)
55
+ replacement = array_literal
56
+ elsif node.method?(:Array)
57
+ range = selector
58
+ replacement = array_literal
59
+ else
60
+ range = receiver
61
+ replacement = selector.begin.join(node.source_range.end)
62
+ end
63
+
64
+ register_offense(range, node, replacement)
65
+ end
66
+
67
+ private
68
+
69
+ def register_offense(range, node, replacement)
70
+ add_offense(range) do |corrector|
71
+ corrector.replace(node, replacement.source)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Identifies usages of `any?`, `empty?` or `none?` predicate methods
7
+ # chained to `select`/`filter`/`find_all` and change them to use predicate method instead.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # arr.select { |x| x > 1 }.any?
12
+ #
13
+ # # good
14
+ # arr.any? { |x| x > 1 }
15
+ #
16
+ # # bad
17
+ # arr.select { |x| x > 1 }.empty?
18
+ # arr.select { |x| x > 1 }.none?
19
+ #
20
+ # # good
21
+ # arr.none? { |x| x > 1 }
22
+ #
23
+ # # good
24
+ # relation.select(:name).any?
25
+ # arr.select { |x| x > 1 }.any?(&:odd?)
26
+ #
27
+ # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
28
+ # # good
29
+ # arr.select { |x| x > 1 }.many?
30
+ #
31
+ # @example AllCops:ActiveSupportExtensionsEnabled: true
32
+ # # bad
33
+ # arr.select { |x| x > 1 }.many?
34
+ #
35
+ # # good
36
+ # arr.many? { |x| x > 1 }
37
+ #
38
+ class RedundantFilterChain < Base
39
+ extend AutoCorrector
40
+
41
+ MSG = 'Use `%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
42
+
43
+ RAILS_METHODS = %i[many?].freeze
44
+ RESTRICT_ON_SEND = (%i[any? empty? none? one?] + RAILS_METHODS).freeze
45
+
46
+ # @!method select_predicate?(node)
47
+ def_node_matcher :select_predicate?, <<~PATTERN
48
+ (send
49
+ {
50
+ (block $(send _ {:select :filter :find_all}) ...)
51
+ $(send _ {:select :filter :find_all} block_pass_type?)
52
+ }
53
+ ${:#{RESTRICT_ON_SEND.join(' :')}})
54
+ PATTERN
55
+
56
+ REPLACEMENT_METHODS = {
57
+ any?: :any?,
58
+ empty?: :none?,
59
+ none?: :none?,
60
+ one?: :one?,
61
+ many?: :many?
62
+ }.freeze
63
+ private_constant :REPLACEMENT_METHODS
64
+
65
+ def on_send(node)
66
+ return if node.arguments? || node.block_node
67
+
68
+ select_predicate?(node) do |select_node, filter_method|
69
+ return if RAILS_METHODS.include?(filter_method) && !active_support_extensions_enabled?
70
+
71
+ register_offense(select_node, node)
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def register_offense(select_node, predicate_node)
78
+ replacement = REPLACEMENT_METHODS[predicate_node.method_name]
79
+ message = format(MSG, prefer: replacement,
80
+ first_method: select_node.method_name,
81
+ second_method: predicate_node.method_name)
82
+
83
+ offense_range = offense_range(select_node, predicate_node)
84
+
85
+ add_offense(offense_range, message: message) do |corrector|
86
+ corrector.remove(predicate_range(predicate_node))
87
+ corrector.replace(select_node.loc.selector, replacement)
88
+ end
89
+ end
90
+
91
+ def offense_range(select_node, predicate_node)
92
+ select_node.loc.selector.join(predicate_node.loc.selector)
93
+ end
94
+
95
+ def predicate_range(predicate_node)
96
+ predicate_node.receiver.source_range.end.join(predicate_node.loc.selector)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.
7
+ # Autocorrect replaces to regexp literal which is the simplest and fastest.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # Regexp.new(/regexp/)
13
+ # Regexp.compile(/regexp/)
14
+ #
15
+ # # good
16
+ # /regexp/
17
+ # Regexp.new('regexp')
18
+ # Regexp.compile('regexp')
19
+ #
20
+ class RedundantRegexpConstructor < Base
21
+ extend AutoCorrector
22
+
23
+ MSG = 'Remove the redundant `Regexp.%<method>s`.'
24
+ RESTRICT_ON_SEND = %i[new compile].freeze
25
+
26
+ # @!method redundant_regexp_constructor(node)
27
+ def_node_matcher :redundant_regexp_constructor, <<~PATTERN
28
+ (send
29
+ (const {nil? cbase} :Regexp) {:new :compile}
30
+ (regexp $... (regopt $...)))
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ return unless (regexp, regopt = redundant_regexp_constructor(node))
35
+
36
+ add_offense(node, message: format(MSG, method: node.method_name)) do |corrector|
37
+ pattern = regexp.map(&:source).join
38
+ regopt = regopt.join
39
+
40
+ corrector.replace(node, "/#{pattern}/#{regopt}")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -106,8 +106,9 @@ module RuboCop
106
106
  break unless sibling&.send_type? && sibling&.method?(node.method_name)
107
107
  break unless sibling.arguments? && !sibling.receiver
108
108
  break unless in_same_section?(sibling, node)
109
+ break unless node.first_argument.str_type? && sibling.first_argument.str_type?
109
110
 
110
- node.first_argument.source < sibling.first_argument.source
111
+ node.first_argument.value < sibling.first_argument.value
111
112
  end
112
113
  end
113
114
 
@@ -3,9 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks for uses of rescue in its modifier form.
7
- #
8
- # The cop to check `rescue` in its modifier form is added for following
6
+ # Checks for uses of `rescue` in its modifier form is added for following
9
7
  # reasons:
10
8
  #
11
9
  # * The syntax of modifier form `rescue` can be misleading because it
@@ -84,6 +84,7 @@ module RuboCop
84
84
  }
85
85
  PATTERN
86
86
 
87
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
87
88
  def on_send(node)
88
89
  return unless (block_node = node.block_node)
89
90
  return if block_node.body&.begin_type?
@@ -91,11 +92,14 @@ module RuboCop
91
92
  return unless (regexp_method_send_node = extract_send_node(block_node))
92
93
  return if match_predicate_without_receiver?(regexp_method_send_node)
93
94
 
94
- opposite = opposite?(regexp_method_send_node)
95
+ replacement = replacement(regexp_method_send_node, node)
96
+ return if target_ruby_version <= 2.2 && replacement == 'grep_v'
97
+
95
98
  regexp = find_regexp(regexp_method_send_node, block_node)
96
99
 
97
- register_offense(node, block_node, regexp, opposite)
100
+ register_offense(node, block_node, regexp, replacement)
98
101
  end
102
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
99
103
 
100
104
  private
101
105
 
@@ -105,9 +109,15 @@ module RuboCop
105
109
  node.hash_type? || creates_hash?(node) || env_const?(node)
106
110
  end
107
111
 
108
- def register_offense(node, block_node, regexp, opposite)
109
- method_name = node.method_name.to_sym
110
- replacement = opposite ? OPPOSITE_REPLACEMENTS[method_name] : REPLACEMENTS[method_name]
112
+ def replacement(regexp_method_send_node, node)
113
+ opposite = opposite?(regexp_method_send_node)
114
+
115
+ method_name = node.method_name
116
+
117
+ opposite ? OPPOSITE_REPLACEMENTS[method_name] : REPLACEMENTS[method_name]
118
+ end
119
+
120
+ def register_offense(node, block_node, regexp, replacement)
111
121
  message = format(MSG, replacement: replacement, original_method: node.method_name)
112
122
 
113
123
  add_offense(block_node, message: message) do |corrector|
@@ -135,7 +135,7 @@ module RuboCop
135
135
 
136
136
  def disallow_endless_method_style?
137
137
  endless_method_config = config.for_cop('Style/EndlessMethod')
138
- return false unless endless_method_config['Enabled']
138
+ return true unless endless_method_config['Enabled']
139
139
 
140
140
  endless_method_config['EnforcedStyle'] == 'disallow'
141
141
  end
@@ -63,6 +63,12 @@ module RuboCop
63
63
  meta_assignment_node.type == MULTIPLE_ASSIGNMENT_TYPE
64
64
  end
65
65
 
66
+ def rest_assignment?
67
+ return false unless meta_assignment_node
68
+
69
+ meta_assignment_node.type == REST_ASSIGNMENT_TYPE
70
+ end
71
+
66
72
  def operator
67
73
  assignment_node = meta_assignment_node || @node
68
74
  assignment_node.loc.operator.source
@@ -70,7 +76,9 @@ module RuboCop
70
76
 
71
77
  def meta_assignment_node
72
78
  unless instance_variable_defined?(:@meta_assignment_node)
73
- @meta_assignment_node = operator_assignment_node || multiple_assignment_node
79
+ @meta_assignment_node = operator_assignment_node ||
80
+ multiple_assignment_node ||
81
+ rest_assignment_node
74
82
  end
75
83
 
76
84
  @meta_assignment_node
@@ -94,6 +102,13 @@ module RuboCop
94
102
 
95
103
  grandparent_node
96
104
  end
105
+
106
+ def rest_assignment_node
107
+ return nil unless node.parent
108
+ return nil unless node.parent.type == REST_ASSIGNMENT_TYPE
109
+
110
+ node.parent
111
+ end
97
112
  end
98
113
  end
99
114
  end
@@ -40,6 +40,7 @@ module RuboCop
40
40
  OPERATOR_ASSIGNMENT_TYPES = (LOGICAL_OPERATOR_ASSIGNMENT_TYPES + [:op_asgn]).freeze
41
41
 
42
42
  MULTIPLE_ASSIGNMENT_TYPE = :masgn
43
+ REST_ASSIGNMENT_TYPE = :splat
43
44
 
44
45
  VARIABLE_REFERENCE_TYPE = :lvar
45
46
 
@@ -18,10 +18,11 @@ module RuboCop
18
18
  def run
19
19
  ensure_server!
20
20
  Cache.status_path.delete if Cache.status_path.file?
21
+ read_stdin = ARGV.include?('-s') || ARGV.include?('--stdin')
21
22
  send_request(
22
23
  command: 'exec',
23
24
  args: ARGV.dup,
24
- body: $stdin.tty? ? '' : $stdin.read
25
+ body: read_stdin ? $stdin.read : ''
25
26
  )
26
27
  warn stderr unless stderr.empty?
27
28
  status
@@ -3,15 +3,19 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.51.0'
6
+ STRING = '1.52.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
10
10
  'running on %<ruby_engine>s %<ruby_version>s)%<server_mode>s [%<ruby_platform>s]'
11
11
 
12
- CANONICAL_FEATURE_NAMES = { 'Rspec' => 'RSpec', 'Graphql' => 'GraphQL', 'Md' => 'Markdown',
13
- 'Thread_safety' => 'ThreadSafety' }.freeze
14
- EXTENSION_PATH_NAMES = { 'rubocop-md' => 'markdown' }.freeze
12
+ CANONICAL_FEATURE_NAMES = {
13
+ 'Rspec' => 'RSpec', 'Graphql' => 'GraphQL', 'Md' => 'Markdown', 'Factory_bot' => 'FactoryBot',
14
+ 'Thread_safety' => 'ThreadSafety'
15
+ }.freeze
16
+ EXTENSION_PATH_NAMES = {
17
+ 'rubocop-md' => 'markdown', 'rubocop-factory_bot' => 'factory_bot'
18
+ }.freeze
15
19
 
16
20
  # @api private
17
21
  def self.version(debug: false, env: nil)
data/lib/rubocop.rb CHANGED
@@ -69,6 +69,7 @@ require_relative 'rubocop/cop/mixin/alignment'
69
69
  require_relative 'rubocop/cop/mixin/allowed_identifiers'
70
70
  require_relative 'rubocop/cop/mixin/allowed_methods'
71
71
  require_relative 'rubocop/cop/mixin/allowed_pattern'
72
+ require_relative 'rubocop/cop/mixin/allowed_receivers'
72
73
  require_relative 'rubocop/cop/mixin/auto_corrector' # rubocop:todo Naming/InclusiveLanguage
73
74
  require_relative 'rubocop/cop/mixin/check_assignment'
74
75
  require_relative 'rubocop/cop/mixin/check_line_breakable'
@@ -558,15 +559,18 @@ require_relative 'rubocop/cop/style/multiline_in_pattern_then'
558
559
  require_relative 'rubocop/cop/style/numbered_parameters'
559
560
  require_relative 'rubocop/cop/style/open_struct_use'
560
561
  require_relative 'rubocop/cop/style/operator_method_call'
562
+ require_relative 'rubocop/cop/style/redundant_array_constructor'
561
563
  require_relative 'rubocop/cop/style/redundant_assignment'
562
564
  require_relative 'rubocop/cop/style/redundant_constant_base'
563
565
  require_relative 'rubocop/cop/style/redundant_double_splat_hash_braces'
564
566
  require_relative 'rubocop/cop/style/redundant_each'
565
567
  require_relative 'rubocop/cop/style/redundant_fetch_block'
566
568
  require_relative 'rubocop/cop/style/redundant_file_extension_in_require'
569
+ require_relative 'rubocop/cop/style/redundant_filter_chain'
567
570
  require_relative 'rubocop/cop/style/redundant_heredoc_delimiter_quotes'
568
571
  require_relative 'rubocop/cop/style/redundant_initialize'
569
572
  require_relative 'rubocop/cop/style/redundant_line_continuation'
573
+ require_relative 'rubocop/cop/style/redundant_regexp_constructor'
570
574
  require_relative 'rubocop/cop/style/redundant_self_assignment'
571
575
  require_relative 'rubocop/cop/style/redundant_self_assignment_branch'
572
576
  require_relative 'rubocop/cop/style/require_order'
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.51.0
4
+ version: 1.52.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
8
8
  - Jonas Arvidsson
9
9
  - Yuji Nakayama
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2023-05-13 00:00:00.000000000 Z
13
+ date: 2023-06-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
@@ -550,6 +550,7 @@ files:
550
550
  - lib/rubocop/cop/mixin/allowed_identifiers.rb
551
551
  - lib/rubocop/cop/mixin/allowed_methods.rb
552
552
  - lib/rubocop/cop/mixin/allowed_pattern.rb
553
+ - lib/rubocop/cop/mixin/allowed_receivers.rb
553
554
  - lib/rubocop/cop/mixin/annotation_comment.rb
554
555
  - lib/rubocop/cop/mixin/array_min_size.rb
555
556
  - lib/rubocop/cop/mixin/array_syntax.rb
@@ -815,6 +816,7 @@ files:
815
816
  - lib/rubocop/cop/style/raise_args.rb
816
817
  - lib/rubocop/cop/style/random_with_offset.rb
817
818
  - lib/rubocop/cop/style/redundant_argument.rb
819
+ - lib/rubocop/cop/style/redundant_array_constructor.rb
818
820
  - lib/rubocop/cop/style/redundant_assignment.rb
819
821
  - lib/rubocop/cop/style/redundant_begin.rb
820
822
  - lib/rubocop/cop/style/redundant_capital_w.rb
@@ -826,6 +828,7 @@ files:
826
828
  - lib/rubocop/cop/style/redundant_exception.rb
827
829
  - lib/rubocop/cop/style/redundant_fetch_block.rb
828
830
  - lib/rubocop/cop/style/redundant_file_extension_in_require.rb
831
+ - lib/rubocop/cop/style/redundant_filter_chain.rb
829
832
  - lib/rubocop/cop/style/redundant_freeze.rb
830
833
  - lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb
831
834
  - lib/rubocop/cop/style/redundant_initialize.rb
@@ -834,6 +837,7 @@ files:
834
837
  - lib/rubocop/cop/style/redundant_parentheses.rb
835
838
  - lib/rubocop/cop/style/redundant_percent_q.rb
836
839
  - lib/rubocop/cop/style/redundant_regexp_character_class.rb
840
+ - lib/rubocop/cop/style/redundant_regexp_constructor.rb
837
841
  - lib/rubocop/cop/style/redundant_regexp_escape.rb
838
842
  - lib/rubocop/cop/style/redundant_return.rb
839
843
  - lib/rubocop/cop/style/redundant_self.rb
@@ -992,10 +996,10 @@ metadata:
992
996
  homepage_uri: https://rubocop.org/
993
997
  changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md
994
998
  source_code_uri: https://github.com/rubocop/rubocop/
995
- documentation_uri: https://docs.rubocop.org/rubocop/1.51/
999
+ documentation_uri: https://docs.rubocop.org/rubocop/1.52/
996
1000
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues
997
1001
  rubygems_mfa_required: 'true'
998
- post_install_message:
1002
+ post_install_message:
999
1003
  rdoc_options: []
1000
1004
  require_paths:
1001
1005
  - lib
@@ -1010,8 +1014,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1010
1014
  - !ruby/object:Gem::Version
1011
1015
  version: '0'
1012
1016
  requirements: []
1013
- rubygems_version: 3.4.6
1014
- signing_key:
1017
+ rubygems_version: 3.3.7
1018
+ signing_key:
1015
1019
  specification_version: 4
1016
1020
  summary: Automatic Ruby code style checking tool.
1017
1021
  test_files: []