rubocop-performance 1.14.3 → 1.16.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/config/default.yml +4 -0
- data/lib/rubocop/cop/mixin/sort_block.rb +7 -0
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +1 -5
- data/lib/rubocop/cop/performance/bind_call.rb +1 -2
- data/lib/rubocop/cop/performance/case_when_splat.rb +6 -12
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +1 -1
- data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +1 -3
- data/lib/rubocop/cop/performance/constant_regexp.rb +1 -3
- data/lib/rubocop/cop/performance/count.rb +38 -2
- data/lib/rubocop/cop/performance/detect.rb +6 -3
- data/lib/rubocop/cop/performance/double_start_end_with.rb +1 -2
- data/lib/rubocop/cop/performance/end_with.rb +1 -2
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +1 -3
- data/lib/rubocop/cop/performance/map_compact.rb +5 -1
- data/lib/rubocop/cop/performance/open_struct.rb +1 -2
- data/lib/rubocop/cop/performance/redundant_match.rb +8 -7
- data/lib/rubocop/cop/performance/redundant_merge.rb +4 -10
- data/lib/rubocop/cop/performance/redundant_sort_block.rb +16 -8
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +7 -3
- data/lib/rubocop/cop/performance/regexp_match.rb +4 -12
- data/lib/rubocop/cop/performance/sort_reverse.rb +18 -9
- data/lib/rubocop/cop/performance/squeeze.rb +1 -4
- data/lib/rubocop/cop/performance/start_with.rb +1 -2
- data/lib/rubocop/cop/performance/string_include.rb +17 -14
- data/lib/rubocop/cop/performance/string_replacement.rb +3 -6
- data/lib/rubocop/cop/performance/sum.rb +3 -0
- data/lib/rubocop/cop/performance/times_map.rb +4 -5
- data/lib/rubocop/cop/performance/uri_default_parser.rb +1 -2
- data/lib/rubocop/performance/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b0361feae763e4c8cbea3bd0160a1e4b0646b2e3b3246fb8dd55a5f21a53acd
|
4
|
+
data.tar.gz: 152d09678555d309441fb809f60b07b69b04289b3949bf1eaca3e9b70b3afe13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f08bd2f25c0e0e537bf8fa5378e701d6b6b6794a45fe534229e73a0dd4bd623dd415965966655a802cc8e93a3776880d99c89245947aae090ba2c49f0bb183f
|
7
|
+
data.tar.gz: 34f697ee70070d32d17b3684712cec5628e71cbdb393722fec3bb0dbc541cf65af92a762907dbbb0c5e6c3023f8dd4738e06a131a5a28014749dac440e15bc92
|
data/LICENSE.txt
CHANGED
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'
|
@@ -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
|
@@ -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
|
@@ -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].loc.expression.begin_pos,
|
103
|
-
conditions[-1].loc.expression.end_pos)
|
102
|
+
range = range_between(conditions[0].loc.expression.begin_pos, conditions[-1].loc.expression.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.source_range,
|
115
|
-
reordering_correction(when_node))
|
113
|
+
corrector.insert_after(when_branches.last.source_range, 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)..]
|
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|
|
@@ -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
|
@@ -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)
|
@@ -39,9 +39,7 @@ module RuboCop
|
|
39
39
|
MSG = 'Extract this regexp into a constant, memoize it, or append an `/o` option to its options.'
|
40
40
|
|
41
41
|
def on_regexp(node)
|
42
|
-
return if within_allowed_assignment?(node) ||
|
43
|
-
!include_interpolated_const?(node) ||
|
44
|
-
node.single_interpolation?
|
42
|
+
return if within_allowed_assignment?(node) || !include_interpolated_const?(node) || node.single_interpolation?
|
45
43
|
|
46
44
|
add_offense(node) do |corrector|
|
47
45
|
corrector.insert_after(node, 'o')
|
@@ -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.loc.expression.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
|
@@ -8,9 +8,12 @@ module RuboCop
|
|
8
8
|
# `detect` instead.
|
9
9
|
#
|
10
10
|
# @safety
|
11
|
-
# This cop is unsafe because is
|
12
|
-
#
|
13
|
-
#
|
11
|
+
# This cop is unsafe because is assumes the class implements the
|
12
|
+
# `Enumerable` interface, but can't reliably detect this. This creates
|
13
|
+
# known compatibility issues with `Hash`, `ActiveRecord` and other
|
14
|
+
# frameworks. `Hash` and `ActiveRecord` do not implement a `detect`
|
15
|
+
# method and `find` has its own meaning. Correcting `Hash` and
|
16
|
+
# `ActiveRecord` methods with this cop should be considered unsafe.
|
14
17
|
#
|
15
18
|
# @example
|
16
19
|
# # bad
|
@@ -41,8 +41,7 @@ module RuboCop
|
|
41
41
|
class DoubleStartEndWith < Base
|
42
42
|
extend AutoCorrector
|
43
43
|
|
44
|
-
MSG = 'Use `%<receiver>s.%<method>s(%<combined_args>s)` '
|
45
|
-
'instead of `%<original_code>s`.'
|
44
|
+
MSG = 'Use `%<receiver>s.%<method>s(%<combined_args>s)` instead of `%<original_code>s`.'
|
46
45
|
|
47
46
|
def on_or(node)
|
48
47
|
receiver, method, first_call_args, second_call_args = process_source(node)
|
@@ -50,8 +50,7 @@ module RuboCop
|
|
50
50
|
include RegexpMetacharacter
|
51
51
|
extend AutoCorrector
|
52
52
|
|
53
|
-
MSG = 'Use `String#end_with?` instead of a regex match anchored to '
|
54
|
-
'the end of the string.'
|
53
|
+
MSG = 'Use `String#end_with?` instead of a regex match anchored to the end of the string.'
|
55
54
|
RESTRICT_ON_SEND = %i[match =~ match?].freeze
|
56
55
|
|
57
56
|
def_node_matcher :redundant_regex?, <<~PATTERN
|
@@ -83,9 +83,7 @@ module RuboCop
|
|
83
83
|
|
84
84
|
def use_long_method
|
85
85
|
preferred_config = config.for_all_cops['Style/PreferredHashMethods']
|
86
|
-
preferred_config &&
|
87
|
-
preferred_config['EnforcedStyle'] == 'long' &&
|
88
|
-
preferred_config['Enabled']
|
86
|
+
preferred_config && preferred_config['EnforcedStyle'] == 'long' && preferred_config['Enabled']
|
89
87
|
end
|
90
88
|
|
91
89
|
def autocorrect_argument(node)
|
@@ -67,7 +67,7 @@ module RuboCop
|
|
67
67
|
def remove_compact_method(corrector, map_node, compact_node, chained_method)
|
68
68
|
compact_method_range = compact_node.loc.selector
|
69
69
|
|
70
|
-
if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) && chained_method
|
70
|
+
if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) && use_dot?(chained_method) &&
|
71
71
|
!map_method_and_compact_method_on_same_line?(map_node, compact_node) &&
|
72
72
|
!invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
|
73
73
|
compact_method_range = compact_method_with_final_newline_range(compact_method_range)
|
@@ -78,6 +78,10 @@ module RuboCop
|
|
78
78
|
corrector.remove(compact_method_range)
|
79
79
|
end
|
80
80
|
|
81
|
+
def use_dot?(node)
|
82
|
+
node.respond_to?(:dot?) && node.dot?
|
83
|
+
end
|
84
|
+
|
81
85
|
def map_method_and_compact_method_on_same_line?(map_node, compact_node)
|
82
86
|
compact_node.loc.selector.line == map_node.loc.selector.line
|
83
87
|
end
|
@@ -32,8 +32,7 @@ module RuboCop
|
|
32
32
|
# end
|
33
33
|
#
|
34
34
|
class OpenStruct < Base
|
35
|
-
MSG = 'Consider using `Struct` over `OpenStruct` '
|
36
|
-
'to optimize the performance.'
|
35
|
+
MSG = 'Consider using `Struct` over `OpenStruct` to optimize the performance.'
|
37
36
|
RESTRICT_ON_SEND = %i[new].freeze
|
38
37
|
|
39
38
|
def_node_matcher :open_struct, <<~PATTERN
|
@@ -20,8 +20,7 @@ module RuboCop
|
|
20
20
|
class RedundantMatch < Base
|
21
21
|
extend AutoCorrector
|
22
22
|
|
23
|
-
MSG = 'Use `=~` in places where the `MatchData` returned by '
|
24
|
-
'`#match` will not be used.'
|
23
|
+
MSG = 'Use `=~` in places where the `MatchData` returned by `#match` will not be used.'
|
25
24
|
RESTRICT_ON_SEND = %i[match].freeze
|
26
25
|
|
27
26
|
# 'match' is a fairly generic name, so we don't flag it unless we see
|
@@ -41,21 +40,23 @@ module RuboCop
|
|
41
40
|
!(node.parent && node.parent.block_type?)
|
42
41
|
|
43
42
|
add_offense(node) do |corrector|
|
44
|
-
autocorrect(corrector, node)
|
43
|
+
autocorrect(corrector, node) if autocorrectable?(node)
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
48
47
|
private
|
49
48
|
|
50
49
|
def autocorrect(corrector, node)
|
51
|
-
# Regexp#match can take a second argument, but this cop doesn't
|
52
|
-
# register an offense in that case
|
53
|
-
return unless node.first_argument.regexp_type?
|
54
|
-
|
55
50
|
new_source = "#{node.receiver.source} =~ #{node.first_argument.source}"
|
56
51
|
|
57
52
|
corrector.replace(node.source_range, new_source)
|
58
53
|
end
|
54
|
+
|
55
|
+
def autocorrectable?(node)
|
56
|
+
# Regexp#match can take a second argument, but this cop doesn't
|
57
|
+
# register an offense in that case
|
58
|
+
node.receiver.regexp_type? || node.first_argument.regexp_type?
|
59
|
+
end
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
@@ -28,6 +28,7 @@ module RuboCop
|
|
28
28
|
# hash[:a] = 1
|
29
29
|
# hash[:b] = 2
|
30
30
|
class RedundantMerge < Base
|
31
|
+
include Alignment
|
31
32
|
extend AutoCorrector
|
32
33
|
|
33
34
|
AREF_ASGN = '%<receiver>s[%<key>s] = %<value>s'
|
@@ -99,8 +100,7 @@ module RuboCop
|
|
99
100
|
end
|
100
101
|
|
101
102
|
def non_redundant_value_used?(receiver, node)
|
102
|
-
node.value_used? &&
|
103
|
-
!EachWithObjectInspector.new(node, receiver).value_used?
|
103
|
+
node.value_used? && !EachWithObjectInspector.new(node, receiver).value_used?
|
104
104
|
end
|
105
105
|
|
106
106
|
def correct_multiple_elements(corrector, node, parent, new_source)
|
@@ -125,14 +125,12 @@ module RuboCop
|
|
125
125
|
|
126
126
|
key = key.sym_type? && pair.colon? ? ":#{key.source}" : key.source
|
127
127
|
|
128
|
-
format(AREF_ASGN, receiver: receiver.source,
|
129
|
-
key: key,
|
130
|
-
value: value.source)
|
128
|
+
format(AREF_ASGN, receiver: receiver.source, key: key, value: value.source)
|
131
129
|
end
|
132
130
|
end
|
133
131
|
|
134
132
|
def rewrite_with_modifier(node, parent, new_source)
|
135
|
-
indent = ' ' *
|
133
|
+
indent = ' ' * configured_indentation_width
|
136
134
|
padding = "\n#{indent + leading_spaces(node)}"
|
137
135
|
new_source.gsub!(/\n/, padding)
|
138
136
|
|
@@ -147,10 +145,6 @@ module RuboCop
|
|
147
145
|
node.source_range.source_line[/\A\s*/]
|
148
146
|
end
|
149
147
|
|
150
|
-
def indent_width
|
151
|
-
@config.for_cop('Layout/IndentationWidth')['Width'] || 2
|
152
|
-
end
|
153
|
-
|
154
148
|
def max_key_value_pairs
|
155
149
|
Integer(cop_config['MaxKeyValuePairs'] || 2)
|
156
150
|
end
|
@@ -16,25 +16,33 @@ module RuboCop
|
|
16
16
|
include SortBlock
|
17
17
|
extend AutoCorrector
|
18
18
|
|
19
|
-
MSG = 'Use `sort`
|
19
|
+
MSG = 'Use `sort` without block.'
|
20
20
|
|
21
21
|
def on_block(node)
|
22
22
|
return unless (send, var_a, var_b, body = sort_with_block?(node))
|
23
23
|
|
24
24
|
replaceable_body?(body, var_a, var_b) do
|
25
|
-
|
25
|
+
register_offense(send, node)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_numblock(node)
|
30
|
+
return unless (send, arg_count, body = sort_with_numblock?(node))
|
31
|
+
return unless arg_count == 2
|
26
32
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
33
|
+
replaceable_body?(body, :_1, :_2) do
|
34
|
+
register_offense(send, node)
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
33
38
|
private
|
34
39
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
40
|
+
def register_offense(send, node)
|
41
|
+
range = sort_range(send, node)
|
42
|
+
|
43
|
+
add_offense(range) do |corrector|
|
44
|
+
corrector.replace(range, 'sort')
|
45
|
+
end
|
38
46
|
end
|
39
47
|
end
|
40
48
|
end
|
@@ -9,6 +9,7 @@ module RuboCop
|
|
9
9
|
# # bad
|
10
10
|
# str.chars[0..2]
|
11
11
|
# str.chars.slice(0..2)
|
12
|
+
# str.chars.last
|
12
13
|
#
|
13
14
|
# # good
|
14
15
|
# str[0..2].chars
|
@@ -20,6 +21,7 @@ module RuboCop
|
|
20
21
|
# # good
|
21
22
|
# str[0]
|
22
23
|
# str[0...2].chars
|
24
|
+
# str[-1]
|
23
25
|
#
|
24
26
|
# # bad
|
25
27
|
# str.chars.take(2)
|
@@ -33,9 +35,8 @@ module RuboCop
|
|
33
35
|
# str.size
|
34
36
|
# str.empty?
|
35
37
|
#
|
36
|
-
# # For example, if the receiver is
|
38
|
+
# # For example, if the receiver is an empty string, it will be incompatible.
|
37
39
|
# # If a negative value is specified for the receiver, `nil` is returned.
|
38
|
-
# str.chars.last # Incompatible with `str[-1]`.
|
39
40
|
# str.chars.last(2) # Incompatible with `str[-2..-1].chars`.
|
40
41
|
# str.chars.drop(2) # Incompatible with `str[2..-1].chars`.
|
41
42
|
#
|
@@ -44,7 +45,7 @@ module RuboCop
|
|
44
45
|
extend AutoCorrector
|
45
46
|
|
46
47
|
MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
|
47
|
-
RESTRICT_ON_SEND = %i[[] slice first take length size empty?].freeze
|
48
|
+
RESTRICT_ON_SEND = %i[[] slice first last take length size empty?].freeze
|
48
49
|
|
49
50
|
def_node_matcher :redundant_chars_call?, <<~PATTERN
|
50
51
|
(send $(send _ :chars) $_ $...)
|
@@ -52,6 +53,7 @@ module RuboCop
|
|
52
53
|
|
53
54
|
def on_send(node)
|
54
55
|
return unless (receiver, method, args = redundant_chars_call?(node))
|
56
|
+
return if method == :last && !args.empty?
|
55
57
|
|
56
58
|
range = offense_range(receiver, node)
|
57
59
|
message = build_message(method, args)
|
@@ -86,6 +88,8 @@ module RuboCop
|
|
86
88
|
"[#{build_call_args(args)}].chars"
|
87
89
|
when :[], :first
|
88
90
|
build_good_method_for_brackets_or_first_method(method, args)
|
91
|
+
when :last
|
92
|
+
'[-1]'
|
89
93
|
when :take
|
90
94
|
"[0...#{args.first.source}].chars"
|
91
95
|
else
|
@@ -124,8 +124,8 @@ module RuboCop
|
|
124
124
|
|
125
125
|
def_node_search :last_matches, <<~PATTERN
|
126
126
|
{
|
127
|
-
(send (const nil? :Regexp) :last_match)
|
128
|
-
(send (const nil? :Regexp) :last_match _)
|
127
|
+
(send (const {nil? cbase} :Regexp) :last_match)
|
128
|
+
(send (const {nil? cbase} :Regexp) :last_match _)
|
129
129
|
({back_ref nth_ref} _)
|
130
130
|
(gvar #match_gvar?)
|
131
131
|
}
|
@@ -217,8 +217,7 @@ module RuboCop
|
|
217
217
|
def find_last_match(body, range, scope_root)
|
218
218
|
last_matches(body).find do |ref|
|
219
219
|
ref_pos = ref.loc.expression.begin_pos
|
220
|
-
range.cover?(ref_pos) &&
|
221
|
-
scope_root(ref) == scope_root
|
220
|
+
range.cover?(ref_pos) && scope_root(ref) == scope_root
|
222
221
|
end
|
223
222
|
end
|
224
223
|
|
@@ -241,14 +240,7 @@ module RuboCop
|
|
241
240
|
end
|
242
241
|
|
243
242
|
def match_gvar?(sym)
|
244
|
-
%i[
|
245
|
-
$~
|
246
|
-
$MATCH
|
247
|
-
$PREMATCH
|
248
|
-
$POSTMATCH
|
249
|
-
$LAST_PAREN_MATCH
|
250
|
-
$LAST_MATCH_INFO
|
251
|
-
].include?(sym)
|
243
|
+
%i[$~ $MATCH $PREMATCH $POSTMATCH $LAST_PAREN_MATCH $LAST_MATCH_INFO].include?(sym)
|
252
244
|
end
|
253
245
|
|
254
246
|
def correct_operator(corrector, recv, arg, oper = nil)
|
@@ -17,27 +17,36 @@ module RuboCop
|
|
17
17
|
include SortBlock
|
18
18
|
extend AutoCorrector
|
19
19
|
|
20
|
-
MSG = 'Use `sort.reverse` instead
|
20
|
+
MSG = 'Use `sort.reverse` instead.'
|
21
21
|
|
22
22
|
def on_block(node)
|
23
23
|
sort_with_block?(node) do |send, var_a, var_b, body|
|
24
24
|
replaceable_body?(body, var_b, var_a) do
|
25
|
-
|
25
|
+
register_offense(send, node)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
def on_numblock(node)
|
31
|
+
sort_with_numblock?(node) do |send, arg_count, body|
|
32
|
+
next unless arg_count == 2
|
29
33
|
|
30
|
-
|
31
|
-
|
34
|
+
replaceable_body?(body, :_2, :_1) do
|
35
|
+
register_offense(send, node)
|
32
36
|
end
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
36
40
|
private
|
37
41
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
42
|
+
def register_offense(send, node)
|
43
|
+
range = sort_range(send, node)
|
44
|
+
|
45
|
+
add_offense(range) do |corrector|
|
46
|
+
replacement = 'sort.reverse'
|
47
|
+
|
48
|
+
corrector.replace(range, replacement)
|
49
|
+
end
|
41
50
|
end
|
42
51
|
end
|
43
52
|
end
|
@@ -24,10 +24,7 @@ module RuboCop
|
|
24
24
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
25
25
|
RESTRICT_ON_SEND = %i[gsub gsub!].freeze
|
26
26
|
|
27
|
-
PREFERRED_METHODS = {
|
28
|
-
gsub: :squeeze,
|
29
|
-
gsub!: :squeeze!
|
30
|
-
}.freeze
|
27
|
+
PREFERRED_METHODS = { gsub: :squeeze, gsub!: :squeeze! }.freeze
|
31
28
|
|
32
29
|
def_node_matcher :squeeze_candidate?, <<~PATTERN
|
33
30
|
(send
|
@@ -50,8 +50,7 @@ module RuboCop
|
|
50
50
|
include RegexpMetacharacter
|
51
51
|
extend AutoCorrector
|
52
52
|
|
53
|
-
MSG = 'Use `String#start_with?` instead of a regex match anchored to '
|
54
|
-
'the beginning of the string.'
|
53
|
+
MSG = 'Use `String#start_with?` instead of a regex match anchored to the beginning of the string.'
|
55
54
|
RESTRICT_ON_SEND = %i[match =~ match?].freeze
|
56
55
|
|
57
56
|
def_node_matcher :redundant_regex?, <<~PATTERN
|
@@ -6,39 +6,42 @@ module RuboCop
|
|
6
6
|
# Identifies unnecessary use of a regex where `String#include?` would suffice.
|
7
7
|
#
|
8
8
|
# @safety
|
9
|
-
# This cop's offenses are not safe to autocorrect if a receiver is nil.
|
9
|
+
# This cop's offenses are not safe to autocorrect if a receiver is nil or a Symbol.
|
10
10
|
#
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
|
-
#
|
14
|
-
# /ab/.match?(
|
15
|
-
#
|
16
|
-
# /ab/ =~
|
17
|
-
#
|
18
|
-
# /ab/.match(
|
13
|
+
# str.match?(/ab/)
|
14
|
+
# /ab/.match?(str)
|
15
|
+
# str =~ /ab/
|
16
|
+
# /ab/ =~ str
|
17
|
+
# str.match(/ab/)
|
18
|
+
# /ab/.match(str)
|
19
19
|
#
|
20
20
|
# # good
|
21
|
-
#
|
21
|
+
# str.include?('ab')
|
22
22
|
class StringInclude < Base
|
23
23
|
extend AutoCorrector
|
24
24
|
|
25
|
-
MSG = 'Use
|
26
|
-
RESTRICT_ON_SEND = %i[match =~ match?].freeze
|
25
|
+
MSG = 'Use `%<negation>sString#include?` instead of a regex match with literal-only pattern.'
|
26
|
+
RESTRICT_ON_SEND = %i[match =~ !~ match?].freeze
|
27
27
|
|
28
28
|
def_node_matcher :redundant_regex?, <<~PATTERN
|
29
|
-
{(send $!nil? {:match :=~ :match?} (regexp (str $#literal?) (regopt)))
|
30
|
-
(send (regexp (str $#literal?) (regopt)) {:match :match?} $
|
29
|
+
{(send $!nil? {:match :=~ :!~ :match?} (regexp (str $#literal?) (regopt)))
|
30
|
+
(send (regexp (str $#literal?) (regopt)) {:match :match?} $_)
|
31
31
|
(match-with-lvasgn (regexp (str $#literal?) (regopt)) $_)}
|
32
32
|
PATTERN
|
33
33
|
|
34
34
|
def on_send(node)
|
35
35
|
return unless (receiver, regex_str = redundant_regex?(node))
|
36
36
|
|
37
|
-
|
37
|
+
negation = node.send_type? && node.method?(:!~)
|
38
|
+
message = format(MSG, negation: ('!' if negation))
|
39
|
+
|
40
|
+
add_offense(node, message: message) do |corrector|
|
38
41
|
receiver, regex_str = regex_str, receiver if receiver.is_a?(String)
|
39
42
|
regex_str = interpret_string_escapes(regex_str)
|
40
43
|
|
41
|
-
new_source = "#{receiver.source}.include?(#{to_string_literal(regex_str)})"
|
44
|
+
new_source = "#{'!' if negation}#{receiver.source}.include?(#{to_string_literal(regex_str)})"
|
42
45
|
|
43
46
|
corrector.replace(node.source_range, new_source)
|
44
47
|
end
|
@@ -86,8 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
unless first_param.str_type?
|
88
88
|
return true if options
|
89
|
-
return true unless first_source.is_a?(String) &&
|
90
|
-
first_source =~ DETERMINISTIC_REGEX
|
89
|
+
return true unless first_source.is_a?(String) && first_source =~ DETERMINISTIC_REGEX
|
91
90
|
|
92
91
|
# This must be done after checking DETERMINISTIC_REGEX
|
93
92
|
# Otherwise things like \s will trip us up
|
@@ -141,8 +140,7 @@ module RuboCop
|
|
141
140
|
end
|
142
141
|
|
143
142
|
def message(node, first_source, second_source)
|
144
|
-
replacement_method =
|
145
|
-
replacement_method(node, first_source, second_source)
|
143
|
+
replacement_method = replacement_method(node, first_source, second_source)
|
146
144
|
|
147
145
|
format(MSG, prefer: replacement_method, current: node.method_name)
|
148
146
|
end
|
@@ -152,8 +150,7 @@ module RuboCop
|
|
152
150
|
end
|
153
151
|
|
154
152
|
def remove_second_param(corrector, node, first_param)
|
155
|
-
end_range = range_between(first_param.source_range.end_pos,
|
156
|
-
node.source_range.end_pos)
|
153
|
+
end_range = range_between(first_param.source_range.end_pos, node.source_range.end_pos)
|
157
154
|
|
158
155
|
corrector.replace(end_range, method_suffix(node))
|
159
156
|
end
|
@@ -32,8 +32,7 @@ module RuboCop
|
|
32
32
|
class TimesMap < Base
|
33
33
|
extend AutoCorrector
|
34
34
|
|
35
|
-
MESSAGE = 'Use `Array.new(%<count>s)` with a block '
|
36
|
-
'instead of `.times.%<map_or_collect>s`'
|
35
|
+
MESSAGE = 'Use `Array.new(%<count>s)` with a block instead of `.times.%<map_or_collect>s`'
|
37
36
|
MESSAGE_ONLY_IF = 'only if `%<count>s` is always 0 or more'
|
38
37
|
RESTRICT_ON_SEND = %i[map collect].freeze
|
39
38
|
|
@@ -44,14 +43,14 @@ module RuboCop
|
|
44
43
|
def on_block(node)
|
45
44
|
check(node)
|
46
45
|
end
|
46
|
+
alias on_numblock on_block
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
50
|
def check(node)
|
51
51
|
times_map_call(node) do |map_or_collect, count|
|
52
52
|
add_offense(node, message: message(map_or_collect, count)) do |corrector|
|
53
|
-
replacement = "Array.new(#{count.source}"
|
54
|
-
"#{map_or_collect.arguments.map { |arg| ", #{arg.source}" }.join})"
|
53
|
+
replacement = "Array.new(#{count.source}#{map_or_collect.arguments.map { |arg| ", #{arg.source}" }.join})"
|
55
54
|
|
56
55
|
corrector.replace(map_or_collect.loc.expression, replacement)
|
57
56
|
end
|
@@ -68,7 +67,7 @@ module RuboCop
|
|
68
67
|
end
|
69
68
|
|
70
69
|
def_node_matcher :times_map_call, <<~PATTERN
|
71
|
-
{(block $(send (send $!nil? :times) {:map :collect}) ...)
|
70
|
+
{({block numblock} $(send (send $!nil? :times) {:map :collect}) ...)
|
72
71
|
$(send (send $!nil? :times) {:map :collect} (block_pass ...))}
|
73
72
|
PATTERN
|
74
73
|
end
|
@@ -15,8 +15,7 @@ module RuboCop
|
|
15
15
|
class UriDefaultParser < Base
|
16
16
|
extend AutoCorrector
|
17
17
|
|
18
|
-
MSG = 'Use `%<double_colon>sURI::DEFAULT_PARSER` instead of '
|
19
|
-
'`%<double_colon>sURI::Parser.new`.'
|
18
|
+
MSG = 'Use `%<double_colon>sURI::DEFAULT_PARSER` instead of `%<double_colon>sURI::Parser.new`.'
|
20
19
|
RESTRICT_ON_SEND = %i[new].freeze
|
21
20
|
|
22
21
|
def_node_matcher :uri_parser_new?, <<~PATTERN
|
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.16.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:
|
13
|
+
date: 2023-02-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubocop
|
@@ -123,7 +123,7 @@ metadata:
|
|
123
123
|
homepage_uri: https://docs.rubocop.org/rubocop-performance/
|
124
124
|
changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
|
125
125
|
source_code_uri: https://github.com/rubocop/rubocop-performance/
|
126
|
-
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.
|
126
|
+
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.16/
|
127
127
|
bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
|
128
128
|
rubygems_mfa_required: 'true'
|
129
129
|
post_install_message:
|
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: '0'
|
143
143
|
requirements: []
|
144
|
-
rubygems_version: 3.3.
|
144
|
+
rubygems_version: 3.3.26
|
145
145
|
signing_key:
|
146
146
|
specification_version: 4
|
147
147
|
summary: Automatic performance checking tool for Ruby code.
|