rubocop-performance 1.21.1 → 1.23.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd286ebd5cb0d982f759a355a86281898577db559004bef9bfb53b8493a32934
4
- data.tar.gz: f3e101a14918c3efa6dc657841471b22afec47d54ce70442567d54ffc3ee8ed5
3
+ metadata.gz: 332ca643753a81ff66c4a6050117f7a479bd3aaa3f186c361a596d06b16aa9b5
4
+ data.tar.gz: 2fb149f85f986d9d0302e6fbe4c7389f312bb93a15a93cec49ffd74495853c78
5
5
  SHA512:
6
- metadata.gz: 1d6df8e36cbb224d892f14e7fb1eeccf34c887c9fd6e9ad302889ab71b64e48db3c3167291f210ad7e69a23f5e4720ae23ee767c4a569701d09e8fa771ede28c
7
- data.tar.gz: 428da3a79195bcf8c715a1962c5bea38a08ee2973c0450b78fc24ceeb376a4f984b3d4f91efba93c799d28986dda22f711e90937738007abbd41b470a484a887
6
+ metadata.gz: e03b8e178f4cde75ef5d82aa7483da512f2816afd82c97b414a4bfcd7afacf589ebb033d6bed40d0968217ec0ff24cb69e2a6c4f28a52ecbdb31cef5599e5386
7
+ data.tar.gz: 410a72e5e85fe6cdc8002b51c8b185dc4d2a1dea5f3a5889c146364c2a20b5b50256c2a90fef59604137dd75d83f20c17ec65991eac6b8dab15e046184e1f006
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-23 Bozhidar Batsov
1
+ Copyright (c) 2012-25 Bozhidar Batsov
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/config/default.yml CHANGED
@@ -32,8 +32,11 @@ Performance/BindCall:
32
32
 
33
33
  Performance/BlockGivenWithExplicitBlock:
34
34
  Description: 'Check block argument explicitly instead of using `block_given?`.'
35
- Enabled: pending
35
+ # This cop was created due to a mistake in microbenchmark.
36
+ # https://github.com/rubocop/rubocop-performance/issues/385
37
+ Enabled: false
36
38
  VersionAdded: '1.9'
39
+ VersionChanged: '1.22'
37
40
 
38
41
  Performance/Caller:
39
42
  Description: >-
@@ -323,6 +326,12 @@ Performance/StartWith:
323
326
  VersionAdded: '0.36'
324
327
  VersionChanged: '1.10'
325
328
 
329
+ Performance/StringBytesize:
330
+ Description: "Use `String#bytesize` instead of calculating the size of the bytes array."
331
+ Safe: false
332
+ Enabled: 'pending'
333
+ VersionAdded: '1.23'
334
+
326
335
  Performance/StringIdentifierArgument:
327
336
  Description: 'Use symbol identifier argument instead of string identifier argument.'
328
337
  Enabled: pending
@@ -3,50 +3,74 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # Identifies places where numeric argument to BigDecimal should be
7
- # converted to string. Initializing from String is faster
8
- # than from Numeric for BigDecimal.
6
+ # Identifies places where a float argument to BigDecimal should be converted to a string.
7
+ # Initializing from String is faster than from Float for BigDecimal.
8
+ #
9
+ # Also identifies places where an integer string argument to BigDecimal should be converted to
10
+ # an integer. Initializing from Integer is faster than from String for BigDecimal.
9
11
  #
10
12
  # @example
11
13
  # # bad
12
- # BigDecimal(1, 2)
13
- # 4.to_d(6)
14
14
  # BigDecimal(1.2, 3, exception: true)
15
15
  # 4.5.to_d(6, exception: true)
16
16
  #
17
17
  # # good
18
- # BigDecimal('1', 2)
19
- # BigDecimal('4', 6)
20
18
  # BigDecimal('1.2', 3, exception: true)
21
19
  # BigDecimal('4.5', 6, exception: true)
22
20
  #
21
+ # # bad
22
+ # BigDecimal('1', 2)
23
+ # BigDecimal('4', 6)
24
+ #
25
+ # # good
26
+ # BigDecimal(1, 2)
27
+ # 4.to_d(6)
28
+ #
23
29
  class BigDecimalWithNumericArgument < Base
