rubocop 1.51.0 → 1.52.0

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 (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: []