rubocop-performance 1.11.3 → 1.13.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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +25 -8
  3. data/lib/rubocop/cop/performance/ancestors_include.rb +4 -0
  4. data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +8 -6
  5. data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +23 -12
  6. data/lib/rubocop/cop/performance/case_when_splat.rb +11 -13
  7. data/lib/rubocop/cop/performance/casecmp.rb +4 -2
  8. data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +1 -1
  9. data/lib/rubocop/cop/performance/concurrent_monotonic_time.rb +42 -0
  10. data/lib/rubocop/cop/performance/count.rb +22 -13
  11. data/lib/rubocop/cop/performance/delete_prefix.rb +4 -4
  12. data/lib/rubocop/cop/performance/delete_suffix.rb +4 -4
  13. data/lib/rubocop/cop/performance/detect.rb +10 -13
  14. data/lib/rubocop/cop/performance/double_start_end_with.rb +21 -0
  15. data/lib/rubocop/cop/performance/end_with.rb +5 -0
  16. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +3 -0
  17. data/lib/rubocop/cop/performance/map_compact.rb +24 -9
  18. data/lib/rubocop/cop/performance/open_struct.rb +4 -0
  19. data/lib/rubocop/cop/performance/range_include.rb +3 -2
  20. data/lib/rubocop/cop/performance/redundant_block_call.rb +1 -0
  21. data/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb +20 -7
  22. data/lib/rubocop/cop/performance/redundant_merge.rb +4 -3
  23. data/lib/rubocop/cop/performance/redundant_string_chars.rb +22 -24
  24. data/lib/rubocop/cop/performance/regexp_match.rb +1 -2
  25. data/lib/rubocop/cop/performance/start_with.rb +5 -0
  26. data/lib/rubocop/cop/performance/string_identifier_argument.rb +59 -0
  27. data/lib/rubocop/cop/performance/string_include.rb +2 -1
  28. data/lib/rubocop/cop/performance/sum.rb +47 -23
  29. data/lib/rubocop/cop/performance/times_map.rb +12 -0
  30. data/lib/rubocop/cop/performance/unfreeze_string.rb +9 -6
  31. data/lib/rubocop/cop/performance_cops.rb +2 -0
  32. data/lib/rubocop/performance/version.rb +1 -1
  33. metadata +7 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 341ace76835db65803b9c7ef7d54f67dbb053c86c9e31b0a80b80f1514e96c29
4
- data.tar.gz: 031bda91d5c5d1e66716f218472621c115cf247e364c25596c6fd9f470261aca
3
+ metadata.gz: 874ce36b942ed539ead8c3329a7dd6831224459a286c2b3189605775e725fc60
4
+ data.tar.gz: 584a851432d98e548151baa8afc1f9a30d5dcca05f8eae0d86c68f17bf933f34
5
5
  SHA512:
6
- metadata.gz: 3c324e059ffa5f0f98789d6336a41ab0135bdf1dcc8e3b45df83ac8bf75e7bae53fe1e40fb7ae0039d83567bd226709b47cd9cc09184819d16ce8c558d56d85e
7
- data.tar.gz: a7c1698db1e6c9c16150f46df944c3f275c38c0f39bca1bc5f0961bdde6a1d14aa9acb9b19823b9f62f352a11120596559fd9cdef6e3343fd8e01bf71b816f96
6
+ metadata.gz: 102cccbb3be2ba55702a2e7aff3c56c6325c80481d269f87921ca1d16a79fa12830c6f080f49bacdebf4b5726e4f4c42af2527c13a4abac5aae0cf4544fb018e
7
+ data.tar.gz: 23c8beebceef175caf7e226a136bb3eaff500b71f5e3e26cba9fee9a84e36aa7a3b315b11216844b7980a421a82fff7a5346560ef1418f58fbe5261599fe4dec
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 argument to string before passing to BigDecimal.'
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: '0.59'
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
@@ -96,14 +101,18 @@ Performance/Count:
96
101
  Performance/DeletePrefix:
97
102
  Description: 'Use `delete_prefix` instead of `gsub`.'
98
103
  Enabled: true