24
30
  extend AutoCorrector
31
+ extend TargetRubyVersion
32
+
33
+ minimum_target_ruby_version 3.1
25
34
 
26
- MSG = 'Convert numeric literal to string and pass it to `BigDecimal`.'
35
+ MSG_FROM_FLOAT_TO_STRING = 'Convert float literal to string and pass it to `BigDecimal`.'
36
+ MSG_FROM_INTEGER_TO_STRING = 'Convert string literal to integer and pass it to `BigDecimal`.'
27
37
  RESTRICT_ON_SEND = %i[BigDecimal to_d].freeze
28
38
 
29
- def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
30
- (send nil? :BigDecimal $numeric_type? ...)
39
+ def_node_matcher :big_decimal_with_numeric_argument, <<~PATTERN
40
+ (send nil? :BigDecimal ${float_type? str_type?} ...)
31
41
  PATTERN
32
42
 
33
- def_node_matcher :to_d?, <<~PATTERN
34
- (send [!nil? $numeric_type?] :to_d ...)
43
+ def_node_matcher :to_d, <<~PATTERN
44
+ (send [!nil? ${float_type? str_type?}] :to_d ...)
35
45
  PATTERN
36
46
 
47
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
37
48
  def on_send(node)
38
- if (numeric = big_decimal_with_numeric_argument?(node))
39
- add_offense(numeric.source_range) do |corrector|
40
- corrector.wrap(numeric, "'", "'")
49
+ if (numeric = big_decimal_with_numeric_argument(node))
50
+ if numeric.numeric_type?
51
+ add_offense(numeric, message: MSG_FROM_FLOAT_TO_STRING) do |corrector|
52
+ corrector.wrap(numeric, "'", "'")
53
+ end
54
+ elsif numeric.value.match?(/\A\d+\z/)
55
+ add_offense(numeric, message: MSG_FROM_INTEGER_TO_STRING) do |corrector|
56
+ corrector.replace(numeric, numeric.value)
57
+ end
41
58
  end
42
- elsif (numeric_to_d = to_d?(node))
43
- add_offense(numeric_to_d.source_range) do |corrector|
44
- big_decimal_args = node.arguments.map(&:source).unshift("'#{numeric_to_d.source}'").join(', ')
59
+ elsif (numeric_to_d = to_d(node))
60
+ if numeric_to_d.numeric_type?
61
+ add_offense(numeric_to_d, message: MSG_FROM_FLOAT_TO_STRING) do |corrector|
62
+ big_decimal_args = node.arguments.map(&:source).unshift("'#{numeric_to_d.source}'").join(', ')
45
63
 
46
- corrector.replace(node, "BigDecimal(#{big_decimal_args})")
64
+ corrector.replace(node, "BigDecimal(#{big_decimal_args})")
65
+ end
66
+ elsif numeric_to_d.value.match?(/\A\d+\z/)
67
+ add_offense(numeric_to_d, message: MSG_FROM_INTEGER_TO_STRING) do |corrector|
68
+ corrector.replace(node, "#{numeric_to_d.value}.to_d")
69
+ end
47
70
  end
48
71
  end
49
72
  end
73
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
50
74
  end
51
75
  end
52
76
  end
@@ -6,6 +6,9 @@ module RuboCop
6
6
  # Identifies unnecessary use of a `block_given?` where explicit check
7
7
  # of block argument would suffice.
8
8
  #
9
+ # NOTE: This cop produces code with significantly worse performance when a
10
+ # block is being passed to the method and as such should not be enabled.
11
+ #
9
12
  # @example
10
13
  # # bad
11
14
  # def method(&block)
@@ -18,14 +18,14 @@ module RuboCop
18
18
  #
19
19
  # [source,ruby]
20
20
  # ----
21
- # `Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size`
21
+ # Model.where(id: [1, 2, 3]).select { |m| m.method == true }.size
22
22
  # ----
23
23
  #
24
24
  # becomes:
25
25
  #
26
26
  # [source,ruby]
27
27
  # ----
28
- # `Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }`
28
+ # Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }
29
29
  # ----
30
30
  #
31
31
  # @example
@@ -41,7 +41,7 @@ module RuboCop
41
41
  class DoubleStartEndWith < Base
42
42
  extend AutoCorrector
