rubocop-performance 1.23.1 → 1.24.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 332ca643753a81ff66c4a6050117f7a479bd3aaa3f186c361a596d06b16aa9b5
4
- data.tar.gz: 2fb149f85f986d9d0302e6fbe4c7389f312bb93a15a93cec49ffd74495853c78
3
+ metadata.gz: 1b4cdc2536f76691be677a1e203a886fae5e170f550424bed14d579f39a87e75
4
+ data.tar.gz: 6ea02935a50fcdeb0b07d1a5d67c4414c71115019cb02dae4746c207f798cad6
5
5
  SHA512:
6
- metadata.gz: e03b8e178f4cde75ef5d82aa7483da512f2816afd82c97b414a4bfcd7afacf589ebb033d6bed40d0968217ec0ff24cb69e2a6c4f28a52ecbdb31cef5599e5386
7
- data.tar.gz: 410a72e5e85fe6cdc8002b51c8b185dc4d2a1dea5f3a5889c146364c2a20b5b50256c2a90fef59604137dd75d83f20c17ec65991eac6b8dab15e046184e1f006
6
+ metadata.gz: 7bc4f69ef0a5ca779626b29d0a7c5333bf135b29d06d1be009acd4e9ffaa368873cb9977a94e9c5d5f50cb1c000d9fa243b8557badbab00756469a0b6a366662
7
+ data.tar.gz: 47e7f03cf61d57a3f9bd8e3cdb79f722fdaa279d300d2de5532435c1231fa06c28b1a148ab31c7b62775d1449a284fc43cee4bd36bbd16b1065145f022c8f729
data/README.md CHANGED
@@ -30,13 +30,13 @@ ways to do this:
30
30
  Put this into your `.rubocop.yml`.
31
31
 
32
32
  ```yaml
33
- require: rubocop-performance
33
+ plugins: rubocop-performance
34
34
  ```
35
35
 
36
36
  Alternatively, use the following array notation when specifying multiple extensions.
37
37
 
38
38
  ```yaml
39
- require:
39
+ plugins:
40
40
  - rubocop-other-extension
41
41
  - rubocop-performance
42
42
  ```
@@ -44,10 +44,13 @@ require:
44
44
  Now you can run `rubocop` and it will automatically load the RuboCop Performance
45
45
  cops together with the standard cops.
46
46
 
47
+ > [!NOTE]
48
+ > The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
49
+
47
50
  ### Command line
48
51
 
49
52
  ```sh
50
- $ rubocop --require rubocop-performance
53
+ $ rubocop --plugin rubocop-performance
51
54
  ```
52
55
 
53
56
  ### Rake task
@@ -56,7 +59,7 @@ $ rubocop --require rubocop-performance
56
59
  require 'rubocop/rake_task'
57
60
 
58
61
  RuboCop::RakeTask.new do |task|
59
- task.requires << 'rubocop-performance'
62
+ task.plugins << 'rubocop-performance'
60
63
  end