104
+ Safe: false
99
105
  SafeMultiline: true
100
106
  VersionAdded: '1.6'
107
+ VersionChanged: '1.11'
101
108
 
102
109
  Performance/DeleteSuffix:
103
110
  Description: 'Use `delete_suffix` instead of `gsub`.'
104
111
  Enabled: true
112
+ Safe: false
105
113
  SafeMultiline: true
106
114
  VersionAdded: '1.6'
115
+ VersionChanged: '1.11'
107
116
 
108
117
  Performance/Detect:
109
118
  Description: >-
@@ -127,7 +136,7 @@ Performance/DoubleStartEndWith:
127
136
  VersionAdded: '0.36'
128
137
  VersionChanged: '0.48'
129
138
  # Used to check for `starts_with?` and `ends_with?`.
130
- # These methods are defined by `ActiveSupport`.
139
+ # These methods are defined by Active Support.
131
140
  IncludeActiveSupportAliases: false
132
141
 
133
142
  Performance/EndWith:
@@ -302,12 +311,17 @@ Performance/StartWith:
302
311
  VersionAdded: '0.36'
303
312
  VersionChanged: '1.10'
304
313
 
314
+ Performance/StringIdentifierArgument:
315
+ Description: 'Use symbol identifier argument instead of string identifier argument.'
316
+ Enabled: pending
317
+ VersionAdded: '1.13'
318
+
305
319
  Performance/StringInclude:
306
320
  Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
307
321
  Enabled: 'pending'
308
- AutoCorrect: false
309
322
  SafeAutoCorrect: false
310
323
  VersionAdded: '1.7'
324
+ VersionChanged: '1.12'
311
325
 
312
326
  Performance/StringReplacement:
313
327
  Description: >-
@@ -320,17 +334,20 @@ Performance/StringReplacement:
320
334
 
321
335
  Performance/Sum:
322
336
  Description: 'Use `sum` instead of a custom array summation.'
337
+ SafeAutoCorrect: false
323
338
  Reference: 'https://blog.bigbinary.com/2016/11/02/ruby-2-4-introduces-enumerable-sum.html'
324
339
  Enabled: 'pending'
325
340
  VersionAdded: '1.8'
341
+ VersionChanged: '1.13'
342
+ OnlySumOrWithInitialValue: false
326
343
 
327
344
  Performance/TimesMap:
328
345
  Description: 'Checks for .times.map calls.'
329
- AutoCorrect: false
330
346
  Enabled: true
347
+ # See https://github.com/rubocop/rubocop/issues/4658
348
+ SafeAutoCorrect: false
331
349
  VersionAdded: '0.36'
332
- VersionChanged: '0.50'
333
- SafeAutoCorrect: false # see https://github.com/rubocop/rubocop/issues/4658
350
+ VersionChanged: '1.13'
334
351
 
335
352
  Performance/UnfreezeString:
336
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,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
- # This cop is also unsafe for string slices because strings do not have `#take` and `#drop` methods.
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
- # # array[..2]
15
- # # array[...2]
16
- # # array[2..]
17
- # # array[2...]
18
- # # array.slice(..2)
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)
@@ -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 argument to string before passing to `BigDecimal`.'
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
- return unless (numeric = big_decimal_with_numeric_argument?(node))
31
- return if numeric.float_type? && specifies_precision?(node)
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
- add_offense(numeric.source_range) do |corrector|
34
- corrector.wrap(numeric, "'", "'")
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
@@ -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
- # This is not a guaranteed performance improvement. If the data being
21
- # processed by the `case` condition is normalized in a manner that favors
22
- # hitting a condition in the splat expansion, it is possible that
23
- # moving the splat condition to the end will use more memory,
24
- # and run slightly slower.
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
- 'of the `when` branches can improve performance.'
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
- # This cop is unsafe because `String#casecmp` and `String#casecmp?` behave
9
- # differently when using Non-ASCII characters.
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
- 'It is better to extract it into a local variable or a constant.'
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.blank?
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.blank?
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
@@ -22,23 +27,15 @@ 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
 