43
43
 
44
- MSG = 'Use `%<receiver>s.%<method>s(%<combined_args>s)` instead of `%<original_code>s`.'
44
+ MSG = 'Use `%<replacement>s` instead of `%<original_code>s`.'
45
45
 
46
46
  def on_or(node)
47
47
  receiver, method, first_call_args, second_call_args = process_source(node)
@@ -50,7 +50,7 @@ module RuboCop
50
50
 
51
51
  combined_args = combine_args(first_call_args, second_call_args)
52
52
 
53
- add_offense(node, message: message(node, receiver, method, combined_args)) do |corrector|
53
+ add_offense(node, message: message(node, receiver, first_call_args, method, combined_args)) do |corrector|
54
54
  autocorrect(corrector, first_call_args, second_call_args, combined_args)
55
55
  end
56
56
  end
@@ -73,10 +73,10 @@ module RuboCop
73
73
  end
74
74
  end
75
75
 
76
- def message(node, receiver, method, combined_args)
77
- format(
78
- MSG, receiver: receiver.source, method: method, combined_args: combined_args, original_code: node.source
79
- )
76
+ def message(node, receiver, first_call_args, method, combined_args)
77
+ dot = first_call_args.first.parent.send_type? ? '.' : '&.'
78
+ replacement = "#{receiver.source}#{dot}#{method}(#{combined_args})"
79
+ format(MSG, replacement: replacement, original_code: node.source)
80
80
  end
81
81
 
82
82
  def combine_args(first_call_args, second_call_args)
@@ -89,16 +89,16 @@ module RuboCop
89
89
 
90
90
  def_node_matcher :two_start_end_with_calls, <<~PATTERN
91
91
  (or
92
- (send $_recv [{:start_with? :end_with?} $_method] $...)
93
- (send _recv _method $...))
92
+ (call $_recv [{:start_with? :end_with?} $_method] $...)
93
+ (call _recv _method $...))
94
94
  PATTERN
95
95
 
96
96
  def_node_matcher :check_with_active_support_aliases, <<~PATTERN
97
97
  (or
98
- (send $_recv
98
+ (call $_recv
99
99
  [{:start_with? :starts_with? :end_with? :ends_with?} $_method]
100
100
  $...)
101
- (send _recv _method $...))
101
+ (call _recv _method $...))
102
102
  PATTERN
103
103
  end
104
104
  end
@@ -72,7 +72,7 @@ module RuboCop
72
72
 
73
73
  def requires_parentheses?(arg)
74
74
  return true if arg.if_type? && arg.ternary?
75
- return true if arg.and_type? || arg.or_type? || arg.range_type?
75
+ return true if arg.operator_keyword? || arg.range_type?
76
76
 
77
77
  call_like?(arg) && requires_parentheses_for_call_like?(arg)
78
78
  end
@@ -130,9 +130,7 @@ module RuboCop
130
130
  end
131
131
 
132
132
  def rewrite_with_modifier(node, parent, new_source)
133
- # FIXME: `|| 2` can be removed when support is limited to RuboCop 1.44 or higher.
134
- # https://github.com/rubocop/rubocop/commit/02d1e5b
135
- indent = ' ' * (configured_indentation_width || 2)
133
+ indent = ' ' * configured_indentation_width
136
134
  padding = "\n#{indent + leading_spaces(node)}"
137
135
  new_source.gsub!("\n", padding)
138
136
 
@@ -48,7 +48,7 @@ module RuboCop
48
48
  RESTRICT_ON_SEND = %i[[] slice first last take length size empty?].freeze
49
49
 
50
50
  def_node_matcher :redundant_chars_call?, <<~PATTERN
51
- (send $(send _ :chars) $_ $...)
51
+ (send $(send !nil? :chars) $_ $...)
52
52
  PATTERN
53
53
 
54
54
  def on_send(node)
@@ -46,7 +46,11 @@ module RuboCop
46
46
  message = format(MSG, current: bad_method, prefer: good_method)
47
47
 
48
48
  add_offense(node.loc.selector, message: message) do |corrector|
