rubocop-performance 1.11.5 → 1.13.2
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 +21 -8
- data/lib/rubocop/cop/performance/ancestors_include.rb +4 -0
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +3 -1
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +23 -12
- data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +2 -1
- data/lib/rubocop/cop/performance/case_when_splat.rb +7 -5
- data/lib/rubocop/cop/performance/casecmp.rb +4 -2
- 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 +3 -4
- data/lib/rubocop/cop/performance/delete_suffix.rb +3 -4
- data/lib/rubocop/cop/performance/detect.rb +6 -5
- data/lib/rubocop/cop/performance/double_start_end_with.rb +21 -0
- 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 +20 -6
- 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 +3 -5
- data/lib/rubocop/cop/performance/redundant_merge.rb +4 -3
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +15 -7
- data/lib/rubocop/cop/performance/start_with.rb +5 -0
- data/lib/rubocop/cop/performance/string_identifier_argument.rb +62 -0
- data/lib/rubocop/cop/performance/string_include.rb +2 -1
- data/lib/rubocop/cop/performance/sum.rb +47 -23
- data/lib/rubocop/cop/performance/times_map.rb +12 -0
- data/lib/rubocop/cop/performance/unfreeze_string.rb +5 -5
- data/lib/rubocop/cop/performance_cops.rb +2 -0
- data/lib/rubocop/performance/version.rb +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee80f72f854adad1ef3a54295f5b732578373d11d19eae5b7ea0386bd2fa0f25
|
4
|
+
data.tar.gz: da36ad6040d986c56430965521ee1e597d3bc0919fa9c77ec1e34e5ca2cf43d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 255bba802b4023ec8be39476cc06c7614a4f7cbce11260a608f4c5c479f6e3d9b41ad6a286f8d42cb805ae65995d3bb29f46a746080dde0fa121f3a269cfaeb9
|
7
|
+
data.tar.gz: 24bffb35ce7441354bb42920d3ec49a07fa005edd4847bdd81066d22beda71dbb186e5e82205c6ad181372be1963e431751466560345068d995400f237297fb8
|
data/LICENSE.txt
CHANGED
data/config/default.yml
CHANGED
@@ -17,7 +17,7 @@ Performance/ArraySemiInfiniteRangeSlice:
|
|
17
17
|
VersionAdded: '1.9'
|
18
18
|
|
19
19
|
Performance/BigDecimalWithNumericArgument:
|
20
|
-
Description: 'Convert numeric
|
20
|
+
Description: 'Convert numeric literal to string and pass it to `BigDecimal`.'
|
21
21
|
Enabled: 'pending'
|
22
22
|
VersionAdded: '1.7'
|
23
23
|
|
@@ -43,10 +43,9 @@ Performance/CaseWhenSplat:
|
|
43
43
|
Reordering `when` conditions with a splat to the end
|
44
44
|
of the `when` branches can improve performance.
|
45
45
|
Enabled: false
|
46
|
-
AutoCorrect: false
|
47
46
|
SafeAutoCorrect: false
|
48
47
|
VersionAdded: '0.34'
|
49
|
-
VersionChanged: '
|
48
|
+
VersionChanged: '1.13'
|
50
49
|
|
51
50
|
Performance/Casecmp:
|
52
51
|
Description: >-
|
@@ -76,6 +75,12 @@ Performance/CompareWithBlock:
|
|
76
75
|
Enabled: true
|
77
76
|
VersionAdded: '0.46'
|
78
77
|
|
78
|
+
Performance/ConcurrentMonotonicTime:
|
79
|
+
Description: 'Use `Process.clock_gettime(Process::CLOCK_MONOTONIC)` instead of `Concurrent.monotonic_time`.'
|
80
|
+
Reference: 'https://github.com/rails/rails/pull/43502'
|
81
|
+
Enabled: pending
|
82
|
+
VersionAdded: '1.12'
|
83
|
+
|
79
84
|
Performance/ConstantRegexp:
|
80
85
|
Description: 'Finds regular expressions with dynamic components that are all constants.'
|
81
86
|
Enabled: pending
|
@@ -131,7 +136,7 @@ Performance/DoubleStartEndWith:
|
|
131
136
|
VersionAdded: '0.36'
|
132
137
|
VersionChanged: '0.48'
|
133
138
|
# Used to check for `starts_with?` and `ends_with?`.
|
134
|
-
# These methods are defined by
|
139
|
+
# These methods are defined by Active Support.
|
135
140
|
IncludeActiveSupportAliases: false
|
136
141
|
|
137
142
|
Performance/EndWith:
|
@@ -306,12 +311,17 @@ Performance/StartWith:
|
|
306
311
|
VersionAdded: '0.36'
|
307
312
|
VersionChanged: '1.10'
|
308
313
|
|
314
|
+
Performance/StringIdentifierArgument:
|
315
|
+
Description: 'Use symbol identifier argument instead of string identifier argument.'
|
316
|
+
Enabled: pending
|
317
|
+
VersionAdded: '1.13'
|
318
|
+
|
309
319
|
Performance/StringInclude:
|
310
320
|
Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
|
311
321
|
Enabled: 'pending'
|
312
|
-
AutoCorrect: false
|
313
322
|
SafeAutoCorrect: false
|
314
323
|
VersionAdded: '1.7'
|
324
|
+
VersionChanged: '1.12'
|
315
325
|
|
316
326
|
Performance/StringReplacement:
|
317
327
|
Description: >-
|
@@ -324,17 +334,20 @@ Performance/StringReplacement:
|
|
324
334
|
|
325
335
|
Performance/Sum:
|
326
336
|
Description: 'Use `sum` instead of a custom array summation.'
|
337
|
+
SafeAutoCorrect: false
|
327
338
|
Reference: 'https://blog.bigbinary.com/2016/11/02/ruby-2-4-introduces-enumerable-sum.html'
|
328
339
|
Enabled: 'pending'
|
329
340
|
VersionAdded: '1.8'
|
341
|
+
VersionChanged: '1.13'
|
342
|
+
OnlySumOrWithInitialValue: false
|
330
343
|
|
331
344
|
Performance/TimesMap:
|
332
345
|
Description: 'Checks for .times.map calls.'
|
333
|
-
AutoCorrect: false
|
334
346
|
Enabled: true
|
347
|
+
# See https://github.com/rubocop/rubocop/issues/4658
|
348
|
+
SafeAutoCorrect: false
|
335
349
|
VersionAdded: '0.36'
|
336
|
-
VersionChanged: '
|
337
|
-
SafeAutoCorrect: false # see https://github.com/rubocop/rubocop/issues/4658
|
350
|
+
VersionChanged: '1.13'
|
338
351
|
|
339
352
|
Performance/UnfreezeString:
|
340
353
|
Description: 'Use unary plus to get an unfrozen string literal.'
|
@@ -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,7 +7,9 @@ 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
|
@@ -10,36 +10,47 @@ module RuboCop
|
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
12
|
# BigDecimal(1, 2)
|
13
|
+
# 4.to_d(6)
|
13
14
|
# BigDecimal(1.2, 3, exception: true)
|
15
|
+
# 4.5.to_d(6, exception: true)
|
14
16
|
#
|
15
17
|
# # good
|
16
18
|
# BigDecimal('1', 2)
|
19
|
+
# BigDecimal('4', 6)
|
17
20
|
# BigDecimal('1.2', 3, exception: true)
|
21
|
+
# BigDecimal('4.5', 6, exception: true)
|
18
22
|
#
|
19
23
|
class BigDecimalWithNumericArgument < Base
|
20
24
|
extend AutoCorrector
|
21
25
|
|
22
|
-
MSG = 'Convert numeric
|
23
|
-
RESTRICT_ON_SEND = %i[BigDecimal].freeze
|
26
|
+
MSG = 'Convert numeric literal to string and pass it to `BigDecimal`.'
|
27
|
+
RESTRICT_ON_SEND = %i[BigDecimal to_d].freeze
|
24
28
|
|
25
29
|
def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
|
26
30
|
(send nil? :BigDecimal $numeric_type? ...)
|
27
31
|
PATTERN
|
28
32
|
|
33
|
+
def_node_matcher :to_d?, <<~PATTERN
|
34
|
+
(send [!nil? $numeric_type?] :to_d ...)
|
35
|
+
PATTERN
|
36
|
+
|
29
37
|
def on_send(node)
|
30
|
-
|
31
|
-
|
38
|
+
if (numeric = big_decimal_with_numeric_argument?(node))
|
39
|
+
add_offense(numeric.source_range) do |corrector|
|
40
|
+
corrector.wrap(numeric, "'", "'")
|
41
|
+
end
|
42
|
+
elsif (numeric_to_d = to_d?(node))
|
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(', ')
|
32
49
|
|
33
|
-
|
34
|
-
|
50
|
+
corrector.replace(node, "BigDecimal(#{big_decimal_args})")
|
51
|
+
end
|
35
52
|
end
|
36
53
|
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def specifies_precision?(node)
|
41
|
-
node.arguments.size > 1 && !node.arguments[1].hash_type?
|
42
|
-
end
|
43
54
|
end
|
44
55
|
end
|
45
56
|
end
|
@@ -38,8 +38,9 @@ module RuboCop
|
|
38
38
|
|
39
39
|
block_arg = def_node.arguments.find(&:blockarg_type?)
|
40
40
|
return unless block_arg
|
41
|
+
return unless (block_arg_name = block_arg.loc.name)
|
41
42
|
|
42
|
-
block_arg_name =
|
43
|
+
block_arg_name = block_arg_name.source.to_sym
|
43
44
|
return if reassigns_block_arg?(def_node, block_arg_name)
|
44
45
|
|
45
46
|
add_offense(node) do |corrector|
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -7,7 +7,6 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# This cop identifies places where `gsub(/\Aprefix/, '')` and `sub(/\Aprefix/, '')`
|
9
9
|
# can be replaced by `delete_prefix('prefix')`.
|
10
|
-
# It is marked as unsafe by default because `Pathname` has `sub` but not `delete_prefix`.
|
11
10
|
#
|
12
11
|
# This cop has `SafeMultiline` configuration option that `true` by default because
|
13
12
|
# `^prefix` is unsafe as it will behave incompatible with `delete_prefix`
|
@@ -15,6 +14,9 @@ module RuboCop
|
|
15
14
|
#
|
16
15
|
# The `delete_prefix('prefix')` method is faster than `gsub(/\Aprefix/, '')`.
|
17
16
|
#
|
17
|
+
# @safety
|
18
|
+
# This cop is unsafe because `Pathname` has `sub` but not `delete_prefix`.
|
19
|
+
#
|
18
20
|
# @example
|
19
21
|
#
|
20
22
|
# # bad
|
@@ -47,9 +49,6 @@ module RuboCop
|
|
47
49
|
class DeletePrefix < Base
|
48
50
|
include RegexpMetacharacter
|
49
51
|
extend AutoCorrector
|
50
|
-
extend TargetRubyVersion
|
51
|
-
|
52
|
-
minimum_target_ruby_version 2.5
|
53
52
|
|
54
53
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
55
54
|
RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze
|
@@ -7,7 +7,6 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# This cop identifies places where `gsub(/suffix\z/, '')` and `sub(/suffix\z/, '')`
|
9
9
|
# can be replaced by `delete_suffix('suffix')`.
|
10
|
-
# It is marked as unsafe by default because `Pathname` has `sub` but not `delete_suffix`.
|
11
10
|
#
|
12
11
|
# This cop has `SafeMultiline` configuration option that `true` by default because
|
13
12
|
# `suffix$` is unsafe as it will behave incompatible with `delete_suffix?`
|
@@ -15,6 +14,9 @@ module RuboCop
|
|
15
14
|
#
|
16
15
|
# The `delete_suffix('suffix')` method is faster than `gsub(/suffix\z/, '')`.
|
17
16
|
#
|
17
|
+
# @safety
|
18
|
+
# This cop is unsafe because `Pathname` has `sub` but not `delete_suffix`.
|
19
|
+
#
|
18
20
|
# @example
|
19
21
|
#
|
20
22
|
# # bad
|
@@ -47,9 +49,6 @@ module RuboCop
|
|
47
49
|
class DeleteSuffix < Base
|
48
50
|
include RegexpMetacharacter
|
49
51
|
extend AutoCorrector
|
50
|
-
extend TargetRubyVersion
|
51
|
-
|
52
|
-
minimum_target_ruby_version 2.5
|
53
52
|
|
54
53
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
55
54
|
RESTRICT_ON_SEND = %i[gsub gsub! sub sub!].freeze
|
@@ -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
|
@@ -22,10 +27,6 @@ module RuboCop
|
|
22
27
|
# [].detect { |item| true }
|
23
28
|
# [].reverse.detect { |item| true }
|
24
29
|
#
|
25
|
-
# `ActiveRecord` compatibility:
|
26
|
-
# `ActiveRecord` does not implement a `detect` method and `find` has its
|
27
|
-
# own meaning. Correcting ActiveRecord methods with this cop should be
|
28
|
-
# considered unsafe.
|
29
30
|
class Detect < Base
|
30
31
|
extend AutoCorrector
|
31
32
|
|
@@ -90,7 +91,7 @@ module RuboCop
|
|
90
91
|
end
|
91
92
|
|
92
93
|
def replacement(method, index)
|
93
|
-
if method == :last || method == :[] && index == -1
|
94
|
+
if method == :last || (method == :[] && index == -1)
|
94
95
|
"reverse.#{preferred_method}"
|
95
96
|
else
|
96
97
|
preferred_method
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
# separated by `||`. In some cases such calls can be replaced
|
8
8
|
# with an single `#start_with?`/`#end_with?` call.
|
9
9
|
#
|
10
|
+
# `IncludeActiveSupportAliases` configuration option is used to check for
|
11
|
+
# `starts_with?` and `ends_with?`. These methods are defined by Active Support.
|
12
|
+
#
|
10
13
|
# @example
|
11
14
|
# # bad
|
12
15
|
# str.start_with?("a") || str.start_with?(Some::CONST)
|
@@ -17,6 +20,24 @@ module RuboCop
|
|
17
20
|
# str.start_with?("a", Some::CONST)
|
18
21
|
# str.start_with?("a", "b", "c")
|
19
22
|
# str.end_with?(var1, var2)
|
23
|
+
#
|
24
|
+
# @example IncludeActiveSupportAliases: false (default)
|
25
|
+
# # good
|
26
|
+
# str.starts_with?("a", "b") || str.starts_with?("c")
|
27
|
+
# str.ends_with?(var1) || str.ends_with?(var2)
|
28
|
+
#
|
29
|
+
# str.starts_with?("a", "b", "c")
|
30
|
+
# str.ends_with?(var1, var2)
|
31
|
+
#
|
32
|
+
# @example IncludeActiveSupportAliases: true
|
33
|
+
# # bad
|
34
|
+
# str.starts_with?("a", "b") || str.starts_with?("c")
|
35
|
+
# str.ends_with?(var1) || str.ends_with?(var2)
|
36
|
+
#
|
37
|
+
# # good
|
38
|
+
# str.starts_with?("a", "b", "c")
|
39
|
+
# str.ends_with?(var1, var2)
|
40
|
+
#
|
20
41
|
class DoubleStartEndWith < Base
|
21
42
|
extend AutoCorrector
|
22
43
|
|
@@ -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
|
# ----
|
@@ -56,19 +58,19 @@ module RuboCop
|
|
56
58
|
|
57
59
|
add_offense(range) do |corrector|
|
58
60
|
corrector.replace(map_node.loc.selector, 'filter_map')
|
59
|
-
remove_compact_method(corrector, node)
|
61
|
+
remove_compact_method(corrector, node, node.parent)
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
65
|
private
|
64
66
|
|
65
|
-
def remove_compact_method(corrector, compact_node)
|
66
|
-
chained_method = compact_node.parent
|
67
|
+
def remove_compact_method(corrector, compact_node, chained_method)
|
67
68
|
compact_method_range = compact_node.loc.selector
|
68
69
|
|
69
70
|
if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) && chained_method.dot? &&
|
71
|
+
!map_method_and_compact_method_on_same_line?(compact_node) &&
|
70
72
|
!invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
|
71
|
-
compact_method_range =
|
73
|
+
compact_method_range = compact_method_with_final_newline_range(compact_method_range)
|
72
74
|
else
|
73
75
|
corrector.remove(compact_node.loc.dot)
|
74
76
|
end
|
@@ -76,9 +78,21 @@ module RuboCop
|
|
76
78
|
corrector.remove(compact_method_range)
|
77
79
|
end
|
78
80
|
|
81
|
+
def map_method_and_compact_method_on_same_line?(compact_node)
|
82
|
+
return false unless compact_node.children.first.respond_to?(:send_node)
|
83
|
+
|
84
|
+
map_node = compact_node.children.first.send_node
|
85
|
+
|
86
|
+
compact_node.loc.selector.line == map_node.loc.selector.line
|
87
|
+
end
|
88
|
+
|
79
89
|
def invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
|
80
90
|
compact_node.loc.selector.line == chained_method.loc.selector.line
|
81
91
|
end
|
92
|
+
|
93
|
+
def compact_method_with_final_newline_range(compact_method_range)
|
94
|
+
range_by_whole_lines(compact_method_range, include_final_newline: true)
|
95
|
+
end
|
82
96
|
end
|
83
97
|
end
|
84
98
|
end
|
@@ -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
|
|
@@ -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)
|
@@ -82,14 +82,10 @@ module RuboCop
|
|
82
82
|
|
83
83
|
def build_good_method(method, args)
|
84
84
|
case method
|
85
|
-
when :
|
85
|
+
when :slice
|
86
86
|
"[#{build_call_args(args)}].chars"
|
87
|
-
when :first
|
88
|
-
|
89
|
-
"[0...#{args.first.source}].chars"
|
90
|
-
else
|
91
|
-
'[0]'
|
92
|
-
end
|
87
|
+
when :[], :first
|
88
|
+
build_good_method_for_brackets_or_first_method(method, args)
|
93
89
|
when :take
|
94
90
|
"[0...#{args.first.source}].chars"
|
95
91
|
else
|
@@ -97,6 +93,18 @@ module RuboCop
|
|
97
93
|
end
|
98
94
|
end
|
99
95
|
|
96
|
+
def build_good_method_for_brackets_or_first_method(method, args)
|
97
|
+
first_arg = args.first
|
98
|
+
|
99
|
+
if first_arg&.range_type?
|
100
|
+
"[#{build_call_args(args)}].chars"
|
101
|
+
elsif method == :first && args.any?
|
102
|
+
"[0...#{args.first.source}].chars"
|
103
|
+
else
|
104
|
+
first_arg ? "[#{first_arg.source}]" : '[0]'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
100
108
|
def build_bad_method(method, args)
|
101
109
|
case method
|
102
110
|
when :[]
|
@@ -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/)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop identifies places where string identifier argument can be replaced
|
7
|
+
# by symbol identifier argument.
|
8
|
+
# It prevents the redundancy of the internal string-to-symbol conversion.
|
9
|
+
#
|
10
|
+
# This cop targets methods that take identifier (e.g. method name) argument
|
11
|
+
# and the following examples are parts of it.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# send('do_something')
|
17
|
+
# attr_accessor 'do_something'
|
18
|
+
# instance_variable_get('@ivar')
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# send(:do_something)
|
22
|
+
# attr_accessor :do_something
|
23
|
+
# instance_variable_get(:@ivar)
|
24
|
+
#
|
25
|
+
class StringIdentifierArgument < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
MSG = 'Use `%<symbol_arg>s` instead of `%<string_arg>s`.'
|
29
|
+
|
30
|
+
# NOTE: `attr` method is not included in this list as it can cause false positives in Nokogiri API.
|
31
|
+
# And `attr` may not be used because `Style/Attr` registers an offense.
|
32
|
+
# https://github.com/rubocop/rubocop-performance/issues/278
|
33
|
+
RESTRICT_ON_SEND = %i[
|
34
|
+
alias_method attr_accessor attr_reader attr_writer autoload autoload?
|
35
|
+
class_variable_defined? const_defined? const_get const_set const_source_location
|
36
|
+
define_method instance_method method_defined? private_class_method? private_method_defined?
|
37
|
+
protected_method_defined? public_class_method public_instance_method public_method_defined?
|
38
|
+
remove_class_variable remove_method undef_method class_variable_get class_variable_set
|
39
|
+
deprecate_constant module_function private private_constant protected public public_constant
|
40
|
+
remove_const ruby2_keywords
|
41
|
+
define_singleton_method instance_variable_defined instance_variable_get instance_variable_set
|
42
|
+
method public_method public_send remove_instance_variable respond_to? send singleton_method
|
43
|
+
__send__
|
44
|
+
].freeze
|
45
|
+
|
46
|
+
def on_send(node)
|
47
|
+
return unless (first_argument = node.first_argument)
|
48
|
+
return unless first_argument.str_type?
|
49
|
+
return if first_argument.value.include?(' ')
|
50
|
+
|
51
|
+
replacement = first_argument.value.to_sym.inspect
|
52
|
+
|
53
|
+
message = format(MSG, symbol_arg: replacement, string_arg: first_argument.source)
|
54
|
+
|
55
|
+
add_offense(first_argument, message: message) do |corrector|
|
56
|
+
corrector.replace(first_argument, replacement)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -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
|
@@ -6,35 +6,46 @@ module RuboCop
|
|
6
6
|
# This cop identifies places where custom code finding the sum of elements
|
7
7
|
# in some Enumerable object can be replaced by `Enumerable#sum` method.
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# Its auto-correction is marked as safe by default (`SafeAutoCorrect: true`)
|
12
|
-
# to prevent `TypeError` in auto-correced code when initial value is not
|
13
|
-
# specified as shown below:
|
9
|
+
# @safety
|
10
|
+
# Auto-corrections are unproblematic wherever an initial value is provided explicitly:
|
14
11
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
12
|
+
# [source,ruby]
|
13
|
+
# ----
|
14
|
+
# [1, 2, 3].reduce(4, :+) # => 10
|
15
|
+
# [1, 2, 3].sum(4) # => 10
|
19
16
|
#
|
20
|
-
#
|
17
|
+
# [].reduce(4, :+) # => 4
|
18
|
+
# [].sum(4) # => 4
|
19
|
+
# ----
|
21
20
|
#
|
22
|
-
#
|
21
|
+
# This also holds true for non-numeric types which implement a `:+` method:
|
23
22
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
23
|
+
# [source,ruby]
|
24
|
+
# ----
|
25
|
+
# ['l', 'o'].reduce('Hel', :+) # => "Hello"
|
26
|
+
# ['l', 'o'].sum('Hel') # => "Hello"
|
27
|
+
# ----
|
29
28
|
#
|
30
|
-
#
|
31
|
-
#
|
29
|
+
# When no initial value is provided though, `Enumerable#reduce` will pick the first enumerated value
|
30
|
+
# as initial value and successively add all following values to it, whereas
|
31
|
+
# `Enumerable#sum` will set an initial value of `0` (`Integer`) which can lead to a `TypeError`:
|
32
32
|
#
|
33
|
-
#
|
33
|
+
# [source,ruby]
|
34
|
+
# ----
|
35
|
+
# [].reduce(:+) # => nil
|
36
|
+
# [1, 2, 3].reduce(:+) # => 6
|
37
|
+
# ['H', 'e', 'l', 'l', 'o'].reduce(:+) # => "Hello"
|
38
|
+
#
|
39
|
+
# [].sum # => 0
|
40
|
+
# [1, 2, 3].sum # => 6
|
41
|
+
# ['H', 'e', 'l', 'l', 'o'].sum # => in `+': String can't be coerced into Integer (TypeError)
|
42
|
+
# ----
|
43
|
+
#
|
44
|
+
# @example OnlySumOrWithInitialValue: false (default)
|
34
45
|
# # bad
|
35
|
-
# [1, 2, 3].inject(:+) #
|
36
|
-
# [1, 2, 3].inject(&:+) # will
|
37
|
-
# [1, 2, 3].reduce { |acc, elem| acc + elem } #
|
46
|
+
# [1, 2, 3].inject(:+) # Auto-corrections for cases without initial value are unsafe
|
47
|
+
# [1, 2, 3].inject(&:+) # and will only be performed when using the `-A` option.
|
48
|
+
# [1, 2, 3].reduce { |acc, elem| acc + elem } # They can be prohibited completely using `SafeAutoCorrect: true`.
|
38
49
|
# [1, 2, 3].reduce(10, :+)
|
39
50
|
# [1, 2, 3].map { |elem| elem ** 2 }.sum
|
40
51
|
# [1, 2, 3].collect(&:count).sum(10)
|
@@ -45,6 +56,17 @@ module RuboCop
|
|
45
56
|
# [1, 2, 3].sum { |elem| elem ** 2 }
|
46
57
|
# [1, 2, 3].sum(10, &:count)
|
47
58
|
#
|
59
|
+
# @example OnlySumOrWithInitialValue: true
|
60
|
+
# # bad
|
61
|
+
# [1, 2, 3].reduce(10, :+)
|
62
|
+
# [1, 2, 3].map { |elem| elem ** 2 }.sum
|
63
|
+
# [1, 2, 3].collect(&:count).sum(10)
|
64
|
+
#
|
65
|
+
# # good
|
66
|
+
# [1, 2, 3].sum(10)
|
67
|
+
# [1, 2, 3].sum { |elem| elem ** 2 }
|
68
|
+
# [1, 2, 3].sum(10, &:count)
|
69
|
+
#
|
48
70
|
class Sum < Base
|
49
71
|
include RangeHelp
|
50
72
|
extend AutoCorrector
|
@@ -103,6 +125,8 @@ module RuboCop
|
|
103
125
|
|
104
126
|
def handle_sum_candidate(node)
|
105
127
|
sum_candidate?(node) do |method, init, operation|
|
128
|
+
next if cop_config['OnlySumOrWithInitialValue'] && init.empty?
|
129
|
+
|
106
130
|
range = sum_method_range(node)
|
107
131
|
message = build_method_message(node, method, init, operation)
|
108
132
|
|
@@ -156,7 +180,7 @@ module RuboCop
|
|
156
180
|
end
|
157
181
|
|
158
182
|
def sum_method_range(node)
|
159
|
-
range_between(node.loc.selector.begin_pos, node.loc.
|
183
|
+
range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
|
160
184
|
end
|
161
185
|
|
162
186
|
def sum_map_range(map, sum)
|
@@ -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
|
@@ -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'
|
@@ -43,6 +44,7 @@ require_relative 'performance/size'
|
|
43
44
|
require_relative 'performance/sort_reverse'
|
44
45
|
require_relative 'performance/squeeze'
|
45
46
|
require_relative 'performance/start_with'
|
47
|
+
require_relative 'performance/string_identifier_argument'
|
46
48
|
require_relative 'performance/string_include'
|
47
49
|
require_relative 'performance/string_replacement'
|
48
50
|
require_relative 'performance/sum'
|
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.13.2
|
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: 2022-01-16 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
|
@@ -104,6 +105,7 @@ files:
|
|
104
105
|
- lib/rubocop/cop/performance/sort_reverse.rb
|
105
106
|
- lib/rubocop/cop/performance/squeeze.rb
|
106
107
|
- lib/rubocop/cop/performance/start_with.rb
|
108
|
+
- lib/rubocop/cop/performance/string_identifier_argument.rb
|
107
109
|
- lib/rubocop/cop/performance/string_include.rb
|
108
110
|
- lib/rubocop/cop/performance/string_replacement.rb
|
109
111
|
- lib/rubocop/cop/performance/sum.rb
|
@@ -121,8 +123,9 @@ metadata:
|
|
121
123
|
homepage_uri: https://docs.rubocop.org/rubocop-performance/
|
122
124
|
changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
|
123
125
|
source_code_uri: https://github.com/rubocop/rubocop-performance/
|
124
|
-
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.
|
126
|
+
documentation_uri: https://docs.rubocop.org/rubocop-performance/1.13/
|
125
127
|
bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
|
128
|
+
rubygems_mfa_required: 'true'
|
126
129
|
post_install_message:
|
127
130
|
rdoc_options: []
|
128
131
|
require_paths:
|
@@ -138,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
141
|
- !ruby/object:Gem::Version
|
139
142
|
version: '0'
|
140
143
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
144
|
+
rubygems_version: 3.3.3
|
142
145
|
signing_key:
|
143
146
|
specification_version: 4
|
144
147
|
summary: Automatic performance checking tool for Ruby code.
|