rubocop-performance 1.11.2 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|