rubocop-performance 1.11.2 → 1.12.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/config/default.yml +11 -1
- data/lib/rubocop/cop/performance/ancestors_include.rb +4 -0
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +8 -6
- data/lib/rubocop/cop/performance/case_when_splat.rb +11 -13
- data/lib/rubocop/cop/performance/casecmp.rb +4 -2
- data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +1 -1
- data/lib/rubocop/cop/performance/concurrent_monotonic_time.rb +42 -0
- data/lib/rubocop/cop/performance/count.rb +22 -13
- data/lib/rubocop/cop/performance/delete_prefix.rb +4 -4
- data/lib/rubocop/cop/performance/delete_suffix.rb +4 -4
- data/lib/rubocop/cop/performance/detect.rb +10 -9
- data/lib/rubocop/cop/performance/end_with.rb +5 -0
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +3 -0
- data/lib/rubocop/cop/performance/map_compact.rb +13 -9
- data/lib/rubocop/cop/performance/open_struct.rb +4 -0
- data/lib/rubocop/cop/performance/range_include.rb +3 -2
- data/lib/rubocop/cop/performance/redundant_block_call.rb +1 -0
- data/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb +20 -7
- data/lib/rubocop/cop/performance/redundant_merge.rb +4 -3
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +7 -17
- data/lib/rubocop/cop/performance/regexp_match.rb +1 -2
- data/lib/rubocop/cop/performance/start_with.rb +5 -0
- data/lib/rubocop/cop/performance/string_include.rb +2 -1
- data/lib/rubocop/cop/performance/sum.rb +1 -1
- data/lib/rubocop/cop/performance/times_map.rb +12 -0
- data/lib/rubocop/cop/performance/unfreeze_string.rb +9 -6
- data/lib/rubocop/cop/performance_cops.rb +1 -0
- data/lib/rubocop/performance/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c98065b3a22d03c0e9290990288d6b8a82a87d956bdf4165d94d3cd326ae7bf5
|
4
|
+
data.tar.gz: a9ee1493235e6584ad381941423c0cac234bfc36fb4a2417433e667a16bec054
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35f36bff7bfe1b19496bfea773e7d0f7892731e57b06bb523ac192324a817f401207750abab20892ea58ec54595d1bdfd454bf250a4a00baf6ef0f4ac3f7b030
|
7
|
+
data.tar.gz: 84a6ebc3e13d7c24aa6f1219443ce2c6cf6cd6c6253d4f09c78056fb3906f08bcb44db5365b03231aae55170a653e504b4a3433b4ed4a4dea1ee21b23d7a1387
|
data/config/default.yml
CHANGED
@@ -76,6 +76,12 @@ Performance/CompareWithBlock:
|
|
76
76
|
Enabled: true
|
77
77
|
VersionAdded: '0.46'
|
78
78
|
|
79
|
+
Performance/ConcurrentMonotonicTime:
|
80
|
+
Description: 'Use `Process.clock_gettime(Process::CLOCK_MONOTONIC)` instead of `Concurrent.monotonic_time`.'
|
81
|
+
Reference: 'https://github.com/rails/rails/pull/43502'
|
82
|
+
Enabled: pending
|
83
|
+
VersionAdded: '1.12'
|
84
|
+
|
79
85
|
Performance/ConstantRegexp:
|
80
86
|
Description: 'Finds regular expressions with dynamic components that are all constants.'
|
81
87
|
Enabled: pending
|
@@ -96,14 +102,18 @@ Performance/Count:
|
|
96
102
|
Performance/DeletePrefix:
|
97
103
|
Description: 'Use `delete_prefix` instead of `gsub`.'
|
98
104
|
Enabled: true
|
105
|
+
Safe: false
|
99
106
|
SafeMultiline: true
|
100
107
|
VersionAdded: '1.6'
|
108
|
+
VersionChanged: '1.11'
|
101
109
|
|
102
110
|
Performance/DeleteSuffix:
|
103
111
|
Description: 'Use `delete_suffix` instead of `gsub`.'
|
104
112
|
Enabled: true
|
113
|
+
Safe: false
|
105
114
|
SafeMultiline: true
|
106
115
|
VersionAdded: '1.6'
|
116
|
+
VersionChanged: '1.11'
|
107
117
|
|
108
118
|
Performance/Detect:
|
109
119
|
Description: >-
|
@@ -305,9 +315,9 @@ Performance/StartWith:
|
|
305
315
|
Performance/StringInclude:
|
306
316
|
Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
|
307
317
|
Enabled: 'pending'
|
308
|
-
AutoCorrect: false
|
309
318
|
SafeAutoCorrect: false
|
310
319
|
VersionAdded: '1.7'
|
320
|
+
VersionChanged: '1.12'
|
311
321
|
|
312
322
|
Performance/StringReplacement:
|
313
323
|
Description: >-
|
@@ -6,6 +6,10 @@ module RuboCop
|
|
6
6
|
# This cop is used to identify usages of `ancestors.include?` and
|
7
7
|
# change them to use `<=` instead.
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe because it can't tell whether the receiver is a class or an object.
|
11
|
+
# e.g. the false positive was for `Nokogiri::XML::Node#ancestors`.
|
12
|
+
#
|
9
13
|
# @example
|
10
14
|
# # bad
|
11
15
|
# A.ancestors.include?(B)
|
@@ -7,15 +7,17 @@ module RuboCop
|
|
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
|
10
|
-
#
|
10
|
+
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe for string slices because strings do not have `#take` and `#drop` methods.
|
11
13
|
#
|
12
14
|
# @example
|
13
15
|
# # bad
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
16
|
+
# array[..2]
|
17
|
+
# array[...2]
|
18
|
+
# array[2..]
|
19
|
+
# array[2...]
|
20
|
+
# array.slice(..2)
|
19
21
|
#
|
20
22
|
# # good
|
21
23
|
# array.take(3)
|
@@ -17,11 +17,13 @@ module RuboCop
|
|
17
17
|
# this defining a higher level when condition to override a condition
|
18
18
|
# that is inside of the splat expansion.
|
19
19
|
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
20
|
+
# @safety
|
21
|
+
# This cop is not unsafe auto-correction because it is not a guaranteed
|
22
|
+
# performance improvement. If the data being processed by the `case` condition is
|
23
|
+
# normalized in a manner that favors hitting a condition in the splat expansion,
|
24
|
+
# it is possible that moving the splat condition to the end will use more memory,
|
25
|
+
# and run slightly slower.
|
26
|
+
# See for more details: https://github.com/rubocop/rubocop/pull/6163
|
25
27
|
#
|
26
28
|
# @example
|
27
29
|
# # bad
|
@@ -58,10 +60,8 @@ module RuboCop
|
|
58
60
|
include RangeHelp
|
59
61
|
extend AutoCorrector
|
60
62
|
|
61
|
-
MSG = 'Reordering `when` conditions with a splat to the end '
|
62
|
-
|
63
|
-
ARRAY_MSG = 'Pass the contents of array literals ' \
|
64
|
-
'directly to `when` conditions.'
|
63
|
+
MSG = 'Reordering `when` conditions with a splat to the end of the `when` branches can improve performance.'
|
64
|
+
ARRAY_MSG = 'Pass the contents of array literals directly to `when` conditions.'
|
65
65
|
|
66
66
|
def on_case(case_node)
|
67
67
|
when_conditions = case_node.when_branches.flat_map(&:conditions)
|
@@ -134,13 +134,11 @@ module RuboCop
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def new_condition_with_then(node, new_condition)
|
137
|
-
"\n#{indent_for(node)}when "
|
138
|
-
"#{new_condition} then #{node.body.source}"
|
137
|
+
"\n#{indent_for(node)}when #{new_condition} then #{node.body.source}"
|
139
138
|
end
|
140
139
|
|
141
140
|
def new_branch_without_then(node, new_condition)
|
142
|
-
"\n#{indent_for(node)}when #{new_condition}"
|
143
|
-
"\n#{indent_for(node.body)}#{node.body.source}"
|
141
|
+
"\n#{indent_for(node)}when #{new_condition}\n#{indent_for(node.body)}#{node.body.source}"
|
144
142
|
end
|
145
143
|
|
146
144
|
def indent_for(node)
|
@@ -5,8 +5,10 @@ module RuboCop
|
|
5
5
|
module Performance
|
6
6
|
# This cop identifies places where a case-insensitive string comparison
|
7
7
|
# can better be implemented using `casecmp`.
|
8
|
-
#
|
9
|
-
#
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe because `String#casecmp` and `String#casecmp?` behave
|
11
|
+
# differently when using Non-ASCII characters.
|
10
12
|
#
|
11
13
|
# @example
|
12
14
|
# # bad
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
#
|
34
34
|
class CollectionLiteralInLoop < Base
|
35
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
|
39
39
|
LOOP_TYPES = (POST_CONDITION_LOOP_TYPES + %i[while until for]).freeze
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop identifies places where `Concurrent.monotonic_time`
|
7
|
+
# can be replaced by `Process.clock_gettime(Process::CLOCK_MONOTONIC)`.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# Concurrent.monotonic_time
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
16
|
+
#
|
17
|
+
class ConcurrentMonotonicTime < Base
|
18
|
+
extend AutoCorrector
|
19
|
+
|
20
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
21
|
+
RESTRICT_ON_SEND = %i[monotonic_time].freeze
|
22
|
+
|
23
|
+
def_node_matcher :concurrent_monotonic_time?, <<~PATTERN
|
24
|
+
(send
|
25
|
+
(const {nil? cbase} :Concurrent) :monotonic_time ...)
|
26
|
+
PATTERN
|
27
|
+
|
28
|
+
def on_send(node)
|
29
|
+
return unless concurrent_monotonic_time?(node)
|
30
|
+
|
31
|
+
optional_unit_parameter = ", #{node.first_argument.source}" if node.first_argument
|
32
|
+
prefer = "Process.clock_gettime(Process::CLOCK_MONOTONIC#{optional_unit_parameter})"
|
33
|
+
message = format(MSG, prefer: prefer, current: node.source)
|
34
|
+
|
35
|
+
add_offense(node, message: message) do |corrector|
|
36
|
+
corrector.replace(node, prefer)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -7,6 +7,28 @@ module RuboCop
|
|
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
|
#
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe because it has known compatibility issues with `ActiveRecord` and other
|
12
|
+
# frameworks. ActiveRecord's `count` ignores the block that is passed to it.
|
13
|
+
# `ActiveRecord` will ignore the block that is passed to `count`.
|
14
|
+
# Other methods, such as `select`, will convert the association to an
|
15
|
+
# array and then run the block on the array. A simple work around to
|
16
|
+
# make `count` work with a block is to call `to_a.count {...}`.
|
17
|
+
#
|
18
|
+
# For example:
|
19
|
+
#
|
20
|
+
# [source,ruby]
|
21
|
+
# ----
|
22
|
+
# `Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size`
|
23
|
+
# ----
|
24
|
+
#
|
25
|
+
# becomes:
|
26
|
+
#
|
27
|
+
# [source,ruby]
|
28
|
+
# ----
|
29
|
+
# `Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }`
|
30
|
+
# ----
|
31
|
+
#
|
10
32
|
# @example
|
11
33
|
# # bad
|
12
34
|
# [1, 2, 3].select { |e| e > 2 }.size
|
@@ -24,19 +46,6 @@ module RuboCop
|
|
24
46
|
# [1, 2, 3].count { |e| e < 2 && e.even? }
|
25
47
|
# Model.select('field AS field_one').count
|
26
48
|
# Model.select(:value).count
|
27
|
-
#
|
28
|
-
# `ActiveRecord` compatibility:
|
29
|
-
# `ActiveRecord` will ignore the block that is passed to `count`.
|
30
|
-
# Other methods, such as `select`, will convert the association to an
|
31
|
-
# array and then run the block on the array. A simple work around to
|
32
|
-
# make `count` work with a block is to call `to_a.count {...}`.
|
33
|
-
#
|
34
|
-
# Example:
|
35
|
-
# `Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size`
|
36
|
-
#
|
37
|
-
# becomes:
|
38
|
-
#
|
39
|
-
# `Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }`
|
40
49
|
class Count < Base
|
41
50
|
include RangeHelp
|
42
51
|
extend AutoCorrector
|
@@ -14,6 +14,9 @@ module RuboCop
|
|
14
14
|
#
|
15
15
|
# The `delete_prefix('prefix')` method is faster than `gsub(/\Aprefix/, '')`.
|
16
16
|
#
|
17
|
+
# @safety
|
18
|
+
# This cop is unsafe because `Pathname` has `sub` but not `delete_prefix`.
|
19
|
+
#
|
17
20
|
# @example
|
18
21
|
#
|
19
22
|
# # bad
|
@@ -46,9 +49,6 @@ module RuboCop
|
|
46
49
|
class DeletePrefix < Base
|
47
50
|
include RegexpMetacharacter
|
48
51
|
extend AutoCorrector
|
49
|
-
extend TargetRubyVersion
|
50
|
-
|
51
|
-
minimum_target_ruby_version 2.5
|
52
52
|
|
53
53
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
54
54
|
RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
|
67
67
|
def on_send(node)
|
68
68
|
return unless (receiver, bad_method, regexp_str, replace_string = delete_prefix_candidate?(node))
|
69
|
-
return unless replace_string.
|
69
|
+
return unless replace_string.empty?
|
70
70
|
|
71
71
|
good_method = PREFERRED_METHODS[bad_method]
|
72
72
|
|
@@ -14,6 +14,9 @@ module RuboCop
|
|
14
14
|
#
|
15
15
|
# The `delete_suffix('suffix')` method is faster than `gsub(/suffix\z/, '')`.
|
16
16
|
#
|
17
|
+
# @safety
|
18
|
+
# This cop is unsafe because `Pathname` has `sub` but not `delete_suffix`.
|
19
|
+
#
|
17
20
|
# @example
|
18
21
|
#
|
19
22
|
# # bad
|
@@ -46,9 +49,6 @@ module RuboCop
|
|
46
49
|
class DeleteSuffix < Base
|
47
50
|
include RegexpMetacharacter
|
48
51
|
extend AutoCorrector
|
49
|
-
extend TargetRubyVersion
|
50
|
-
|
51
|
-
minimum_target_ruby_version 2.5
|
52
52
|
|
53
53
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
54
54
|
RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
|
67
67
|
def on_send(node)
|
68
68
|
return unless (receiver, bad_method, regexp_str, replace_string = delete_suffix_candidate?(node))
|
69
|
-
return unless replace_string.
|
69
|
+
return unless replace_string.empty?
|
70
70
|
|
71
71
|
good_method = PREFERRED_METHODS[bad_method]
|
72
72
|
|
@@ -7,6 +7,11 @@ module RuboCop
|
|
7
7
|
# chained to `select`, `find_all` or `filter` and change them to use
|
8
8
|
# `detect` instead.
|
9
9
|
#
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe because is has known compatibility issues with `ActiveRecord` and other
|
12
|
+
# frameworks. `ActiveRecord` does not implement a `detect` method and `find` has its own
|
13
|
+
# meaning. Correcting `ActiveRecord` methods with this cop should be considered unsafe.
|
14
|
+
#
|
10
15
|
# @example
|
11
16
|
# # bad
|
12
17
|
# [].select { |item| true }.first
|
@@ -31,14 +36,10 @@ module RuboCop
|
|
31
36
|
|
32
37
|
CANDIDATE_METHODS = Set[:select, :find_all, :filter].freeze
|
33
38
|
|
34
|
-
MSG = 'Use `%<prefer>s` instead of '
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
INDEX_MSG = 'Use `%<prefer>s` instead of ' \
|
39
|
-
'`%<first_method>s[%<index>i]`.'
|
40
|
-
INDEX_REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of ' \
|
41
|
-
'`%<first_method>s[%<index>i]`.'
|
39
|
+
MSG = 'Use `%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
|
40
|
+
REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
|
41
|
+
INDEX_MSG = 'Use `%<prefer>s` instead of `%<first_method>s[%<index>i]`.'
|
42
|
+
INDEX_REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of `%<first_method>s[%<index>i]`.'
|
42
43
|
RESTRICT_ON_SEND = %i[first last []].freeze
|
43
44
|
|
44
45
|
def_node_matcher :detect_candidate?, <<~PATTERN
|
@@ -94,7 +95,7 @@ module RuboCop
|
|
94
95
|
end
|
95
96
|
|
96
97
|
def replacement(method, index)
|
97
|
-
if method == :last || method == :[] && index == -1
|
98
|
+
if method == :last || (method == :[] && index == -1)
|
98
99
|
"reverse.#{preferred_method}"
|
99
100
|
else
|
100
101
|
preferred_method
|
@@ -9,6 +9,11 @@ module RuboCop
|
|
9
9
|
# `end$` is unsafe as it will behave incompatible with `end_with?`
|
10
10
|
# for receiver is multiline string.
|
11
11
|
#
|
12
|
+
# @safety
|
13
|
+
# This will change to a new method call which isn't guaranteed to be on the
|
14
|
+
# object. Switching these methods has to be done with knowledge of the types
|
15
|
+
# of the variables which rubocop doesn't have.
|
16
|
+
#
|
12
17
|
# @example
|
13
18
|
# # bad
|
14
19
|
# 'abc'.match?(/bc\Z/)
|
@@ -15,6 +15,9 @@ module RuboCop
|
|
15
15
|
# both perform an O(n) search through all of the values, calling `values`
|
16
16
|
# allocates a new array while using `value?` does not.
|
17
17
|
#
|
18
|
+
# @safety
|
19
|
+
# This cop is unsafe because it can't tell whether the receiver is a hash object.
|
20
|
+
#
|
18
21
|
# @example
|
19
22
|
# # bad
|
20
23
|
# { a: 1, b: 2 }.keys.include?(:a)
|
@@ -6,8 +6,10 @@ module RuboCop
|
|
6
6
|
# In Ruby 2.7, `Enumerable#filter_map` has been added.
|
7
7
|
#
|
8
8
|
# This cop identifies places where `map { ... }.compact` can be replaced by `filter_map`.
|
9
|
-
#
|
10
|
-
#
|
9
|
+
#
|
10
|
+
# @safety
|
11
|
+
# This cop's autocorrection is unsafe because `map { ... }.compact` that is not
|
12
|
+
# compatible with `filter_map`.
|
11
13
|
#
|
12
14
|
# [source,ruby]
|
13
15
|
# ----
|
@@ -23,6 +25,7 @@ module RuboCop
|
|
23
25
|
# # good
|
24
26
|
# ary.filter_map(&:foo)
|
25
27
|
# ary.map(&:foo).compact!
|
28
|
+
# ary.compact.map(&:foo)
|
26
29
|
#
|
27
30
|
class MapCompact < Base
|
28
31
|
include RangeHelp
|
@@ -55,23 +58,24 @@ module RuboCop
|
|
55
58
|
|
56
59
|
add_offense(range) do |corrector|
|
57
60
|
corrector.replace(map_node.loc.selector, 'filter_map')
|
58
|
-
corrector
|
59
|
-
corrector.remove(compact_method_range(node))
|
61
|
+
remove_compact_method(corrector, node)
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
65
|
private
|
64
66
|
|
65
|
-
def
|
67
|
+
def remove_compact_method(corrector, compact_node)
|
66
68
|
chained_method = compact_node.parent
|
67
69
|
compact_method_range = compact_node.loc.selector
|
68
70
|
|
69
|
-
if compact_node.multiline? &&
|
70
|
-
|
71
|
-
range_by_whole_lines(compact_method_range, include_final_newline: true)
|
71
|
+
if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) && chained_method.dot? &&
|
72
|
+
!invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
|
73
|
+
compact_method_range = range_by_whole_lines(compact_method_range, include_final_newline: true)
|
72
74
|
else
|
73
|
-
|
75
|
+
corrector.remove(compact_node.loc.dot)
|
74
76
|
end
|
77
|
+
|
78
|
+
corrector.remove(compact_method_range)
|
75
79
|
end
|
76
80
|
|
77
81
|
def invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
|
@@ -11,6 +11,10 @@ module RuboCop
|
|
11
11
|
# especially in case of single-threaded
|
12
12
|
# applications with multiple `OpenStruct` instantiations.
|
13
13
|
#
|
14
|
+
# @safety
|
15
|
+
# This cop is unsafe because `OpenStruct.new` and `Struct.new`
|
16
|
+
# are not equivalent.
|
17
|
+
#
|
14
18
|
# @example
|
15
19
|
# # bad
|
16
20
|
# class MyClass
|
@@ -9,8 +9,9 @@ module RuboCop
|
|
9
9
|
# end points of the `Range`. In a great majority of cases, this is what
|
10
10
|
# is wanted.
|
11
11
|
#
|
12
|
-
#
|
13
|
-
# `Range#
|
12
|
+
# @safety
|
13
|
+
# This cop is unsafe because `Range#include?` (or `Range#member?`) and `Range#cover?`
|
14
|
+
# are not equivalent behaviour.
|
14
15
|
#
|
15
16
|
# @example
|
16
17
|
# # bad
|
@@ -9,8 +9,9 @@ module RuboCop
|
|
9
9
|
# By default, `Object#===` behaves the same as `Object#==`, but this
|
10
10
|
# behavior is appropriately overridden in subclass. For example,
|
11
11
|
# `Range#===` returns `true` when argument is within the range.
|
12
|
-
#
|
13
|
-
#
|
12
|
+
#
|
13
|
+
# @safety
|
14
|
+
# This cop is unsafe because `===` and `==` do not always behave the same.
|
14
15
|
#
|
15
16
|
# @example
|
16
17
|
# # bad
|
@@ -24,9 +25,6 @@ module RuboCop
|
|
24
25
|
#
|
25
26
|
class RedundantEqualityComparisonBlock < Base
|
26
27
|
extend AutoCorrector
|
27
|
-
extend TargetRubyVersion
|
28
|
-
|
29
|
-
minimum_target_ruby_version 2.5
|
30
28
|
|
31
29
|
MSG = 'Use `%<prefer>s` instead of block.'
|
32
30
|
|
@@ -74,12 +72,27 @@ module RuboCop
|
|
74
72
|
|
75
73
|
def new_argument(block_argument, block_body)
|
76
74
|
if block_argument.source == block_body.receiver.source
|
77
|
-
block_body.first_argument
|
75
|
+
rhs = block_body.first_argument
|
76
|
+
return if use_block_argument_in_method_argument_of_operand?(block_argument, rhs)
|
77
|
+
|
78
|
+
rhs.source
|
78
79
|
elsif block_argument.source == block_body.first_argument.source
|
79
|
-
block_body.receiver
|
80
|
+
lhs = block_body.receiver
|
81
|
+
return if use_block_argument_in_method_argument_of_operand?(block_argument, lhs)
|
82
|
+
|
83
|
+
lhs.source
|
80
84
|
end
|
81
85
|
end
|
82
86
|
|
87
|
+
def use_block_argument_in_method_argument_of_operand?(block_argument, operand)
|
88
|
+
return false unless operand.send_type?
|
89
|
+
|
90
|
+
arguments = operand.arguments
|
91
|
+
arguments.inject(arguments.map(&:source)) do |operand_sources, argument|
|
92
|
+
operand_sources + argument.each_descendant(:lvar).map(&:source)
|
93
|
+
end.any?(block_argument.source)
|
94
|
+
end
|
95
|
+
|
83
96
|
def offense_range(node)
|
84
97
|
node.send_node.loc.selector.join(node.source_range.end)
|
85
98
|
end
|
@@ -8,8 +8,9 @@ module RuboCop
|
|
8
8
|
# You can set the maximum number of key-value pairs to consider
|
9
9
|
# an offense with `MaxKeyValuePairs`.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because RuboCop cannot determine if the
|
13
|
+
# receiver of `merge!` is actually a hash or not.
|
13
14
|
#
|
14
15
|
# @example
|
15
16
|
# # bad
|
@@ -91,7 +92,7 @@ module RuboCop
|
|
91
92
|
end
|
92
93
|
|
93
94
|
def non_redundant_pairs?(receiver, pairs)
|
94
|
-
pairs.size > 1 && !receiver.pure? || pairs.size > max_key_value_pairs
|
95
|
+
(pairs.size > 1 && !receiver.pure?) || pairs.size > max_key_value_pairs
|
95
96
|
end
|
96
97
|
|
97
98
|
def kwsplat_used?(pairs)
|
@@ -16,35 +16,35 @@ module RuboCop
|
|
16
16
|
# # bad
|
17
17
|
# str.chars.first
|
18
18
|
# str.chars.first(2)
|
19
|
-
# str.chars.last
|
20
|
-
# str.chars.last(2)
|
21
19
|
#
|
22
20
|
# # good
|
23
21
|
# str[0]
|
24
22
|
# str[0...2].chars
|
25
|
-
# str[-1]
|
26
|
-
# str[-2..-1].chars
|
27
23
|
#
|
28
24
|
# # bad
|
29
25
|
# str.chars.take(2)
|
30
|
-
# str.chars.drop(2)
|
31
26
|
# str.chars.length
|
32
27
|
# str.chars.size
|
33
28
|
# str.chars.empty?
|
34
29
|
#
|
35
30
|
# # good
|
36
31
|
# str[0...2].chars
|
37
|
-
# str[2..-1].chars
|
38
32
|
# str.length
|
39
33
|
# str.size
|
40
34
|
# str.empty?
|
41
35
|
#
|
36
|
+
# # For example, if the receiver is a blank string, it will be incompatible.
|
37
|
+
# # If a negative value is specified for the receiver, `nil` is returned.
|
38
|
+
# str.chars.last # Incompatible with `str[-1]`.
|
39
|
+
# str.chars.last(2) # Incompatible with `str[-2..-1].chars`.
|
40
|
+
# str.chars.drop(2) # Incompatible with `str[2..-1].chars`.
|
41
|
+
#
|
42
42
|
class RedundantStringChars < Base
|
43
43
|
include RangeHelp
|
44
44
|
extend AutoCorrector
|
45
45
|
|
46
46
|
MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
|
47
|
-
RESTRICT_ON_SEND = %i[[] slice first
|
47
|
+
RESTRICT_ON_SEND = %i[[] slice first take length size empty?].freeze
|
48
48
|
|
49
49
|
def_node_matcher :redundant_chars_call?, <<~PATTERN
|
50
50
|
(send $(send _ :chars) $_ $...)
|
@@ -80,7 +80,6 @@ module RuboCop
|
|
80
80
|
format(MSG, good_method: good_method, bad_method: bad_method)
|
81
81
|
end
|
82
82
|
|
83
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
84
83
|
def build_good_method(method, args)
|
85
84
|
case method
|
86
85
|
when :[], :slice
|
@@ -91,21 +90,12 @@ module RuboCop
|
|
91
90
|
else
|
92
91
|
'[0]'
|
93
92
|
end
|
94
|
-
when :last
|
95
|
-
if args.any?
|
96
|
-
"[-#{args.first.source}..-1].chars"
|
97
|
-
else
|
98
|
-
'[-1]'
|
99
|
-
end
|
100
93
|
when :take
|
101
94
|
"[0...#{args.first.source}].chars"
|
102
|
-
when :drop
|
103
|
-
"[#{args.first.source}..-1].chars"
|
104
95
|
else
|
105
96
|
".#{method}"
|
106
97
|
end
|
107
98
|
end
|
108
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
109
99
|
|
110
100
|
def build_bad_method(method, args)
|
111
101
|
case method
|
@@ -78,8 +78,7 @@ module RuboCop
|
|
78
78
|
# Constants are included in this list because it is unlikely that
|
79
79
|
# someone will store `nil` as a constant and then use it for comparison
|
80
80
|
TYPES_IMPLEMENTING_MATCH = %i[const regexp str sym].freeze
|
81
|
-
MSG = 'Use `match?` instead of `%<current>s` when `MatchData` '
|
82
|
-
'is not used.'
|
81
|
+
MSG = 'Use `match?` instead of `%<current>s` when `MatchData` is not used.'
|
83
82
|
|
84
83
|
def_node_matcher :match_method?, <<~PATTERN
|
85
84
|
{
|
@@ -9,6 +9,11 @@ module RuboCop
|
|
9
9
|
# `^start` is unsafe as it will behave incompatible with `start_with?`
|
10
10
|
# for receiver is multiline string.
|
11
11
|
#
|
12
|
+
# @safety
|
13
|
+
# This will change to a new method call which isn't guaranteed to be on the
|
14
|
+
# object. Switching these methods has to be done with knowledge of the types
|
15
|
+
# of the variables which rubocop doesn't have.
|
16
|
+
#
|
12
17
|
# @example
|
13
18
|
# # bad
|
14
19
|
# 'abc'.match?(/\Aab/)
|
@@ -6,7 +6,8 @@ module RuboCop
|
|
6
6
|
# This cop identifies unnecessary use of a regex where
|
7
7
|
# `String#include?` would suffice.
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# @safety
|
10
|
+
# This cop's offenses are not safe to auto-correct if a receiver is nil.
|
10
11
|
#
|
11
12
|
# @example
|
12
13
|
# # bad
|
@@ -7,6 +7,18 @@ module RuboCop
|
|
7
7
|
# In most cases such calls can be replaced
|
8
8
|
# with an explicit array creation.
|
9
9
|
#
|
10
|
+
# @safety
|
11
|
+
# This cop's autocorrection is unsafe because `Integer#times` does nothing if receiver is 0
|
12
|
+
# or less. However, `Array.new` raises an error if argument is less than 0.
|
13
|
+
#
|
14
|
+
# For example:
|
15
|
+
#
|
16
|
+
# [source,ruby]
|
17
|
+
# ----
|
18
|
+
# -1.times{} # does nothing
|
19
|
+
# Array.new(-1) # ArgumentError: negative array size
|
20
|
+
# ----
|
21
|
+
#
|
10
22
|
# @example
|
11
23
|
# # bad
|
12
24
|
# 9.times.map do |i|
|
@@ -7,11 +7,11 @@ module RuboCop
|
|
7
7
|
# literal instead of `String#dup` and `String.new`.
|
8
8
|
# Unary plus operator is faster than `String#dup`.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
10
|
+
# @safety
|
11
|
+
# This cop's autocorrection is unsafe because `String.new` (without operator) is not
|
12
|
+
# exactly the same as `+''`. These differ in encoding. `String.new.encoding` is always
|
13
|
+
# `ASCII-8BIT`. However, `(+'').encoding` is the same as script encoding(e.g. `UTF-8`).
|
14
|
+
# if you expect `ASCII-8BIT` encoding, disable this cop.
|
15
15
|
#
|
16
16
|
# @example
|
17
17
|
# # bad
|
@@ -45,7 +45,10 @@ module RuboCop
|
|
45
45
|
return unless dup_string?(node) || string_new?(node)
|
46
46
|
|
47
47
|
add_offense(node) do |corrector|
|
48
|
-
|
48
|
+
string_value = "+#{string_value(node)}"
|
49
|
+
string_value = "(#{string_value})" if node.parent&.send_type?
|
50
|
+
|
51
|
+
corrector.replace(node, string_value)
|
49
52
|
end
|
50
53
|
end
|
51
54
|
|
@@ -13,6 +13,7 @@ require_relative 'performance/case_when_splat'
|
|
13
13
|
require_relative 'performance/casecmp'
|
14
14
|
require_relative 'performance/collection_literal_in_loop'
|
15
15
|
require_relative 'performance/compare_with_block'
|
16
|
+
require_relative 'performance/concurrent_monotonic_time'
|
16
17
|
require_relative 'performance/constant_regexp'
|
17
18
|
require_relative 'performance/count'
|
18
19
|
require_relative 'performance/delete_prefix'
|
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.12.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: 2021-
|
13
|
+
date: 2021-10-31 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rubocop
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/rubocop/cop/performance/chain_array_allocation.rb
|
75
75
|
- lib/rubocop/cop/performance/collection_literal_in_loop.rb
|
76
76
|
- lib/rubocop/cop/performance/compare_with_block.rb
|
77
|
+
- lib/rubocop/cop/performance/concurrent_monotonic_time.rb
|
77
78
|
- lib/rubocop/cop/performance/constant_regexp.rb
|
78
79
|
- lib/rubocop/cop/performance/count.rb
|
79
80
|
- lib/rubocop/cop/performance/delete_prefix.rb
|
@@ -121,7 +122,7 @@ metadata:
|
|
121
122
|
homepage_uri: https://docs.rubocop.org/rubocop-performance/
|
122
123
|
changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
|
123
124
|
source_code_uri: https://github.com/rubocop/rubocop-performance/
|
124
|
-
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.
|
125
|
+
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.12/
|
125
126
|
bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
|
126
127
|
post_install_message:
|
127
128
|
rdoc_options: []
|
@@ -138,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
139
|
- !ruby/object:Gem::Version
|
139
140
|
version: '0'
|
140
141
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
142
|
+
rubygems_version: 3.3.0.dev
|
142
143
|
signing_key:
|
143
144
|
specification_version: 4
|
144
145
|
summary: Automatic performance checking tool for Ruby code.
|