rubocop-performance 1.19.0 → 1.20.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.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/config/default.yml +16 -16
- data/lib/rubocop/cop/mixin/sort_block.rb +2 -2
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +1 -1
- data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +4 -0
- data/lib/rubocop/cop/performance/count.rb +5 -5
- data/lib/rubocop/cop/performance/fixed_size.rb +2 -1
- data/lib/rubocop/cop/performance/flat_map.rb +4 -3
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +2 -2
- data/lib/rubocop/cop/performance/map_compact.rb +2 -2
- data/lib/rubocop/cop/performance/map_method_chain.rb +3 -1
- data/lib/rubocop/cop/performance/range_include.rb +8 -6
- data/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb +1 -1
- data/lib/rubocop/cop/performance/redundant_match.rb +30 -1
- data/lib/rubocop/cop/performance/redundant_merge.rb +3 -1
- data/lib/rubocop/cop/performance/reverse_each.rb +1 -1
- data/lib/rubocop/cop/performance/reverse_first.rb +5 -13
- data/lib/rubocop/cop/performance/select_map.rb +2 -6
- data/lib/rubocop/cop/performance/size.rb +4 -3
- data/lib/rubocop/cop/performance/sort_reverse.rb +5 -4
- data/lib/rubocop/cop/performance/string_identifier_argument.rb +16 -2
- data/lib/rubocop/cop/performance/string_include.rb +3 -2
- data/lib/rubocop/cop/performance/sum.rb +11 -9
- data/lib/rubocop/cop/performance/times_map.rb +14 -2
- data/lib/rubocop/cop/performance/unfreeze_string.rb +6 -3
- data/lib/rubocop/performance/version.rb +1 -1
- data/lib/rubocop-performance.rb +8 -0
- metadata +14 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afce4fa4bdd79fa5f4429edcdb3fa157f94be3f2526630db7d342c56fd5d741b
|
4
|
+
data.tar.gz: 833a0a5c44c55a7e30640c7658f54e5a28c5a362add04c60b434fa9f58b61136
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62dea0dda6f9fc634e7d7d418ba980bb106d698db3d7242da2c81c9abc49124748dc553bf413e9281fe6969d1b29ef991d58e2e2a6211c759f27cbe36a99cfe4
|
7
|
+
data.tar.gz: 046a795365aa47793e3afa36cc0685cc44851573210669945a8b6bda73d8edcb38ca6acc522d17009ea722a6c84e68c21ddc759181ba1840cac7c566e76b0220
|
data/README.md
CHANGED
data/config/default.yml
CHANGED
@@ -6,7 +6,7 @@ Performance:
|
|
6
6
|
|
7
7
|
Performance/AncestorsInclude:
|
8
8
|
Description: 'Use `A <= B` instead of `A.ancestors.include?(B)`.'
|
9
|
-
Reference: 'https://github.com/
|
9
|
+
Reference: 'https://github.com/fastruby/fast-ruby#ancestorsinclude-vs--code'
|
10
10
|
Enabled: 'pending'
|
11
11
|
Safe: false
|
12
12
|
VersionAdded: '1.7'
|
@@ -54,7 +54,7 @@ Performance/CaseWhenSplat:
|
|
54
54
|
Performance/Casecmp:
|
55
55
|
Description: >-
|
56
56
|
Use `casecmp` rather than `downcase ==`, `upcase ==`, `== downcase`, or `== upcase`..
|
57
|
-
Reference: 'https://github.com/
|
57
|
+
Reference: 'https://github.com/fastruby/fast-ruby#stringcasecmp-vs--stringcasecmp-vs-stringdowncase---code'
|
58
58
|
Enabled: true
|
59
59
|
Safe: false
|
60
60
|
VersionAdded: '0.36'
|
@@ -122,7 +122,7 @@ Performance/Detect:
|
|
122
122
|
Description: >-
|
123
123
|
Use `detect` instead of `select.first`, `find_all.first`, `filter.first`,
|
124
124
|
`select.last`, `find_all.last`, and `filter.last`.
|
125
|
-
Reference: 'https://github.com/
|
125
|
+
Reference: 'https://github.com/fastruby/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
|
126
126
|
# This cop has known compatibility issues with `ActiveRecord` and other
|
127
127
|
# frameworks. `ActiveRecord` does not implement a `detect` method and `find`
|
128
128
|
# has its own meaning. Correcting `ActiveRecord` methods with this cop
|
@@ -145,7 +145,7 @@ Performance/DoubleStartEndWith:
|
|
145
145
|
|
146
146
|
Performance/EndWith:
|
147
147
|
Description: 'Use `end_with?` instead of a regex match anchored to the end of a string.'
|
148
|
-
Reference: 'https://github.com/
|
148
|
+
Reference: 'https://github.com/fastruby/fast-ruby#stringmatch-vs-stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
|
149
149
|
# This will change to a new method call which isn't guaranteed to be on the
|
150
150
|
# object. Switching these methods has to be done with knowledge of the types
|
151
151
|
# of the variables which rubocop doesn't have.
|
@@ -165,7 +165,7 @@ Performance/FlatMap:
|
|
165
165
|
Use `Enumerable#flat_map`
|
166
166
|
instead of `Enumerable#map...Array#flatten(1)`
|
167
167
|
or `Enumerable#collect..Array#flatten(1)`.
|
168
|
-
Reference: 'https://github.com/
|
168
|
+
Reference: 'https://github.com/fastruby/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code'
|
169
169
|
Enabled: true
|
170
170
|
VersionAdded: '0.30'
|
171
171
|
EnabledForFlattenWithoutParams: false
|
@@ -176,7 +176,7 @@ Performance/FlatMap:
|
|
176
176
|
|
177
177
|
Performance/InefficientHashSearch:
|
178
178
|
Description: 'Use `key?` or `value?` instead of `keys.include?` or `values.include?`.'
|
179
|
-
Reference: 'https://github.com/
|
179
|
+
Reference: 'https://github.com/fastruby/fast-ruby#hashkey-instead-of-hashkeysinclude-code'
|
180
180
|
Enabled: true
|
181
181
|
VersionAdded: '0.56'
|
182
182
|
Safe: false
|
@@ -201,7 +201,7 @@ Performance/MapMethodChain:
|
|
201
201
|
|
202
202
|
Performance/MethodObjectAsBlock:
|
203
203
|
Description: 'Use block explicitly instead of block-passing a method object.'
|
204
|
-
Reference: 'https://github.com/
|
204
|
+
Reference: 'https://github.com/fastruby/fast-ruby#normal-way-to-apply-method-vs-method-code'
|
205
205
|
Enabled: pending
|
206
206
|
VersionAdded: '1.9'
|
207
207
|
|
@@ -213,7 +213,7 @@ Performance/OpenStruct:
|
|
213
213
|
|
214
214
|
Performance/RangeInclude:
|
215
215
|
Description: 'Use `Range#cover?` instead of `Range#include?` (or `Range#member?`).'
|
216
|
-
Reference: 'https://github.com/
|
216
|
+
Reference: 'https://github.com/fastruby/fast-ruby#cover-vs-include-code'
|
217
217
|
Enabled: true
|
218
218
|
VersionAdded: '0.36'
|
219
219
|
VersionChanged: '1.7'
|
@@ -221,7 +221,7 @@ Performance/RangeInclude:
|
|
221
221
|
|
222
222
|
Performance/RedundantBlockCall:
|
223
223
|
Description: 'Use `yield` instead of `block.call`.'
|
224
|
-
Reference: 'https://github.com/
|
224
|
+
Reference: 'https://github.com/fastruby/fast-ruby#proccall-and-block-arguments-vs-yieldcode'
|
225
225
|
Enabled: true
|
226
226
|
VersionAdded: '0.36'
|
227
227
|
|
@@ -244,7 +244,7 @@ Performance/RedundantMatch:
|
|
244
244
|
|
245
245
|
Performance/RedundantMerge:
|
246
246
|
Description: 'Use Hash#[]=, rather than Hash#merge! with a single key-value pair.'
|
247
|
-
Reference: 'https://github.com/
|
247
|
+
Reference: 'https://github.com/fastruby/fast-ruby#hashmerge-vs-hash-code'
|
248
248
|
Enabled: true
|
249
249
|
Safe: false
|
250
250
|
VersionAdded: '0.36'
|
@@ -271,13 +271,13 @@ Performance/RegexpMatch:
|
|
271
271
|
Description: >-
|
272
272
|
Use `match?` instead of `Regexp#match`, `String#match`, `Symbol#match`,
|
273
273
|
`Regexp#===`, or `=~` when `MatchData` is not used.
|
274
|
-
Reference: 'https://github.com/
|
274
|
+
Reference: 'https://github.com/fastruby/fast-ruby#regexp-vs-regexpmatch-vs-regexpmatch-vs-stringmatch-vs-string-vs-stringmatch-code-'
|
275
275
|
Enabled: true
|
276
276
|
VersionAdded: '0.47'
|
277
277
|
|
278
278
|
Performance/ReverseEach:
|
279
279
|
Description: 'Use `reverse_each` instead of `reverse.each`.'
|
280
|
-
Reference: 'https://github.com/
|
280
|
+
Reference: 'https://github.com/fastruby/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code'
|
281
281
|
Enabled: true
|
282
282
|
VersionAdded: '0.30'
|
283
283
|
|
@@ -295,7 +295,7 @@ Performance/Size:
|
|
295
295
|
Description: >-
|
296
296
|
Use `size` instead of `count` for counting
|
297
297
|
the number of elements in `Array` and `Hash`.
|
298
|
-
Reference: 'https://github.com/
|
298
|
+
Reference: 'https://github.com/fastruby/fast-ruby#arraylength-vs-arraysize-vs-arraycount-code'
|
299
299
|
Enabled: true
|
300
300
|
VersionAdded: '0.30'
|
301
301
|
|
@@ -306,13 +306,13 @@ Performance/SortReverse:
|
|
306
306
|
|
307
307
|
Performance/Squeeze:
|
308
308
|
Description: "Use `squeeze('a')` instead of `gsub(/a+/, 'a')`."
|
309
|
-
Reference: 'https://github.com/
|
309
|
+
Reference: 'https://github.com/fastruby/fast-ruby#remove-extra-spaces-or-other-contiguous-characters-code'
|
310
310
|
Enabled: 'pending'
|
311
311
|
VersionAdded: '1.7'
|
312
312
|
|
313
313
|
Performance/StartWith:
|
314
314
|
Description: 'Use `start_with?` instead of a regex match anchored to the beginning of a string.'
|
315
|
-
Reference: 'https://github.com/
|
315
|
+
Reference: 'https://github.com/fastruby/fast-ruby#stringmatch-vs-stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
|
316
316
|
# This will change to a new method call which isn't guaranteed to be on the
|
317
317
|
# object. Switching these methods has to be done with knowledge of the types
|
318
318
|
# of the variables which rubocop doesn't have.
|
@@ -339,7 +339,7 @@ Performance/StringReplacement:
|
|
339
339
|
Use `tr` instead of `gsub` when you are replacing the same
|
340
340
|
number of characters. Use `delete` instead of `gsub` when
|
341
341
|
you are deleting characters.
|
342
|
-
Reference: 'https://github.com/
|
342
|
+
Reference: 'https://github.com/fastruby/fast-ruby#stringgsub-vs-stringtr-code'
|
343
343
|
Enabled: true
|
344
344
|
VersionAdded: '0.33'
|
345
345
|
|
@@ -9,14 +9,14 @@ module RuboCop
|
|
9
9
|
|
10
10
|
def_node_matcher :sort_with_block?, <<~PATTERN
|
11
11
|
(block
|
12
|
-
$(
|
12
|
+
$(call _ :sort)
|
13
13
|
(args (arg $_a) (arg $_b))
|
14
14
|
$send)
|
15
15
|
PATTERN
|
16
16
|
|
17
17
|
def_node_matcher :sort_with_numblock?, <<~PATTERN
|
18
18
|
(numblock
|
19
|
-
$(
|
19
|
+
$(call _ :sort)
|
20
20
|
$_arg_count
|
21
21
|
$send)
|
22
22
|
PATTERN
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
39
39
|
RESTRICT_ON_SEND = SLICE_METHODS
|
40
40
|
|
41
41
|
def_node_matcher :endless_range_slice?, <<~PATTERN
|
42
|
-
(call
|
42
|
+
(call $!{str dstr xstr} $%SLICE_METHODS $#endless_range?)
|
43
43
|
PATTERN
|
44
44
|
|
45
45
|
def_node_matcher :endless_range?, <<~PATTERN
|
@@ -9,8 +9,7 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# @safety
|
11
11
|
# This cop is unsafe because it has known compatibility issues with `ActiveRecord` and other
|
12
|
-
# frameworks.
|
13
|
-
# `ActiveRecord` will ignore the block that is passed to `count`.
|
12
|
+
# frameworks. Before Rails 5.1, `ActiveRecord` will ignore the block that is passed to `count`.
|
14
13
|
# Other methods, such as `select`, will convert the association to an
|
15
14
|
# array and then run the block on the array. A simple work around to
|
16
15
|
# make `count` work with a block is to call `to_a.count {...}`.
|
@@ -55,8 +54,8 @@ module RuboCop
|
|
55
54
|
|
56
55
|
def_node_matcher :count_candidate?, <<~PATTERN
|
57
56
|
{
|
58
|
-
(
|
59
|
-
(
|
57
|
+
(call (block $(call _ ${:select :filter :find_all :reject}) ...) ${:count :length :size})
|
58
|
+
(call $(call _ ${:select :filter :find_all :reject} (:block_pass _)) ${:count :length :size})
|
60
59
|
}
|
61
60
|
PATTERN
|
62
61
|
|
@@ -73,6 +72,7 @@ module RuboCop
|
|
73
72
|
end
|
74
73
|
end
|
75
74
|
end
|
75
|
+
alias on_csend on_send
|
76
76
|
|
77
77
|
private
|
78
78
|
|
@@ -101,7 +101,7 @@ module RuboCop
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def negate_reject(corrector, node)
|
104
|
-
if node.receiver.
|
104
|
+
if node.receiver.call_type?
|
105
105
|
negate_block_pass_reject(corrector, node)
|
106
106
|
else
|
107
107
|
negate_block_reject(corrector, node)
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
RESTRICT_ON_SEND = %i[count length size].freeze
|
51
51
|
|
52
52
|
def_node_matcher :counter, <<~MATCHER
|
53
|
-
(
|
53
|
+
(call ${array hash str sym} {:count :length :size} $...)
|
54
54
|
MATCHER
|
55
55
|
|
56
56
|
def on_send(node)
|
@@ -62,6 +62,7 @@ module RuboCop
|
|
62
62
|
add_offense(node)
|
63
63
|
end
|
64
64
|
end
|
65
|
+
alias on_csend on_send
|
65
66
|
|
66
67
|
private
|
67
68
|
|
@@ -26,10 +26,10 @@ module RuboCop
|
|
26
26
|
'multiple levels.'
|
27
27
|
|
28
28
|
def_node_matcher :flat_map_candidate?, <<~PATTERN
|
29
|
-
(
|
29
|
+
(call
|
30
30
|
{
|
31
|
-
$(block (
|
32
|
-
$(
|
31
|
+
$(block (call _ ${:collect :map}) ...)
|
32
|
+
$(call _ ${:collect :map} (block_pass _))
|
33
33
|
}
|
34
34
|
${:flatten :flatten!}
|
35
35
|
$...
|
@@ -46,6 +46,7 @@ module RuboCop
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
|
+
alias on_csend on_send
|
49
50
|
|
50
51
|
private
|
51
52
|
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
RESTRICT_ON_SEND = %i[include?].freeze
|
46
46
|
|
47
47
|
def_node_matcher :inefficient_include?, <<~PATTERN
|
48
|
-
(
|
48
|
+
(call (call $_ {:keys :values}) :include? _)
|
49
49
|
PATTERN
|
50
50
|
|
51
51
|
def on_send(node)
|
@@ -89,7 +89,7 @@ module RuboCop
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def correct_argument(node)
|
92
|
-
node.
|
92
|
+
node.first_argument.source
|
93
93
|
end
|
94
94
|
|
95
95
|
def correct_hash_expression(node)
|
@@ -68,6 +68,7 @@ module RuboCop
|
|
68
68
|
|
69
69
|
private
|
70
70
|
|
71
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
71
72
|
def find_begin_of_chained_map_method(node, map_args)
|
72
73
|
return unless (chained_map_method = node.receiver)
|
73
74
|
return if !chained_map_method.call_type? || !RESTRICT_ON_SEND.include?(chained_map_method.method_name)
|
@@ -77,10 +78,11 @@ module RuboCop
|
|
77
78
|
|
78
79
|
receiver = chained_map_method.receiver
|
79
80
|
|
80
|
-
return chained_map_method unless receiver
|
81
|
+
return chained_map_method unless receiver&.call_type? && block_pass_with_symbol_arg?(receiver.first_argument)
|
81
82
|
|
82
83
|
find_begin_of_chained_map_method(chained_map_method, map_args)
|
83
84
|
end
|
85
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
84
86
|
end
|
85
87
|
end
|
86
88
|
end
|
@@ -12,6 +12,12 @@ module RuboCop
|
|
12
12
|
# @safety
|
13
13
|
# This cop is unsafe because `Range#include?` (or `Range#member?`) and `Range#cover?`
|
14
14
|
# are not equivalent behavior.
|
15
|
+
# Example of a case where `Range#cover?` may not provide the desired result:
|
16
|
+
#
|
17
|
+
# [source,ruby]
|
18
|
+
# ----
|
19
|
+
# ('a'..'z').cover?('yellow') # => true
|
20
|
+
# ----
|
15
21
|
#
|
16
22
|
# @example
|
17
23
|
# # bad
|
@@ -20,11 +26,6 @@ module RuboCop
|
|
20
26
|
#
|
21
27
|
# # good
|
22
28
|
# ('a'..'z').cover?('b') # => true
|
23
|
-
#
|
24
|
-
# # Example of a case where `Range#cover?` may not provide
|
25
|
-
# # the desired result:
|
26
|
-
#
|
27
|
-
# ('a'..'z').cover?('yellow') # => true
|
28
29
|
class RangeInclude < Base
|
29
30
|
extend AutoCorrector
|
30
31
|
|
@@ -37,7 +38,7 @@ module RuboCop
|
|
37
38
|
# (We don't even catch it if the Range is in double parens)
|
38
39
|
|
39
40
|
def_node_matcher :range_include, <<~PATTERN
|
40
|
-
(
|
41
|
+
(call {irange erange (begin {irange erange})} ${:include? :member?} ...)
|
41
42
|
PATTERN
|
42
43
|
|
43
44
|
def on_send(node)
|
@@ -49,6 +50,7 @@ module RuboCop
|
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
53
|
+
alias on_csend on_send
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
return unless TARGET_METHODS.include?(node.method_name)
|
64
64
|
return unless one_block_argument?(node.arguments)
|
65
65
|
|
66
|
-
block_argument = node.
|
66
|
+
block_argument = node.first_argument
|
67
67
|
block_body = node.body
|
68
68
|
return unless use_equality_comparison_block?(block_body)
|
69
69
|
return if same_block_argument_and_is_a_argument?(block_body, block_argument)
|
@@ -23,6 +23,8 @@ module RuboCop
|
|
23
23
|
MSG = 'Use `=~` in places where the `MatchData` returned by `#match` will not be used.'
|
24
24
|
RESTRICT_ON_SEND = %i[match].freeze
|
25
25
|
|
26
|
+
HIGHER_PRECEDENCE_OPERATOR_METHODS = %i[| ^ & + - * / % ** > >= < <= << >>].freeze
|
27
|
+
|
26
28
|
# 'match' is a fairly generic name, so we don't flag it unless we see
|
27
29
|
# a string or regexp literal on one side or the other
|
28
30
|
def_node_matcher :match_call?, <<~PATTERN
|
@@ -47,7 +49,7 @@ module RuboCop
|
|
47
49
|
private
|
48
50
|
|
49
51
|
def autocorrect(corrector, node)
|
50
|
-
new_source = "#{node.receiver.source} =~ #{node
|
52
|
+
new_source = "#{node.receiver.source} =~ #{replacement(node)}"
|
51
53
|
|
52
54
|
corrector.replace(node, new_source)
|
53
55
|
end
|
@@ -57,6 +59,33 @@ module RuboCop
|
|
57
59
|
# register an offense in that case
|
58
60
|
node.receiver.regexp_type? || node.first_argument.regexp_type?
|
59
61
|
end
|
62
|
+
|
63
|
+
def replacement(node)
|
64
|
+
arg = node.first_argument
|
65
|
+
|
66
|
+
if requires_parentheses?(arg)
|
67
|
+
"(#{arg.source})"
|
68
|
+
else
|
69
|
+
arg.source
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def requires_parentheses?(arg)
|
74
|
+
return true if arg.if_type? && arg.ternary?
|
75
|
+
return true if arg.and_type? || arg.or_type? || arg.range_type?
|
76
|
+
|
77
|
+
call_like?(arg) && requires_parentheses_for_call_like?(arg)
|
78
|
+
end
|
79
|
+
|
80
|
+
def requires_parentheses_for_call_like?(arg)
|
81
|
+
return false if arg.parenthesized? || !arg.arguments?
|
82
|
+
|
83
|
+
!HIGHER_PRECEDENCE_OPERATOR_METHODS.include?(arg.method_name)
|
84
|
+
end
|
85
|
+
|
86
|
+
def call_like?(arg)
|
87
|
+
arg.call_type? || arg.yield_type? || arg.super_type?
|
88
|
+
end
|
60
89
|
end
|
61
90
|
end
|
62
91
|
end
|
@@ -130,7 +130,9 @@ module RuboCop
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def rewrite_with_modifier(node, parent, new_source)
|
133
|
-
|
133
|
+
# FIXME: `|| 2` can be removed when support is limited to RuboCop 1.44 or higher.
|
134
|
+
# https://github.com/rubocop/rubocop/commit/02d1e5b
|
135
|
+
indent = ' ' * (configured_indentation_width || 2)
|
134
136
|
padding = "\n#{indent + leading_spaces(node)}"
|
135
137
|
new_source.gsub!("\n", padding)
|
136
138
|
|
@@ -24,13 +24,13 @@ module RuboCop
|
|
24
24
|
RESTRICT_ON_SEND = %i[first].freeze
|
25
25
|
|
26
26
|
def_node_matcher :reverse_first_candidate?, <<~PATTERN
|
27
|
-
(
|
27
|
+
(call $(call _ :reverse) :first (int _)?)
|
28
28
|
PATTERN
|
29
29
|
|
30
30
|
def on_send(node)
|
31
31
|
reverse_first_candidate?(node) do |receiver|
|
32
32
|
range = correction_range(receiver, node)
|
33
|
-
message = build_message(node)
|
33
|
+
message = build_message(node, range)
|
34
34
|
|
35
35
|
add_offense(range, message: message) do |corrector|
|
36
36
|
replacement = build_good_method(node)
|
@@ -47,27 +47,19 @@ module RuboCop
|
|
47
47
|
range_between(receiver.loc.selector.begin_pos, node.source_range.end_pos)
|
48
48
|
end
|
49
49
|
|
50
|
-
def build_message(node)
|
50
|
+
def build_message(node, range)
|
51
51
|
good_method = build_good_method(node)
|
52
|
-
bad_method =
|
52
|
+
bad_method = range.source
|
53
53
|
format(MSG, good_method: good_method, bad_method: bad_method)
|
54
54
|
end
|
55
55
|
|
56
56
|
def build_good_method(node)
|
57
57
|
if node.arguments?
|
58
|
-
"last(#{node.
|
58
|
+
"last(#{node.first_argument.source})#{node.loc.dot.source}reverse"
|
59
59
|
else
|
60
60
|
'last'
|
61
61
|
end
|
62
62
|
end
|
63
|
-
|
64
|
-
def build_bad_method(node)
|
65
|
-
if node.arguments?
|
66
|
-
"reverse.first(#{node.arguments.first.source})"
|
67
|
-
else
|
68
|
-
'reverse.first'
|
69
|
-
end
|
70
|
-
end
|
71
63
|
end
|
72
64
|
end
|
73
65
|
end
|
@@ -24,10 +24,6 @@ module RuboCop
|
|
24
24
|
MSG = 'Use `filter_map` instead of `%<method_name>s.map`.'
|
25
25
|
RESTRICT_ON_SEND = %i[select filter].freeze
|
26
26
|
|
27
|
-
def_node_matcher :bad_method?, <<~PATTERN
|
28
|
-
(send nil? :bad_method ...)
|
29
|
-
PATTERN
|
30
|
-
|
31
27
|
def on_send(node)
|
32
28
|
return if (first_argument = node.first_argument) && !first_argument.block_pass_type?
|
33
29
|
return unless (send_node = map_method_candidate(node))
|
@@ -45,9 +41,9 @@ module RuboCop
|
|
45
41
|
def map_method_candidate(node)
|
46
42
|
return unless (parent = node.parent)
|
47
43
|
|
48
|
-
if parent.block_type? && parent.parent&.
|
44
|
+
if parent.block_type? && parent.parent&.call_type?
|
49
45
|
parent.parent
|
50
|
-
elsif parent.
|
46
|
+
elsif parent.call_type?
|
51
47
|
parent
|
52
48
|
end
|
53
49
|
end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
def_node_matcher :array?, <<~PATTERN
|
44
44
|
{
|
45
45
|
[!nil? array_type?]
|
46
|
-
(
|
46
|
+
(call _ :to_a)
|
47
47
|
(send (const nil? :Array) :[] _)
|
48
48
|
(send nil? :Array _)
|
49
49
|
}
|
@@ -52,14 +52,14 @@ module RuboCop
|
|
52
52
|
def_node_matcher :hash?, <<~PATTERN
|
53
53
|
{
|
54
54
|
[!nil? hash_type?]
|
55
|
-
(
|
55
|
+
(call _ :to_h)
|
56
56
|
(send (const nil? :Hash) :[] _)
|
57
57
|
(send nil? :Hash _)
|
58
58
|
}
|
59
59
|
PATTERN
|
60
60
|
|
61
61
|
def_node_matcher :count?, <<~PATTERN
|
62
|
-
(
|
62
|
+
(call {#array? #hash?} :count)
|
63
63
|
PATTERN
|
64
64
|
|
65
65
|
def on_send(node)
|
@@ -69,6 +69,7 @@ module RuboCop
|
|
69
69
|
corrector.replace(node.loc.selector, 'size')
|
70
70
|
end
|
71
71
|
end
|
72
|
+
alias on_csend on_send
|
72
73
|
end
|
73
74
|
end
|
74
75
|
end
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
17
17
|
include SortBlock
|
18
18
|
extend AutoCorrector
|
19
19
|
|
20
|
-
MSG = 'Use `
|
20
|
+
MSG = 'Use `%<prefer>s` instead.'
|
21
21
|
|
22
22
|
def on_block(node)
|
23
23
|
sort_with_block?(node) do |send, var_a, var_b, body|
|
@@ -41,11 +41,12 @@ module RuboCop
|
|
41
41
|
|
42
42
|
def register_offense(send, node)
|
43
43
|
range = sort_range(send, node)
|
44
|
+
prefer = "sort#{send.loc.dot.source}reverse"
|
44
45
|
|
45
|
-
|
46
|
-
replacement = 'sort.reverse'
|
46
|
+
message = format(MSG, prefer: prefer)
|
47
47
|
|
48
|
-
|
48
|
+
add_offense(range, message: message) do |corrector|
|
49
|
+
corrector.replace(range, prefer)
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
@@ -16,11 +16,13 @@ module RuboCop
|
|
16
16
|
# send('do_something')
|
17
17
|
# attr_accessor 'do_something'
|
18
18
|
# instance_variable_get('@ivar')
|
19
|
+
# const_get("string_#{interpolation}")
|
19
20
|
#
|
20
21
|
# # good
|
21
22
|
# send(:do_something)
|
22
23
|
# attr_accessor :do_something
|
23
24
|
# instance_variable_get(:@ivar)
|
25
|
+
# const_get(:"string_#{interpolation}")
|
24
26
|
#
|
25
27
|
class StringIdentifierArgument < Base
|
26
28
|
extend AutoCorrector
|
@@ -45,15 +47,16 @@ module RuboCop
|
|
45
47
|
respond_to? send singleton_method __send__
|
46
48
|
] + COMMAND_METHODS).freeze
|
47
49
|
|
50
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
48
51
|
def on_send(node)
|
49
52
|
return if COMMAND_METHODS.include?(node.method_name) && node.receiver
|
50
53
|
return unless (first_argument = node.first_argument)
|
51
|
-
return unless first_argument.str_type?
|
54
|
+
return unless first_argument.str_type? || first_argument.dstr_type?
|
52
55
|
|
53
56
|
first_argument_value = first_argument.value
|
54
57
|
return if first_argument_value.include?(' ') || first_argument_value.include?('::')
|
55
58
|
|
56
|
-
replacement = first_argument_value
|
59
|
+
replacement = argument_replacement(first_argument, first_argument_value)
|
57
60
|
|
58
61
|
message = format(MSG, symbol_arg: replacement, string_arg: first_argument.source)
|
59
62
|
|
@@ -61,6 +64,17 @@ module RuboCop
|
|
61
64
|
corrector.replace(first_argument, replacement)
|
62
65
|
end
|
63
66
|
end
|
67
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def argument_replacement(node, value)
|
72
|
+
if node.str_type?
|
73
|
+
value.to_sym.inspect
|
74
|
+
else
|
75
|
+
":\"#{value.to_sym}\""
|
76
|
+
end
|
77
|
+
end
|
64
78
|
end
|
65
79
|
end
|
66
80
|
end
|
@@ -16,6 +16,7 @@ module RuboCop
|
|
16
16
|
# /ab/ =~ str
|
17
17
|
# str.match(/ab/)
|
18
18
|
# /ab/.match(str)
|
19
|
+
# /ab/ === str
|
19
20
|
#
|
20
21
|
# # good
|
21
22
|
# str.include?('ab')
|
@@ -23,11 +24,11 @@ module RuboCop
|
|
23
24
|
extend AutoCorrector
|
24
25
|
|
25
26
|
MSG = 'Use `%<negation>sString#include?` instead of a regex match with literal-only pattern.'
|
26
|
-
RESTRICT_ON_SEND = %i[match =~ !~ match?].freeze
|
27
|
+
RESTRICT_ON_SEND = %i[match =~ !~ match? ===].freeze
|
27
28
|
|
28
29
|
def_node_matcher :redundant_regex?, <<~PATTERN
|
29
30
|
{(call $!nil? {:match :=~ :!~ :match?} (regexp (str $#literal?) (regopt)))
|
30
|
-
(send (regexp (str $#literal?) (regopt)) {:match :match?} $_)
|
31
|
+
(send (regexp (str $#literal?) (regopt)) {:match :match? :===} $_)
|
31
32
|
(match-with-lvasgn (regexp (str $#literal?) (regopt)) $_)}
|
32
33
|
PATTERN
|
33
34
|
|
@@ -80,21 +80,21 @@ module RuboCop
|
|
80
80
|
RESTRICT_ON_SEND = %i[inject reduce sum].freeze
|
81
81
|
|
82
82
|
def_node_matcher :sum_candidate?, <<~PATTERN
|
83
|
-
(
|
83
|
+
(call _ ${:inject :reduce} $_init ? ${(sym :+) (block_pass (sym :+))})
|
84
84
|
PATTERN
|
85
85
|
|
86
86
|
def_node_matcher :sum_map_candidate?, <<~PATTERN
|
87
|
-
(
|
87
|
+
(call
|
88
88
|
{
|
89
|
-
(block $(
|
90
|
-
$(
|
89
|
+
(block $(call _ {:map :collect}) ...)
|
90
|
+
$(call _ {:map :collect} (block_pass _))
|
91
91
|
}
|
92
92
|
:sum $_init ?)
|
93
93
|
PATTERN
|
94
94
|
|
95
95
|
def_node_matcher :sum_with_block_candidate?, <<~PATTERN
|
96
96
|
(block
|
97
|
-
$(
|
97
|
+
$(call _ {:inject :reduce} $_init ?)
|
98
98
|
(args (arg $_acc) (arg $_elem))
|
99
99
|
$send)
|
100
100
|
PATTERN
|
@@ -110,6 +110,7 @@ module RuboCop
|
|
110
110
|
handle_sum_candidate(node)
|
111
111
|
handle_sum_map_candidate(node)
|
112
112
|
end
|
113
|
+
alias on_csend on_send
|
113
114
|
|
114
115
|
def on_block(node)
|
115
116
|
sum_with_block_candidate?(node) do |send, init, var_acc, var_elem, body|
|
@@ -143,7 +144,7 @@ module RuboCop
|
|
143
144
|
sum_map_candidate?(node) do |map, init|
|
144
145
|
next if node.block_literal? || node.block_argument?
|
145
146
|
|
146
|
-
message = build_sum_map_message(map
|
147
|
+
message = build_sum_map_message(map, init)
|
147
148
|
|
148
149
|
add_offense(sum_map_range(map, node), message: message) do |corrector|
|
149
150
|
autocorrect_sum_map(corrector, node, map, init)
|
@@ -178,7 +179,7 @@ module RuboCop
|
|
178
179
|
|
179
180
|
corrector.remove(sum_range)
|
180
181
|
|
181
|
-
dot =
|
182
|
+
dot = map.loc.dot&.source || ''
|
182
183
|
corrector.replace(map_range, "#{dot}#{replacement}")
|
183
184
|
end
|
184
185
|
|
@@ -205,10 +206,11 @@ module RuboCop
|
|
205
206
|
format(msg, good_method: good_method, bad_method: bad_method)
|
206
207
|
end
|
207
208
|
|
208
|
-
def build_sum_map_message(
|
209
|
+
def build_sum_map_message(send_node, init)
|
209
210
|
sum_method = build_good_method(init)
|
210
211
|
good_method = "#{sum_method} { ... }"
|
211
|
-
|
212
|
+
dot = send_node.loc.dot&.source || '.'
|
213
|
+
bad_method = "#{send_node.method_name} { ... }#{dot}#{sum_method}"
|
212
214
|
format(MSG, good_method: good_method, bad_method: bad_method)
|
213
215
|
end
|
214
216
|
|
@@ -39,6 +39,7 @@ module RuboCop
|
|
39
39
|
def on_send(node)
|
40
40
|
check(node)
|
41
41
|
end
|
42
|
+
alias on_csend on_send
|
42
43
|
|
43
44
|
def on_block(node)
|
44
45
|
check(node)
|
@@ -49,6 +50,8 @@ module RuboCop
|
|
49
50
|
|
50
51
|
def check(node)
|
51
52
|
times_map_call(node) do |map_or_collect, count|
|
53
|
+
next unless handleable_receiver?(node)
|
54
|
+
|
52
55
|
add_offense(node, message: message(map_or_collect, count)) do |corrector|
|
53
56
|
replacement = "Array.new(#{count.source}#{map_or_collect.arguments.map { |arg| ", #{arg.source}" }.join})"
|
54
57
|
|
@@ -57,6 +60,13 @@ module RuboCop
|
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
63
|
+
def handleable_receiver?(node)
|
64
|
+
receiver = node.receiver.receiver
|
65
|
+
return true if receiver.literal? && (receiver.int_type? || receiver.float_type?)
|
66
|
+
|
67
|
+
node.receiver.dot?
|
68
|
+
end
|
69
|
+
|
60
70
|
def message(map_or_collect, count)
|
61
71
|
template = if count.literal?
|
62
72
|
"#{MESSAGE}."
|
@@ -67,8 +77,10 @@ module RuboCop
|
|
67
77
|
end
|
68
78
|
|
69
79
|
def_node_matcher :times_map_call, <<~PATTERN
|
70
|
-
{
|
71
|
-
|
80
|
+
{
|
81
|
+
({block numblock} $(call (call $!nil? :times) {:map :collect}) ...)
|
82
|
+
$(call (call $!nil? :times) {:map :collect} (block_pass ...))
|
83
|
+
}
|
72
84
|
PATTERN
|
73
85
|
end
|
74
86
|
end
|
@@ -15,8 +15,8 @@ module RuboCop
|
|
15
15
|
#
|
16
16
|
# @example
|
17
17
|
# # bad
|
18
|
-
# ''.dup
|
19
|
-
# "something".dup
|
18
|
+
# ''.dup # when Ruby 3.2 or lower
|
19
|
+
# "something".dup # when Ruby 3.2 or lower
|
20
20
|
# String.new
|
21
21
|
# String.new('')
|
22
22
|
# String.new('something')
|
@@ -26,6 +26,9 @@ module RuboCop
|
|
26
26
|
# +''
|
27
27
|
class UnfreezeString < Base
|
28
28
|
extend AutoCorrector
|
29
|
+
extend TargetRubyVersion
|
30
|
+
|
31
|
+
minimum_target_ruby_version 2.3
|
29
32
|
|
30
33
|
MSG = 'Use unary plus to get an unfrozen string literal.'
|
31
34
|
RESTRICT_ON_SEND = %i[dup new].freeze
|
@@ -42,7 +45,7 @@ module RuboCop
|
|
42
45
|
PATTERN
|
43
46
|
|
44
47
|
def on_send(node)
|
45
|
-
return unless dup_string?(node) || string_new?(node)
|
48
|
+
return unless (dup_string?(node) && target_ruby_version <= 3.2) || string_new?(node)
|
46
49
|
|
47
50
|
add_offense(node) do |corrector|
|
48
51
|
string_value = "+#{string_value(node)}"
|
data/lib/rubocop-performance.rb
CHANGED
@@ -9,3 +9,11 @@ require_relative 'rubocop/performance/inject'
|
|
9
9
|
RuboCop::Performance::Inject.defaults!
|
10
10
|
|
11
11
|
require_relative 'rubocop/cop/performance_cops'
|
12
|
+
|
13
|
+
RuboCop::Cop::Lint::UnusedMethodArgument.singleton_class.prepend(
|
14
|
+
Module.new do
|
15
|
+
def autocorrect_incompatible_with
|
16
|
+
super.push(RuboCop::Cop::Performance::BlockGivenWithExplicitBlock)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-performance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-
|
13
|
+
date: 2023-12-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubocop
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
21
|
+
version: 1.48.1
|
22
22
|
- - "<"
|
23
23
|
- !ruby/object:Gem::Version
|
24
24
|
version: '2.0'
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
requirements:
|
29
29
|
- - ">="
|
30
30
|
- !ruby/object:Gem::Version
|
31
|
-
version: 1.
|
31
|
+
version: 1.48.1
|
32
32
|
- - "<"
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '2.0'
|
@@ -38,14 +38,20 @@ dependencies:
|
|
38
38
|
requirements:
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
41
|
+
version: 1.30.0
|
42
|
+
- - "<"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '2.0'
|
42
45
|
type: :runtime
|
43
46
|
prerelease: false
|
44
47
|
version_requirements: !ruby/object:Gem::Requirement
|
45
48
|
requirements:
|
46
49
|
- - ">="
|
47
50
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
51
|
+
version: 1.30.0
|
52
|
+
- - "<"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
49
55
|
description: |
|
50
56
|
A collection of RuboCop cops to check for performance optimizations
|
51
57
|
in Ruby code.
|
@@ -124,7 +130,7 @@ metadata:
|
|
124
130
|
homepage_uri: https://docs.rubocop.org/rubocop-performance/
|
125
131
|
changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
|
126
132
|
source_code_uri: https://github.com/rubocop/rubocop-performance/
|
127
|
-
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.
|
133
|
+
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.20/
|
128
134
|
bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
|
129
135
|
rubygems_mfa_required: 'true'
|
130
136
|
post_install_message:
|
@@ -142,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
148
|
- !ruby/object:Gem::Version
|
143
149
|
version: '0'
|
144
150
|
requirements: []
|
145
|
-
rubygems_version: 3.
|
151
|
+
rubygems_version: 3.1.6
|
146
152
|
signing_key:
|
147
153
|
specification_version: 4
|
148
154
|
summary: Automatic performance checking tool for Ruby code.
|