61
64
  ```
62
65
 
data/config/default.yml CHANGED
@@ -381,3 +381,9 @@ Performance/UriDefaultParser:
381
381
  Description: 'Use `URI::DEFAULT_PARSER` instead of `URI::Parser.new`.'
382
382
  Enabled: true
383
383
  VersionAdded: '0.50'
384
+
385
+ Performance/ZipWithoutBlock:
386
+ Description: 'Checks for `map { |id| [id] }` and suggests replacing it with `zip`.'
387
+ Enabled: pending
388
+ Safe: false
389
+ VersionAdded: '1.24'
@@ -44,8 +44,8 @@ module RuboCop
44
44
 
45
45
  def_node_matcher :endless_range?, <<~PATTERN
46
46
  {
47
- ({irange erange} nil? (int positive?))
48
- ({irange erange} (int positive?) nil?)
47
+ (range nil? (int positive?))
48
+ (range (int positive?) nil?)
49
49
  }
50
50
  PATTERN
51
51
 
@@ -58,6 +58,7 @@ module RuboCop
58
58
  class CaseWhenSplat < Base
59
59
  include Alignment
60
60
  include RangeHelp
61
+ include CommentsHelp
61
62
  extend AutoCorrector
62
63
 
63
64
  MSG = 'Reordering `when` conditions with a splat to the end of the `when` branches can improve performance.'
@@ -116,11 +117,18 @@ module RuboCop
116
117
  def reordering_correction(when_node)
117
118
  new_condition = replacement(when_node.conditions)
118
119
 
119
- if same_line?(when_node, when_node.body)
120
- new_condition_with_then(when_node, new_condition)
121
- else
122
- new_branch_without_then(when_node, new_condition)
123
- end
120
+ condition =
121
+ if same_line?(when_node, when_node.body)
122
+ new_condition_with_then(when_node, new_condition)
123
+ else
124
+ new_branch_without_then(when_node, new_condition)
125
+ end
126
+
127
+ condition_comments = comments_in_range(when_node).map do |comment_node|
128
+ "#{indent_for(comment_node)}#{comment_node.source}"
129
+ end.join("\n")
130
+
131
+ "#{condition}#{condition_comments}"
124
132
  end
125
133
 
126
134
  def when_branch_range(when_node)
@@ -134,7 +142,13 @@ module RuboCop
134
142
  end
135
143
 
136
144
  def new_branch_without_then(node, new_condition)
137
- "\n#{indent_for(node)}when #{new_condition}\n#{indent_for(node.body)}#{node.body.source}"
145
+ new_branch = "\n#{indent_for(node)}when #{new_condition}\n"
146
+
147
+ if node.body
148
+ "#{new_branch}#{indent_for(node.body)}#{node.body.source}"
149
+ else
150
+ new_branch
151
+ end
138
152
  end
139
153
 
140
154
  def indent_for(node)
@@ -45,6 +45,8 @@ module RuboCop
45
45
 
46
46
  RETURNS_NEW_ARRAY = (ALWAYS_RETURNS_NEW_ARRAY + RETURNS_NEW_ARRAY_WHEN_NO_BLOCK).freeze
47
47
 
48
+ RESTRICT_ON_SEND = RETURNS_NEW_ARRAY
49
+
48
50
  MSG = 'Use unchained `%<method>s` and `%<second_method>s!` ' \
49
51
  '(followed by `return array` if required) instead of chaining ' \
50
52
  '`%<method>s...%<second_method>s`.'
@@ -52,7 +54,7 @@ module RuboCop
52
54
  def_node_matcher :chain_array_allocation?, <<~PATTERN
53
55
  (send {
54
56
  (send _ $%RETURN_NEW_ARRAY_WHEN_ARGS {int lvar ivar cvar gvar send})
55
- ({block numblock} (send _ $%ALWAYS_RETURNS_NEW_ARRAY) ...)
57
+ (any_block (send _ $%ALWAYS_RETURNS_NEW_ARRAY) ...)
56
58
  (send _ $%RETURNS_NEW_ARRAY ...)
57
59
  } $%HAS_MUTATION_ALTERNATIVE ...)
58
60
  PATTERN
@@ -73,7 +75,7 @@ module RuboCop
73
75
  def enumerable_select_method?(node)
74
76
  # NOTE: `QueryMethods#select` in Rails accepts positional arguments, whereas `Enumerable#select` does not.
75
77
  # This difference can be utilized to reduce the knowledge requirements related to `select`.
76
- (node.block_type? || node.numblock_type?) && node.send_node.arguments.empty?
78
+ node.any_block_type? && node.send_node.arguments.empty?
77
79
  end
78
80
  end
79
81
  end
@@ -65,6 +65,8 @@ module RuboCop
65
65
 
66
66
  HASH_METHODS = (ENUMERABLE_METHOD_NAMES | NONMUTATING_HASH_METHODS).to_set.freeze
67
67
 
68
+ RESTRICT_ON_SEND = ARRAY_METHODS + HASH_METHODS
69
+
68
70
  def_node_matcher :kernel_loop?, <<~PATTERN
