rubocop 1.51.0 → 1.52.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +20 -2
- data/lib/rubocop/cop/base.rb +1 -1
- data/lib/rubocop/cop/lint/inherit_exception.rb +7 -0
- data/lib/rubocop/cop/lint/missing_super.rb +3 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +2 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +3 -1
- data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
- data/lib/rubocop/cop/naming/variable_name.rb +6 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
- data/lib/rubocop/cop/style/collection_compact.rb +6 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +8 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -2
- data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
- data/lib/rubocop/cop/style/require_order.rb +2 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
- data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +16 -1
- data/lib/rubocop/cop/variable_force.rb +1 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/version.rb +8 -4
- data/lib/rubocop.rb +4 -0
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5301525d37bb844594d465a40a1e5643646f2b85a3bbd7258ce92af20c1d82bd
|
4
|
+
data.tar.gz: 3a1ba98652dc97a41f5ee5828160a9a74b59c806b3da618742e879a92d5ba596
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
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
|
data/lib/rubocop/cop/base.rb
CHANGED
@@ -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.
|
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
|
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) &&
|
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? ||
|
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
|
@@ -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__
|
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
|
-
|
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
|
@@ -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.
|
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
|
-
|
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,
|
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
|
109
|
-
|
110
|
-
|
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
|
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 ||
|
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
|
@@ -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.
|
25
|
+
body: read_stdin ? $stdin.read : ''
|
25
26
|
)
|
26
27
|
warn stderr unless stderr.empty?
|
27
28
|
status
|
data/lib/rubocop/version.rb
CHANGED
@@ -3,15 +3,19 @@
|
|
3
3
|
module RuboCop
|
4
4
|
# This module holds the RuboCop version information.
|
5
5
|
module Version
|
6
|
-
STRING = '1.
|
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 = {
|
13
|
-
|
14
|
-
|
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.
|
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-
|
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.
|
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.
|
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: []
|