32
33
  CANDIDATE_METHODS = Set[:select, :find_all, :filter].freeze
33
34
 
34
- MSG = 'Use `%<prefer>s` instead of ' \
35
- '`%<first_method>s.%<second_method>s`.'
36
- REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of ' \
37
- '`%<first_method>s.%<second_method>s`.'
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]`.'
35
+ MSG = 'Use `%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
36
+ REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of `%<first_method>s.%<second_method>s`.'
37
+ INDEX_MSG = 'Use `%<prefer>s` instead of `%<first_method>s[%<index>i]`.'
38
+ INDEX_REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of `%<first_method>s[%<index>i]`.'
42
39
  RESTRICT_ON_SEND = %i[first last []].freeze
43
40
 
44
41
  def_node_matcher :detect_candidate?, <<~PATTERN
@@ -94,7 +91,7 @@ module RuboCop
94
91
  end
95
92
 
96
93
  def replacement(method, index)
97
- if method == :last || method == :[] && index == -1
94
+ if method == :last || (method == :[] && index == -1)
98
95
  "reverse.#{preferred_method}"
99
96
  else
100
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
- # It is marked as unsafe auto-correction by default because `map { ... }.compact`
10
- # that is not compatible with `filter_map`.
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,28 +58,41 @@ module RuboCop
56
58
 
57
59
  add_offense(range) do |corrector|
58
60
  corrector.replace(map_node.loc.selector, 'filter_map')
59
- corrector.remove(compact_loc.dot)
60
- corrector.remove(compact_method_range(node))
61
+ remove_compact_method(corrector, node, node.parent)
61
62
  end
62
63
  end
63
64
 
64
65
  private
65
66
 
66
- def compact_method_range(compact_node)
67
- chained_method = compact_node.parent
67
+ def remove_compact_method(corrector, compact_node, chained_method)
68
68
  compact_method_range = compact_node.loc.selector
69
69
 
70
- if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) &&
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) &&
71
72
  !invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
72
- range_by_whole_lines(compact_method_range, include_final_newline: true)
73
+ compact_method_range = compact_method_with_final_newline_range(compact_method_range)
73
74
  else
74
- compact_method_range
75
+ corrector.remove(compact_node.loc.dot)
75
76
  end
77
+
78
+ corrector.remove(compact_method_range)
79
+ end
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
76
87
  end
77
88
 
78
89
  def invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
79
90
  compact_node.loc.selector.line == chained_method.loc.selector.line
80
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
81
96
  end
82
97
  end
83
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
- # This cop is `Safe: false` by default because `Range#include?` (or `Range#member?`) and
13
- # `Range#cover?` are not equivalent behaviour.
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
@@ -55,6 +55,7 @@ module RuboCop
55
55
  end
56
56
  end
57
57
  end
58
+ alias on_defs on_def
58
59
 
59
60
  private
60
61
 
@@ -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
- # Therefore, It is marked as unsafe by default because `===` and `==`
13
- # do not always behave the same.
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.source
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.source
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
- # This cop is marked as unsafe because RuboCop cannot determine if the
12
- # receiver of `merge!` is actually a hash or not.
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 last take drop length size empty?].freeze
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,32 +80,30 @@ 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
- when :[], :slice
85
+ when :slice
87
86
  "[#{build_call_args(args)}].chars"
88
- when :first
89
- if args.any?
90
- "[0...#{args.first.source}].chars"
91
- else
92
- '[0]'
93
- end
94
- when :last
95
- if args.any?
96
- "[-#{args.first.source}..-1].chars"
97
- else
98
- '[-1]'
99
- end
87
+ when :[], :first
88
+ build_good_method_for_brackets_or_first_method(method, args)
100
89
  when :take
101
90
  "[0...#{args.first.source}].chars"
102
- when :drop
103
- "[#{args.first.source}..-1].chars"
104
91
  else
105
92
  ".#{method}"
106
93
  end
107
94
  end
108
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
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
109
107
 
110
108
  def build_bad_method(method, args)
111
109
  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/)