69
71
  (block
70
72
  (send {nil? (const nil? :Kernel)} :loop)
@@ -75,7 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def allowed_parent?(node)
78
- node && (node.casgn_type? || node.block_type?)
78
+ node&.type?(:casgn, :block)
79
79
  end
80
80
 
81
81
  def contains_splat?(node)
@@ -38,7 +38,7 @@ module RuboCop
38
38
  # (We don't even catch it if the Range is in double parens)
39
39
 
40
40
  def_node_matcher :range_include, <<~PATTERN
41
- (call {irange erange (begin {irange erange})} ${:include? :member?} ...)
41
+ (call {range (begin range)} ${:include? :member?} ...)
42
42
  PATTERN
43
43
 
44
44
  def on_send(node)
@@ -84,7 +84,7 @@ module RuboCop
84
84
  end
85
85
 
86
86
  def call_like?(arg)
87
- arg.call_type? || arg.yield_type? || arg.super_type?
87
+ arg.type?(:call, :yield, :super)
88
88
  end
89
89
  end
90
90
  end
@@ -239,7 +239,7 @@ module RuboCop
239
239
 
240
240
  def scope_root(node)
241
241
  node.each_ancestor.find do |ancestor|
242
- ancestor.def_type? || ancestor.defs_type? || ancestor.class_type? || ancestor.module_type?
242
+ ancestor.type?(:def, :defs, :class, :module)
243
243
  end
244
244
  end
245
245
 
@@ -36,6 +36,13 @@ module RuboCop
36
36
  MESSAGE_ONLY_IF = 'only if `%<count>s` is always 0 or more'
37
37
  RESTRICT_ON_SEND = %i[map collect].freeze
38
38
 
39
+ def_node_matcher :times_map_call, <<~PATTERN
40
+ {
41
+ (any_block $(call (call $!nil? :times) {:map :collect}) ...)
42
+ $(call (call $!nil? :times) {:map :collect} (block_pass ...))
43
+ }
44
+ PATTERN
45
+
39
46
  def on_send(node)
40
47
  check(node)
41
48
  end
@@ -62,7 +69,7 @@ module RuboCop
62
69
 
63
70
  def handleable_receiver?(node)
64
71
  receiver = node.receiver.receiver
65
- return true if receiver.literal? && (receiver.int_type? || receiver.float_type?)
72
+ return true if receiver.literal? && receiver.type?(:int, :float)
66
73
 
67
74
  node.receiver.dot?
68
75
  end
@@ -75,13 +82,6 @@ module RuboCop
75
82
  end
76
83
  format(template, count: count.source, map_or_collect: map_or_collect.method_name)
77
84
  end
78
-
79
- def_node_matcher :times_map_call, <<~PATTERN
80
- {
81
- ({block numblock} $(call (call $!nil? :times) {:map :collect}) ...)
82
- $(call (call $!nil? :times) {:map :collect} (block_pass ...))
83
- }
84
- PATTERN
85
85
  end
86
86
  end
87
87
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # Checks for `map { |id| [id] }` and suggests replacing it with `zip`.
7
+ #
8
+ # @safety
9
+ # This cop is unsafe for novel definitions of `map` and `collect`
10
+ # on non-Enumerable objects that do not respond to `zip`.
11
+ # To make your object enumerable, define an `each` method
12
+ # as described in https://ruby-doc.org/core/Enumerable.html
13
+ #
14
+ # @example
15
+ # # bad
16
+ # [1, 2, 3].map { |id| [id] }
17
+ #
18
+ # # good
19
+ # [1, 2, 3].zip
20
+ class ZipWithoutBlock < Base
21
+ extend AutoCorrector
22
+
23
+ MSG = 'Use `zip` without a block argument instead.'
24
+ RESTRICT_ON_SEND = Set.new(%i[map collect]).freeze
25
+
26
+ # @!method map_with_array?(node)
27
+ def_node_matcher :map_with_array?, <<~PATTERN
28
+ {
29
+ (block (call !nil? RESTRICT_ON_SEND) (args (arg _)) (array (lvar _)))
30
+ (numblock (call !nil? RESTRICT_ON_SEND) 1 (array (lvar _)))
31
+ }
32
+ PATTERN
33
+
34
+ def on_send(node)
35
+ return unless map_with_array?(node.parent)
36
+
37
+ register_offense(node)
38
+ end
39
+ alias on_csend on_send
40
+
41
+ private
42
+
43
+ def register_offense(node)
44
+ offense_range = offense_range(node)
45
+ add_offense(offense_range) do |corrector|
46
+ corrector.replace(offense_range, 'zip')
47
+ end
48
+ end
49
+
50
+ def offense_range(node)
51
+ node.loc.selector.join(node.parent.loc.end)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -54,3 +54,4 @@ require_relative 'performance/times_map'
54
54
  require_relative 'performance/unfreeze_string'
55
55
  require_relative 'performance/uri_default_parser'
56
56
  require_relative 'performance/chain_array_allocation'
57
+ require_relative 'performance/zip_without_block'
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lint_roller'
4
+
5
+ module RuboCop
6
+ module Performance
7
+ # A plugin that integrates RuboCop Performance with RuboCop's plugin system.
8
+ class Plugin < LintRoller::Plugin
9
+ def about
10
+ LintRoller::About.new(
11
+ name: 'rubocop-performance',
12
+ version: Version::STRING,
13
+ homepage: 'https://github.com/rubocop/rubocop-performance',
14
+ description: 'A collection of RuboCop cops to check for performance optimizations in Ruby code.'
15
+ )
16
+ end
17
+
18
+ def supported?(context)
19
+ context.engine == :rubocop
20
+ end
21
+
22
+ def rules(_context)
23
+ project_root = Pathname.new(__dir__).join('../../..')
24
+
25
+ ConfigObsoletion.files << project_root.join('config', 'obsoletion.yml')
26
+
27
+ LintRoller::Rules.new(type: :path, config_format: :rubocop, value: project_root.join('config', 'default.yml'))
28
+ end
29
+ end
30
+ end
31
+ end
@@ -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.23.1'
7
+ STRING = '1.24.0'
8
8
 
9
9
  def self.document_version
10
10
  STRING.match('\d+\.\d+').to_s
@@ -1,14 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RuboCop
4
- # RuboCop Performance project namespace
4
+ # RuboCop Performance project namespace.
5
5
  module Performance
6
- PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
7
- CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
8
- CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
9
-
10
- private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
11
-
12
- ::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join('config', 'obsoletion.yml')
13
6
  end
14
7
  end
@@ -4,10 +4,7 @@ require 'rubocop'
4
4
 
5
5
  require_relative 'rubocop/performance'
6
6
  require_relative 'rubocop/performance/version'
7
- require_relative 'rubocop/performance/inject'
8
-
9
- RuboCop::Performance::Inject.defaults!
10
-
7
+ require_relative 'rubocop/performance/plugin'
11
8
  require_relative 'rubocop/cop/performance_cops'
12
9
 
13
10
  RuboCop::Cop::Lint::UnusedMethodArgument.singleton_class.prepend(
metadata CHANGED
@@ -1,23 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-performance
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.23.1
4
+ version: 1.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
8
8
  - Jonas Arvidsson
9
9
  - Yuji Nakayama
10
+ autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2025-01-04 00:00:00.000000000 Z
13
+ date: 2025-02-15 00:00:00.000000000 Z
13
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: lint_roller
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '1.1'
14
29
  - !ruby/object:Gem::Dependency
15
30
  name: rubocop
16
31
  requirement: !ruby/object:Gem::Requirement
17
32
  requirements:
18
33
  - - ">="
19
34
  - !ruby/object:Gem::Version
20
- version: 1.48.1
35
+ version: 1.72.1
21
36
  - - "<"
22
37
  - !ruby/object:Gem::Version
23
38
  version: '2.0'
@@ -27,7 +42,7 @@ dependencies:
27
42
  requirements:
28
43
  - - ">="
29
44
  - !ruby/object:Gem::Version
30
- version: 1.48.1
45
+ version: 1.72.1
31
46
  - - "<"
32
47
  - !ruby/object:Gem::Version
33
48
  version: '2.0'
@@ -37,7 +52,7 @@ dependencies:
37
52
  requirements:
38
53
  - - ">="
39
54
  - !ruby/object:Gem::Version
40
- version: 1.31.1
55
+ version: 1.38.0
41
56
  - - "<"
42
57
  - !ruby/object:Gem::Version
43
58
  version: '2.0'
@@ -47,7 +62,7 @@ dependencies:
47
62
  requirements:
48
63
  - - ">="
49
64
  - !ruby/object:Gem::Version
50
- version: 1.31.1
65
+ version: 1.38.0
51
66
  - - "<"
52
67
  - !ruby/object:Gem::Version
53
68
  version: '2.0'
@@ -119,9 +134,10 @@ files:
119
134
  - lib/rubocop/cop/performance/times_map.rb
120
135
  - lib/rubocop/cop/performance/unfreeze_string.rb
121
136
  - lib/rubocop/cop/performance/uri_default_parser.rb
137
+ - lib/rubocop/cop/performance/zip_without_block.rb
122
138
  - lib/rubocop/cop/performance_cops.rb
123
139
  - lib/rubocop/performance.rb
124
- - lib/rubocop/performance/inject.rb
140
+ - lib/rubocop/performance/plugin.rb
125
141
  - lib/rubocop/performance/version.rb
126
142
  homepage: https://github.com/rubocop/rubocop-performance
127
143
  licenses:
@@ -130,9 +146,11 @@ metadata:
130
146
  homepage_uri: https://docs.rubocop.org/rubocop-performance/
131
147
  changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
132
148
  source_code_uri: https://github.com/rubocop/rubocop-performance/
133
- documentation_uri: https://docs.rubocop.org/rubocop-performance/1.23/
149
+ documentation_uri: https://docs.rubocop.org/rubocop-performance/1.24/
134
150
  bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
135
151
  rubygems_mfa_required: 'true'
152
+ default_lint_roller_plugin: RuboCop::Performance::Plugin
153
+ post_install_message:
136
154
  rdoc_options: []
137
155
  require_paths:
138
156
  - lib
@@ -147,7 +165,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
165
  - !ruby/object:Gem::Version
148
166
  version: '0'
149
167
  requirements: []
150
- rubygems_version: 3.6.1
168
+ rubygems_version: 3.1.6
169
+ signing_key:
151
170
  specification_version: 4
152
171
  summary: Automatic performance checking tool for Ruby code.
153
172
  test_files: []
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Performance
5
- # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
6
- # bit of our configuration.
7
- module Inject
8
- def self.defaults!
9
- path = CONFIG_DEFAULT.to_s
10
- hash = ConfigLoader.send(:load_yaml_configuration, path)
11
- config = Config.new(hash, path).tap(&:make_excludes_absolute)
12
- puts "configuration from #{path}" if ConfigLoader.debug?
13
- config = ConfigLoader.merge_with_default(config, path)
14
- ConfigLoader.instance_variable_set(:@default_configuration, config)
15
- end
16
- end
17
- end
18
- end