49
- string_literal = to_string_literal(replace_str)
49
+ # FIXME: When requiring only RuboCop 1.70.0 and above,
50
+ # `dup` in `replace_str.dup` becomes unnecessary, as
51
+ # frozen strings are handled in the `to_string_literal`
52
+ # implementation. Please remove it.
53
+ string_literal = to_string_literal(replace_str.dup)
50
54
  new_code = "#{receiver.source}#{node.loc.dot.source}#{good_method}(#{string_literal})"
51
55
 
52
56
  corrector.replace(node, new_code)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # Checks for calls to `#bytes` counting method and suggests using `bytesize` instead.
7
+ # The `bytesize` method is more efficient and directly returns the size in bytes,
8
+ # avoiding the intermediate array allocation that `bytes.size` incurs.
9
+ #
10
+ # @safety
11
+ # This cop is unsafe because it assumes that the receiver
12
+ # responds to `#bytesize` method.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # string_var.bytes.count
17
+ # "foobar".bytes.size
18
+ #
19
+ # # good
20
+ # string_var.bytesize
21
+ # "foobar".bytesize
22
+ class StringBytesize < Base
23
+ extend AutoCorrector
24
+
25
+ MSG = 'Use `String#bytesize` instead of calculating the size of the bytes array.'
26
+ RESTRICT_ON_SEND = %i[size length count].freeze
27
+
28
+ def_node_matcher :string_bytes_method?, <<~MATCHER
29
+ (call (call !{nil? int} :bytes) {:size :length :count})
30
+ MATCHER
31
+
32
+ def on_send(node)
33
+ string_bytes_method?(node) do
34
+ range = node.receiver.loc.selector.begin.join(node.source_range.end)
35
+
36
+ add_offense(range) do |corrector|
37
+ corrector.replace(range, 'bytesize')
38
+ end
39
+ end
40
+ end
41
+ alias on_csend on_send
42
+ end
43
+ end
44
+ end
45
+ end
@@ -159,7 +159,7 @@ module RuboCop
159
159
 
160
160
  def array_literal?(node)
161
161
  receiver = node.children.first
162
- receiver&.literal? && receiver&.array_type?
162
+ receiver&.literal? && receiver.array_type?
163
163
  end
164
164
 
165
165
  def autocorrect(corrector, init, range)
@@ -44,6 +44,7 @@ require_relative 'performance/select_map'
44
44
  require_relative 'performance/size'
45
45
  require_relative 'performance/sort_reverse'
46
46
  require_relative 'performance/squeeze'
47
+ require_relative 'performance/string_bytesize'
47
48
  require_relative 'performance/start_with'
48
49
  require_relative 'performance/string_identifier_argument'
49
50
  require_relative 'performance/string_include'
@@ -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.21.1'
7
+ STRING = '1.23.1'
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.21.1
4
+ version: 1.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -9,7 +9,7 @@ authors:
9
9
  - Yuji Nakayama
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-06-16 00:00:00.000000000 Z
12
+ date: 2025-01-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rubocop
@@ -111,6 +111,7 @@ files:
111
111
  - lib/rubocop/cop/performance/sort_reverse.rb
112
112
  - lib/rubocop/cop/performance/squeeze.rb
113
113
  - lib/rubocop/cop/performance/start_with.rb
114
+ - lib/rubocop/cop/performance/string_bytesize.rb
114
115
  - lib/rubocop/cop/performance/string_identifier_argument.rb
115
116
  - lib/rubocop/cop/performance/string_include.rb
116
117
  - lib/rubocop/cop/performance/string_replacement.rb
@@ -129,7 +130,7 @@ metadata:
129
130
  homepage_uri: https://docs.rubocop.org/rubocop-performance/
130
131
  changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
131
132
  source_code_uri: https://github.com/rubocop/rubocop-performance/
132
- documentation_uri: https://docs.rubocop.org/rubocop-performance/1.21/
133
+ documentation_uri: https://docs.rubocop.org/rubocop-performance/1.23/
133
134
  bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
134
135
  rubygems_mfa_required: 'true'
135
136
  rdoc_options: []
@@ -146,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
147
  - !ruby/object:Gem::Version
147
148
  version: '0'
148
149
  requirements: []
149
- rubygems_version: 3.6.0.dev
150
+ rubygems_version: 3.6.1
150
151
  specification_version: 4
151
152
  summary: Automatic performance checking tool for Ruby code.
152
153
  test_files: []