@@ -0,0 +1,59 @@
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
+ RESTRICT_ON_SEND = %i[
31
+ alias_method attr attr_accessor attr_reader attr_writer autoload autoload?
32
+ class_variable_defined? const_defined? const_get const_set const_source_location
33
+ define_method instance_method method_defined? private_class_method? private_method_defined?
34
+ protected_method_defined? public_class_method public_instance_method public_method_defined?
35
+ remove_class_variable remove_method undef_method class_variable_get class_variable_set
36
+ deprecate_constant module_function private private_constant protected public public_constant
37
+ remove_const ruby2_keywords
38
+ define_singleton_method instance_variable_defined instance_variable_get instance_variable_set
39
+ method public_method public_send remove_instance_variable respond_to? send singleton_method
40
+ __send__
41
+ ].freeze
42
+
43
+ def on_send(node)
44
+ return unless (first_argument = node.first_argument)
45
+ return unless first_argument.str_type?
46
+ return if first_argument.value.include?(' ')
47
+
48
+ replacement = first_argument.value.to_sym.inspect
49
+
50
+ message = format(MSG, symbol_arg: replacement, string_arg: first_argument.source)
51
+
52
+ add_offense(first_argument, message: message) do |corrector|
53
+ corrector.replace(first_argument, replacement)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ 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
- # This cop's offenses are not safe to auto-correct if a receiver is nil.
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
- # This cop can change auto-correction scope depending on the value of
10
- # `SafeAutoCorrect`.
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
- # [source,ruby]
16
- # ----
17
- # ['a', 'b'].sum # => (String can't be coerced into Integer)
18
- # ----
12
+ # [source,ruby]
13
+ # ----
14
+ # [1, 2, 3].reduce(4, :+) # => 10
15
+ # [1, 2, 3].sum(4) # => 10
19
16
  #
20
- # Therefore if initial value is not specified, unsafe auto-corrected will not occur.
17
+ # [].reduce(4, :+) # => 4
18
+ # [].sum(4) # => 4
19
+ # ----
21
20
  #
22
- # If you always want to enable auto-correction, you can set `SafeAutoCorrect: false`.
21
+ # This also holds true for non-numeric types which implement a `:+` method:
23
22
  #
24
- # [source,yaml]
25
- # ----
26
- # Performance/Sum:
27
- # SafeAutoCorrect: false
28
- # ----
23
+ # [source,ruby]
24
+ # ----
25
+ # ['l', 'o'].reduce('Hel', :+) # => "Hello"
26
+ # ['l', 'o'].sum('Hel') # => "Hello"
27
+ # ----
29
28
  #
30
- # Please note that the auto-correction command line option will be changed from
31
- # `rubocop -a` to `rubocop -A`, which includes unsafe auto-correction.
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
- # @example
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(:+) # These bad cases with no initial value are unsafe and
36
- # [1, 2, 3].inject(&:+) # will not be auto-correced by default. If you want to
37
- # [1, 2, 3].reduce { |acc, elem| acc + elem } # auto-corrected, you can set `SafeAutoCorrect: false`.
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.end.end_pos)
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
- # NOTE: `String.new` (without operator) is not exactly the same as `+''`.
11
- # These differ in encoding. `String.new.encoding` is always `ASCII-8BIT`.
12
- # However, `(+'').encoding` is the same as script encoding(e.g. `UTF-8`).
13
- # Therefore, auto-correction is unsafe.
14
- # So, if you expect `ASCII-8BIT` encoding, disable this cop.
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
- corrector.replace(node, "+#{string_value(node)}")
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'
@@ -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'
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Performance
5
5
  # This module holds the RuboCop Performance version information.
6
6
  module Version
7
- STRING = '1.11.3'
7
+ STRING = '1.13.0'
8
8
 
9
9
  def self.document_version
10
10
  STRING.match('\d+\.\d+').to_s
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.11.3
4
+ version: 1.13.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-05-06 00:00:00.000000000 Z
13
+ date: 2021-12-25 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.11/
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.2.12
144
+ rubygems_version: 3.3.0
142
145
  signing_key:
143
146
  specification_version: 4
144
147
  summary: Automatic performance checking tool for Ruby code.