rubocop-performance 1.13.3 → 1.19.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/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +13 -2
- data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +2 -2
- data/lib/rubocop/cop/mixin/sort_block.rb +7 -0
- data/lib/rubocop/cop/performance/ancestors_include.rb +1 -2
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +3 -2
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +2 -6
- data/lib/rubocop/cop/performance/bind_call.rb +1 -2
- data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +1 -1
- data/lib/rubocop/cop/performance/caller.rb +1 -2
- data/lib/rubocop/cop/performance/case_when_splat.rb +7 -13
- data/lib/rubocop/cop/performance/casecmp.rb +10 -12
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +5 -5
- data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +4 -6
- data/lib/rubocop/cop/performance/compare_with_block.rb +20 -11
- data/lib/rubocop/cop/performance/concurrent_monotonic_time.rb +1 -1
- data/lib/rubocop/cop/performance/constant_regexp.rb +6 -4
- data/lib/rubocop/cop/performance/count.rb +39 -3
- data/lib/rubocop/cop/performance/delete_prefix.rb +8 -2
- data/lib/rubocop/cop/performance/delete_suffix.rb +8 -2
- data/lib/rubocop/cop/performance/detect.rb +7 -6
- data/lib/rubocop/cop/performance/double_start_end_with.rb +4 -5
- data/lib/rubocop/cop/performance/end_with.rb +7 -6
- data/lib/rubocop/cop/performance/fixed_size.rb +2 -2
- data/lib/rubocop/cop/performance/flat_map.rb +7 -5
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +17 -15
- data/lib/rubocop/cop/performance/io_readlines.rb +2 -2
- data/lib/rubocop/cop/performance/map_compact.rb +9 -4
- data/lib/rubocop/cop/performance/map_method_chain.rb +87 -0
- data/lib/rubocop/cop/performance/method_object_as_block.rb +1 -1
- data/lib/rubocop/cop/performance/open_struct.rb +2 -3
- data/lib/rubocop/cop/performance/range_include.rb +2 -2
- data/lib/rubocop/cop/performance/redundant_block_call.rb +2 -2
- data/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb +38 -3
- data/lib/rubocop/cop/performance/redundant_match.rb +10 -9
- data/lib/rubocop/cop/performance/redundant_merge.rb +9 -16
- data/lib/rubocop/cop/performance/redundant_sort_block.rb +17 -10
- data/lib/rubocop/cop/performance/redundant_split_regexp_argument.rb +3 -2
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +10 -6
- data/lib/rubocop/cop/performance/regexp_match.rb +23 -24
- data/lib/rubocop/cop/performance/reverse_each.rb +3 -3
- data/lib/rubocop/cop/performance/reverse_first.rb +4 -3
- data/lib/rubocop/cop/performance/select_map.rb +2 -1
- data/lib/rubocop/cop/performance/size.rb +1 -2
- data/lib/rubocop/cop/performance/sort_reverse.rb +19 -10
- data/lib/rubocop/cop/performance/squeeze.rb +8 -8
- data/lib/rubocop/cop/performance/start_with.rb +7 -6
- data/lib/rubocop/cop/performance/string_identifier_argument.rb +16 -11
- data/lib/rubocop/cop/performance/string_include.rb +23 -17
- data/lib/rubocop/cop/performance/string_replacement.rb +7 -10
- data/lib/rubocop/cop/performance/sum.rb +7 -4
- data/lib/rubocop/cop/performance/times_map.rb +6 -7
- data/lib/rubocop/cop/performance/uri_default_parser.rb +4 -6
- data/lib/rubocop/cop/performance_cops.rb +1 -0
- data/lib/rubocop/performance/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06f3e8346dc7f9be72a1f18c62a25dc02aeac41debcfe3c58df68e2a6904df43
|
4
|
+
data.tar.gz: f01facdb92a3056d05990e2ed2b6b1920de0501edf53a08e95e08620651c8557
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07eb541698b6ccf2985ef62392bd78703bf6607e2877ef3865ab1762d62910c4c346fbb7e9bc48af7b7d98b0e1ad22e8c79ea2425555fbe75c2a5e614837eaa7
|
7
|
+
data.tar.gz: 60fc9f900906cca518d0da62170f71ae6e5f5ffd44f4c1cbe75af83f9a1fef252b6bab95d3af4f49f328d4a856cd17c7f47621ee62575ab282eacfd26dc09841
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Performance optimization analysis for your projects, as an extension to [RuboCop
|
|
11
11
|
Just install the `rubocop-performance` gem
|
12
12
|
|
13
13
|
```sh
|
14
|
-
gem install rubocop-performance
|
14
|
+
$ gem install rubocop-performance
|
15
15
|
```
|
16
16
|
|
17
17
|
or if you use bundler put this in your `Gemfile`
|
@@ -47,7 +47,7 @@ cops together with the standard cops.
|
|
47
47
|
### Command line
|
48
48
|
|
49
49
|
```sh
|
50
|
-
rubocop --require rubocop-performance
|
50
|
+
$ rubocop --require rubocop-performance
|
51
51
|
```
|
52
52
|
|
53
53
|
### Rake task
|
data/config/default.yml
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# This is the default configuration file.
|
2
2
|
|
3
|
+
Performance:
|
4
|
+
Enabled: true
|
5
|
+
DocumentationBaseURL: https://docs.rubocop.org/rubocop-performance
|
6
|
+
|
3
7
|
Performance/AncestorsInclude:
|
4
8
|
Description: 'Use `A <= B` instead of `A.ancestors.include?(B)`.'
|
5
9
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#ancestorsinclude-vs--code'
|
@@ -160,7 +164,7 @@ Performance/FlatMap:
|
|
160
164
|
Description: >-
|
161
165
|
Use `Enumerable#flat_map`
|
162
166
|
instead of `Enumerable#map...Array#flatten(1)`
|
163
|
-
or `
|
167
|
+
or `Enumerable#collect..Array#flatten(1)`.
|
164
168
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code'
|
165
169
|
Enabled: true
|
166
170
|
VersionAdded: '0.30'
|
@@ -189,6 +193,12 @@ Performance/MapCompact:
|
|
189
193
|
SafeAutoCorrect: false
|
190
194
|
VersionAdded: '1.11'
|
191
195
|
|
196
|
+
Performance/MapMethodChain:
|
197
|
+
Description: 'Checks if the `map` method is used in a chain.'
|
198
|
+
Enabled: pending
|
199
|
+
Safe: false
|
200
|
+
VersionAdded: '1.19'
|
201
|
+
|
192
202
|
Performance/MethodObjectAsBlock:
|
193
203
|
Description: 'Use block explicitly instead of block-passing a method object.'
|
194
204
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#normal-way-to-apply-method-vs-method-code'
|
@@ -222,6 +232,7 @@ Performance/RedundantEqualityComparisonBlock:
|
|
222
232
|
Reference: 'https://github.com/rails/rails/pull/41363'
|
223
233
|
Enabled: pending
|
224
234
|
Safe: false
|
235
|
+
AllowRegexpMatch: true
|
225
236
|
VersionAdded: '1.10'
|
226
237
|
|
227
238
|
Performance/RedundantMatch:
|
@@ -247,7 +258,7 @@ Performance/RedundantSortBlock:
|
|
247
258
|
VersionAdded: '1.7'
|
248
259
|
|
249
260
|
Performance/RedundantSplitRegexpArgument:
|
250
|
-
Description: '
|
261
|
+
Description: 'Identifies places where `split` argument can be replaced from a deterministic regexp to a string.'
|
251
262
|
Enabled: pending
|
252
263
|
VersionAdded: '1.10'
|
253
264
|
|
@@ -54,9 +54,9 @@ module RuboCop
|
|
54
54
|
|
55
55
|
def drop_start_metacharacter(regexp_string)
|
56
56
|
if regexp_string.start_with?('\\A')
|
57
|
-
regexp_string[2
|
57
|
+
regexp_string[2..] # drop `\A` anchor
|
58
58
|
else
|
59
|
-
regexp_string[1
|
59
|
+
regexp_string[1..] # drop `^` anchor
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -14,6 +14,13 @@ module RuboCop
|
|
14
14
|
$send)
|
15
15
|
PATTERN
|
16
16
|
|
17
|
+
def_node_matcher :sort_with_numblock?, <<~PATTERN
|
18
|
+
(numblock
|
19
|
+
$(send _ :sort)
|
20
|
+
$_arg_count
|
21
|
+
$send)
|
22
|
+
PATTERN
|
23
|
+
|
17
24
|
def_node_matcher :replaceable_body?, <<~PATTERN
|
18
25
|
(send (lvar %1) :<=> (lvar %2))
|
19
26
|
PATTERN
|
@@ -3,8 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
7
|
-
# change them to use `<=` instead.
|
6
|
+
# Identifies usages of `ancestors.include?` and change them to use `<=` instead.
|
8
7
|
#
|
9
8
|
# @safety
|
10
9
|
# This cop is unsafe because it can't tell whether the receiver is a class or an object.
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
6
|
+
# Identifies places where slicing arrays with semi-infinite ranges
|
7
7
|
# can be replaced by `Array#take` and `Array#drop`.
|
8
8
|
# This cop was created due to a mistake in microbenchmark and hence is disabled by default.
|
9
9
|
# Refer https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717
|
@@ -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
|
-
(
|
42
|
+
(call $_ $%SLICE_METHODS $#endless_range?)
|
43
43
|
PATTERN
|
44
44
|
|
45
45
|
def_node_matcher :endless_range?, <<~PATTERN
|
@@ -59,6 +59,7 @@ module RuboCop
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
62
|
+
alias on_csend on_send
|
62
63
|
|
63
64
|
private
|
64
65
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
6
|
+
# Identifies places where numeric argument to BigDecimal should be
|
7
7
|
# converted to string. Initializing from String is faster
|
8
8
|
# than from Numeric for BigDecimal.
|
9
9
|
#
|
@@ -41,11 +41,7 @@ module RuboCop
|
|
41
41
|
end
|
42
42
|
elsif (numeric_to_d = to_d?(node))
|
43
43
|
add_offense(numeric_to_d.source_range) do |corrector|
|
44
|
-
big_decimal_args = node
|
45
|
-
.arguments
|
46
|
-
.map(&:source)
|
47
|
-
.unshift("'#{numeric_to_d.source}'")
|
48
|
-
.join(', ')
|
44
|
+
big_decimal_args = node.arguments.map(&:source).unshift("'#{numeric_to_d.source}'").join(', ')
|
49
45
|
|
50
46
|
corrector.replace(node, "BigDecimal(#{big_decimal_args})")
|
51
47
|
end
|
@@ -26,8 +26,7 @@ module RuboCop
|
|
26
26
|
|
27
27
|
minimum_target_ruby_version 2.7
|
28
28
|
|
29
|
-
MSG = 'Use `bind_call(%<bind_arg>s%<comma>s%<call_args>s)` '
|
30
|
-
'instead of `bind(%<bind_arg>s).call(%<call_args>s)`.'
|
29
|
+
MSG = 'Use `bind_call(%<bind_arg>s%<comma>s%<call_args>s)` instead of `bind(%<bind_arg>s).call(%<call_args>s)`.'
|
31
30
|
RESTRICT_ON_SEND = %i[call].freeze
|
32
31
|
|
33
32
|
def_node_matcher :bind_with_call_method?, <<~PATTERN
|
@@ -18,7 +18,7 @@ module RuboCop
|
|
18
18
|
# that is inside of the splat expansion.
|
19
19
|
#
|
20
20
|
# @safety
|
21
|
-
# This cop is not unsafe
|
21
|
+
# This cop is not unsafe autocorrection because it is not a guaranteed
|
22
22
|
# performance improvement. If the data being processed by the `case` condition is
|
23
23
|
# normalized in a manner that favors hitting a condition in the splat expansion,
|
24
24
|
# it is possible that moving the splat condition to the end will use more memory,
|
@@ -99,8 +99,7 @@ module RuboCop
|
|
99
99
|
|
100
100
|
def inline_fix_branch(corrector, when_node)
|
101
101
|
conditions = when_node.conditions
|
102
|
-
range = range_between(conditions[0].
|
103
|
-
conditions[-1].loc.expression.end_pos)
|
102
|
+
range = range_between(conditions[0].source_range.begin_pos, conditions[-1].source_range.end_pos)
|
104
103
|
|
105
104
|
corrector.replace(range, replacement(conditions))
|
106
105
|
end
|
@@ -111,8 +110,7 @@ module RuboCop
|
|
111
110
|
return if when_branches.one?
|
112
111
|
|
113
112
|
corrector.remove(when_branch_range(when_node))
|
114
|
-
corrector.insert_after(when_branches.last
|
115
|
-
reordering_correction(when_node))
|
113
|
+
corrector.insert_after(when_branches.last, reordering_correction(when_node))
|
116
114
|
end
|
117
115
|
|
118
116
|
def reordering_correction(when_node)
|
@@ -126,11 +124,9 @@ module RuboCop
|
|
126
124
|
end
|
127
125
|
|
128
126
|
def when_branch_range(when_node)
|
129
|
-
next_branch =
|
130
|
-
when_node.parent.when_branches[when_node.branch_index + 1]
|
127
|
+
next_branch = when_node.parent.when_branches[when_node.branch_index + 1]
|
131
128
|
|
132
|
-
range_between(when_node.source_range.begin_pos,
|
133
|
-
next_branch.source_range.begin_pos)
|
129
|
+
range_between(when_node.source_range.begin_pos, next_branch.source_range.begin_pos)
|
134
130
|
end
|
135
131
|
|
136
132
|
def new_condition_with_then(node, new_condition)
|
@@ -162,13 +158,11 @@ module RuboCop
|
|
162
158
|
def non_splat?(condition)
|
163
159
|
variable, = *condition
|
164
160
|
|
165
|
-
(condition.splat_type? && variable.array_type?) ||
|
166
|
-
!condition.splat_type?
|
161
|
+
(condition.splat_type? && variable.array_type?) || !condition.splat_type?
|
167
162
|
end
|
168
163
|
|
169
164
|
def needs_reorder?(when_node)
|
170
|
-
following_branches =
|
171
|
-
when_node.parent.when_branches[(when_node.branch_index + 1)..-1]
|
165
|
+
following_branches = when_node.parent.when_branches[(when_node.branch_index + 1)..]
|
172
166
|
|
173
167
|
following_branches.any? do |when_branch|
|
174
168
|
when_branch.conditions.any? do |condition|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
6
|
+
# Identifies places where a case-insensitive string comparison
|
7
7
|
# can better be implemented using `casecmp`.
|
8
8
|
#
|
9
9
|
# @safety
|
@@ -54,11 +54,11 @@ module RuboCop
|
|
54
54
|
return unless (parts = take_method_apart(node))
|
55
55
|
|
56
56
|
_receiver, method, arg, variable = parts
|
57
|
-
good_method = build_good_method(arg, variable)
|
57
|
+
good_method = build_good_method(method, arg, variable)
|
58
58
|
|
59
59
|
message = format(MSG, good: good_method, bad: node.source)
|
60
60
|
add_offense(node, message: message) do |corrector|
|
61
|
-
|
61
|
+
autocorrect(corrector, node, good_method)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -81,22 +81,20 @@ module RuboCop
|
|
81
81
|
[receiver, method, arg, variable]
|
82
82
|
end
|
83
83
|
|
84
|
-
def
|
85
|
-
corrector.
|
86
|
-
|
87
|
-
replacement = build_good_method(arg, variable)
|
88
|
-
|
89
|
-
corrector.replace(node.loc.expression, replacement)
|
84
|
+
def autocorrect(corrector, node, replacement)
|
85
|
+
corrector.replace(node, replacement)
|
90
86
|
end
|
91
87
|
|
92
|
-
def build_good_method(arg, variable)
|
88
|
+
def build_good_method(method, arg, variable)
|
89
|
+
bang = method == :!= ? '!' : ''
|
90
|
+
|
93
91
|
# We want resulting call to be parenthesized
|
94
92
|
# if arg already includes one or more sets of parens, don't add more
|
95
93
|
# or if method call already used parens, again, don't add more
|
96
94
|
if arg.send_type? || !parentheses?(arg)
|
97
|
-
"#{variable.source}.casecmp(#{arg.source}).zero?"
|
95
|
+
"#{bang}#{variable.source}.casecmp(#{arg.source}).zero?"
|
98
96
|
else
|
99
|
-
"#{variable.source}.casecmp#{arg.source}.zero?"
|
97
|
+
"#{bang}#{variable.source}.casecmp#{arg.source}.zero?"
|
100
98
|
end
|
101
99
|
end
|
102
100
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
6
|
+
# Identifies usages of `array.compact.flatten.map { |x| x.downcase }`.
|
7
7
|
# Each of these methods (`compact`, `flatten`, `map`) will generate a new intermediate array
|
8
8
|
# that is promptly thrown away. Instead it is faster to mutate when we know it's safe.
|
9
9
|
#
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
RETURNS_NEW_ARRAY_WHEN_NO_BLOCK = %i[zip product].to_set.freeze
|
34
34
|
|
35
35
|
# These methods ALWAYS return a new array
|
36
|
-
# after they're called it's safe to mutate the
|
36
|
+
# after they're called it's safe to mutate the resulting array
|
37
37
|
ALWAYS_RETURNS_NEW_ARRAY = %i[* + - collect compact drop
|
38
38
|
drop_while flatten map reject
|
39
39
|
reverse rotate select shuffle sort
|
@@ -47,13 +47,13 @@ module RuboCop
|
|
47
47
|
|
48
48
|
RETURNS_NEW_ARRAY = (ALWAYS_RETURNS_NEW_ARRAY + RETURNS_NEW_ARRAY_WHEN_NO_BLOCK).freeze
|
49
49
|
|
50
|
-
MSG = 'Use unchained `%<method>s` and `%<second_method>s!` '\
|
51
|
-
'(followed by `return array` if required) instead of chaining '\
|
50
|
+
MSG = 'Use unchained `%<method>s` and `%<second_method>s!` ' \
|
51
|
+
'(followed by `return array` if required) instead of chaining ' \
|
52
52
|
'`%<method>s...%<second_method>s`.'
|
53
53
|
|
54
54
|
def_node_matcher :chain_array_allocation?, <<~PATTERN
|
55
55
|
(send {
|
56
|
-
(send _ $%RETURN_NEW_ARRAY_WHEN_ARGS {int lvar ivar cvar gvar})
|
56
|
+
(send _ $%RETURN_NEW_ARRAY_WHEN_ARGS {int lvar ivar cvar gvar send})
|
57
57
|
(block (send _ $%ALWAYS_RETURNS_NEW_ARRAY) ...)
|
58
58
|
(send _ $%RETURNS_NEW_ARRAY ...)
|
59
59
|
} $%HAS_MUTATION_ALTERNATIVE ...)
|
@@ -5,8 +5,8 @@ require 'set'
|
|
5
5
|
module RuboCop
|
6
6
|
module Cop
|
7
7
|
module Performance
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# Identifies places where Array and Hash literals are used within loops.
|
9
|
+
# It is better to extract them into a local variable or constant
|
10
10
|
# to avoid unnecessary allocations on each iteration.
|
11
11
|
#
|
12
12
|
# You can set the minimum number of elements to consider
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
# end
|
33
33
|
#
|
34
34
|
class CollectionLiteralInLoop < Base
|
35
|
-
MSG = 'Avoid immutable %<literal_class>s literals in loops. '\
|
35
|
+
MSG = 'Avoid immutable %<literal_class>s literals in loops. ' \
|
36
36
|
'It is better to extract it into a local variable or a constant.'
|
37
37
|
|
38
38
|
POST_CONDITION_LOOP_TYPES = %i[while_post until_post].freeze
|
@@ -104,9 +104,7 @@ module RuboCop
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def loop?(ancestor, node)
|
107
|
-
keyword_loop?(ancestor.type) ||
|
108
|
-
kernel_loop?(ancestor) ||
|
109
|
-
node_within_enumerable_loop?(node, ancestor)
|
107
|
+
keyword_loop?(ancestor.type) || kernel_loop?(ancestor) || node_within_enumerable_loop?(node, ancestor)
|
110
108
|
end
|
111
109
|
|
112
110
|
def keyword_loop?(type)
|
@@ -3,37 +3,44 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
6
|
+
# Identifies places where `sort { |a, b| a.foo <=> b.foo }`
|
7
7
|
# can be replaced by `sort_by(&:foo)`.
|
8
|
-
# This cop also checks `max` and `
|
8
|
+
# This cop also checks `sort!`, `min`, `max` and `minmax` methods.
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
|
-
# array.sort
|
13
|
-
# array.
|
14
|
-
# array.
|
15
|
-
# array.
|
12
|
+
# array.sort { |a, b| a.foo <=> b.foo }
|
13
|
+
# array.sort! { |a, b| a.foo <=> b.foo }
|
14
|
+
# array.max { |a, b| a.foo <=> b.foo }
|
15
|
+
# array.min { |a, b| a.foo <=> b.foo }
|
16
|
+
# array.minmax { |a, b| a.foo <=> b.foo }
|
17
|
+
# array.sort { |a, b| a[:foo] <=> b[:foo] }
|
16
18
|
#
|
17
19
|
# # good
|
18
20
|
# array.sort_by(&:foo)
|
21
|
+
# array.sort_by!(&:foo)
|
19
22
|
# array.sort_by { |v| v.foo }
|
20
23
|
# array.sort_by do |var|
|
21
24
|
# var.foo
|
22
25
|
# end
|
23
26
|
# array.max_by(&:foo)
|
24
27
|
# array.min_by(&:foo)
|
28
|
+
# array.minmax_by(&:foo)
|
25
29
|
# array.sort_by { |a| a[:foo] }
|
26
30
|
class CompareWithBlock < Base
|
27
31
|
include RangeHelp
|
28
32
|
extend AutoCorrector
|
29
33
|
|
30
|
-
MSG = 'Use `%<
|
34
|
+
MSG = 'Use `%<replacement_method>s%<instead>s` instead of ' \
|
31
35
|
'`%<compare_method>s { |%<var_a>s, %<var_b>s| %<str_a>s ' \
|
32
36
|
'<=> %<str_b>s }`.'
|
33
37
|
|
38
|
+
REPLACEMENT = { sort: :sort_by, sort!: :sort_by!, min: :min_by, max: :max_by, minmax: :minmax_by }.freeze
|
39
|
+
private_constant :REPLACEMENT
|
40
|
+
|
34
41
|
def_node_matcher :compare?, <<~PATTERN
|
35
42
|
(block
|
36
|
-
$(send _ {:sort :min :max})
|
43
|
+
$(send _ {:sort :sort! :min :max :minmax})
|
37
44
|
(args (arg $_a) (arg $_b))
|
38
45
|
$send)
|
39
46
|
PATTERN
|
@@ -54,9 +61,9 @@ module RuboCop
|
|
54
61
|
|
55
62
|
add_offense(range, message: message(send, method, var_a, var_b, args_a)) do |corrector|
|
56
63
|
replacement = if method == :[]
|
57
|
-
"#{send.method_name}
|
64
|
+
"#{REPLACEMENT[send.method_name]} { |a| a[#{args_a.first.source}] }"
|
58
65
|
else
|
59
|
-
"#{send.method_name}
|
66
|
+
"#{REPLACEMENT[send.method_name]}(&:#{method})"
|
60
67
|
end
|
61
68
|
corrector.replace(range, replacement)
|
62
69
|
end
|
@@ -82,7 +89,8 @@ module RuboCop
|
|
82
89
|
|
83
90
|
# rubocop:disable Metrics/MethodLength
|
84
91
|
def message(send, method, var_a, var_b, args)
|
85
|
-
compare_method
|
92
|
+
compare_method = send.method_name
|
93
|
+
replacement_method = REPLACEMENT[compare_method]
|
86
94
|
if method == :[]
|
87
95
|
key = args.first
|
88
96
|
instead = " { |a| a[#{key.source}] }"
|
@@ -94,6 +102,7 @@ module RuboCop
|
|
94
102
|
str_b = "#{var_b}.#{method}"
|
95
103
|
end
|
96
104
|
format(MSG, compare_method: compare_method,
|
105
|
+
replacement_method: replacement_method,
|
97
106
|
instead: instead,
|
98
107
|
var_a: var_a,
|
99
108
|
var_b: var_b,
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
6
|
+
# Finds regular expressions with dynamic components that are all constants.
|
7
7
|
#
|
8
8
|
# Ruby allocates a new Regexp object every time it executes a code containing such
|
9
9
|
# a regular expression. It is more efficient to extract it into a constant,
|
@@ -38,10 +38,12 @@ module RuboCop
|
|
38
38
|
|
39
39
|
MSG = 'Extract this regexp into a constant, memoize it, or append an `/o` option to its options.'
|
40
40
|
|
41
|
+
def self.autocorrect_incompatible_with
|
42
|
+
[RegexpMatch]
|
43
|
+
end
|
44
|
+
|
41
45
|
def on_regexp(node)
|
42
|
-
return if within_allowed_assignment?(node) ||
|
43
|
-
!include_interpolated_const?(node) ||
|
44
|
-
node.single_interpolation?
|
46
|
+
return if within_allowed_assignment?(node) || !include_interpolated_const?(node) || node.single_interpolation?
|
45
47
|
|
46
48
|
add_offense(node) do |corrector|
|
47
49
|
corrector.insert_after(node, 'o')
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
#
|
6
|
+
# Identifies usages of `count` on an `Enumerable` that
|
7
7
|
# follow calls to `select`, `find_all`, `filter` or `reject`. Querying logic can instead be
|
8
8
|
# passed to the `count` call.
|
9
9
|
#
|
@@ -79,12 +79,11 @@ module RuboCop
|
|
79
79
|
def autocorrect(corrector, node, selector_node, selector)
|
80
80
|
selector_loc = selector_node.loc.selector
|
81
81
|
|
82
|
-
return if selector == :reject
|
83
|
-
|
84
82
|
range = source_starting_at(node) { |n| n.loc.dot.begin_pos }
|
85
83
|
|
86
84
|
corrector.remove(range)
|
87
85
|
corrector.replace(selector_loc, 'count')
|
86
|
+
negate_reject(corrector, node) if selector == :reject
|
88
87
|
end
|
89
88
|
|
90
89
|
def eligible_node?(node)
|
@@ -100,6 +99,43 @@ module RuboCop
|
|
100
99
|
|
101
100
|
range_between(begin_pos, node.source_range.end_pos)
|
102
101
|
end
|
102
|
+
|
103
|
+
def negate_reject(corrector, node)
|
104
|
+
if node.receiver.send_type?
|
105
|
+
negate_block_pass_reject(corrector, node)
|
106
|
+
else
|
107
|
+
negate_block_reject(corrector, node)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def negate_block_pass_reject(corrector, node)
|
112
|
+
corrector.replace(
|
113
|
+
node.receiver.source_range.with(begin_pos: node.receiver.loc.begin.begin_pos),
|
114
|
+
negate_block_pass_as_inline_block(node.receiver)
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
def negate_block_reject(corrector, node)
|
119
|
+
target =
|
120
|
+
if node.receiver.body.begin_type?
|
121
|
+
node.receiver.body.children.last
|
122
|
+
else
|
123
|
+
node.receiver.body
|
124
|
+
end
|
125
|
+
corrector.replace(target, negate_expression(target))
|
126
|
+
end
|
127
|
+
|
128
|
+
def negate_expression(node)
|
129
|
+
"!(#{node.source})"
|
130
|
+
end
|
131
|
+
|
132
|
+
def negate_block_pass_as_inline_block(node)
|
133
|
+
if node.last_argument.children.first.sym_type?
|
134
|
+
" { |element| !element.#{node.last_argument.children.first.value} }"
|
135
|
+
else
|
136
|
+
" { !#{node.last_argument.children.first.source}.call }"
|
137
|
+
end
|
138
|
+
end
|
103
139
|
end
|
104
140
|
end
|
105
141
|
end
|
@@ -49,6 +49,9 @@ module RuboCop
|
|
49
49
|
class DeletePrefix < Base
|
50
50
|
include RegexpMetacharacter
|
51
51
|
extend AutoCorrector
|
52
|
+
extend TargetRubyVersion
|
53
|
+
|
54
|
+
minimum_target_ruby_version 2.5
|
52
55
|
|
53
56
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
54
57
|
RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze
|
@@ -61,9 +64,10 @@ module RuboCop
|
|
61
64
|
}.freeze
|
62
65
|
|
63
66
|
def_node_matcher :delete_prefix_candidate?, <<~PATTERN
|
64
|
-
(
|
67
|
+
(call $!nil? ${:gsub :gsub! :sub :sub!} (regexp (str $#literal_at_start?) (regopt)) (str $_))
|
65
68
|
PATTERN
|
66
69
|
|
70
|
+
# rubocop:disable Metrics/AbcSize
|
67
71
|
def on_send(node)
|
68
72
|
return unless (receiver, bad_method, regexp_str, replace_string = delete_prefix_candidate?(node))
|
69
73
|
return unless replace_string.empty?
|
@@ -77,11 +81,13 @@ module RuboCop
|
|
77
81
|
regexp_str = interpret_string_escapes(regexp_str)
|
78
82
|
string_literal = to_string_literal(regexp_str)
|
79
83
|
|
80
|
-
new_code = "#{receiver.source}
|
84
|
+
new_code = "#{receiver.source}#{node.loc.dot.source}#{good_method}(#{string_literal})"
|
81
85
|
|
82
86
|
corrector.replace(node, new_code)
|
83
87
|
end
|
84
88
|
end
|
89
|
+
# rubocop:enable Metrics/AbcSize
|
90
|
+
alias on_csend on_send
|
85
91
|
end
|
86
92
|
end
|
87
93
|
end
|
@@ -49,6 +49,9 @@ module RuboCop
|
|
49
49
|
class DeleteSuffix < Base
|
50
50
|
include RegexpMetacharacter
|
51
51
|
extend AutoCorrector
|
52
|
+
extend TargetRubyVersion
|
53
|
+
|
54
|
+
minimum_target_ruby_version 2.5
|
52
55
|
|
53
56
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
54
57
|
RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze
|
@@ -61,9 +64,10 @@ module RuboCop
|
|
61
64
|
}.freeze
|
62
65
|
|
63
66
|
def_node_matcher :delete_suffix_candidate?, <<~PATTERN
|
64
|
-
(
|
67
|
+
(call $!nil? ${:gsub :gsub! :sub :sub!} (regexp (str $#literal_at_end?) (regopt)) (str $_))
|
65
68
|
PATTERN
|
66
69
|
|
70
|
+
# rubocop:disable Metrics/AbcSize
|
67
71
|
def on_send(node)
|
68
72
|
return unless (receiver, bad_method, regexp_str, replace_string = delete_suffix_candidate?(node))
|
69
73
|
return unless replace_string.empty?
|
@@ -77,11 +81,13 @@ module RuboCop
|
|
77
81
|
regexp_str = interpret_string_escapes(regexp_str)
|
78
82
|
string_literal = to_string_literal(regexp_str)
|
79
83
|
|
80
|
-
new_code = "#{receiver.source}
|
84
|
+
new_code = "#{receiver.source}#{node.loc.dot.source}#{good_method}(#{string_literal})"
|
81
85
|
|
82
86
|
corrector.replace(node, new_code)
|
83
87
|
end
|
84
88
|
end
|
89
|
+
# rubocop:enable Metrics/AbcSize
|
90
|
+
alias on_csend on_send
|
85
91
|
end
|
86
92
|
end
|
87
93
|
end
|