rubocop-performance 1.10.1 → 1.11.3

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: 026fa40bed33c9e7867599f1024ddf6c1ab430b00beae5f5ec52d9b32f5adef9
4
- data.tar.gz: d0997dd1a5255e217f5faf2adc4f27b64a43266ff24264aa80307b474cbfa936
3
+ metadata.gz: 341ace76835db65803b9c7ef7d54f67dbb053c86c9e31b0a80b80f1514e96c29
4
+ data.tar.gz: 031bda91d5c5d1e66716f218472621c115cf247e364c25596c6fd9f470261aca
5
5
  SHA512:
6
- metadata.gz: 7a09ace7478bf3d87dc35897bb677c802c6b191ce0206e1b94e04826091ce8075ad9f267cd7805cd68ba3476c679e3cdb59c219fd71760ac4756c26a209c51bc
7
- data.tar.gz: f9ccef454d4c9ff9a8d67db5276d2249d03a2882b169abfc5d4bacc28f9f09391edb15100750480c354fe9cc161463156169f216d482c9504f7d6a17da524a0c
6
+ metadata.gz: 3c324e059ffa5f0f98789d6336a41ab0135bdf1dcc8e3b45df83ac8bf75e7bae53fe1e40fb7ae0039d83567bd226709b47cd9cc09184819d16ce8c558d56d85e
7
+ data.tar.gz: a7c1698db1e6c9c16150f46df944c3f275c38c0f39bca1bc5f0961bdde6a1d14aa9acb9b19823b9f62f352a11120596559fd9cdef6e3343fd8e01bf71b816f96
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rubocop-performance.svg)](https://badge.fury.io/rb/rubocop-performance)
4
4
  [![CircleCI](https://circleci.com/gh/rubocop/rubocop-performance.svg?style=svg)](https://circleci.com/gh/rubocop/rubocop-performance)
5
+ [![Discord](https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true)](https://discord.gg/wJjWvGRDmm)
5
6
 
6
7
  Performance optimization analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop/rubocop).
7
8
 
data/config/default.yml CHANGED
@@ -174,6 +174,12 @@ Performance/IoReadlines:
174
174
  Enabled: false
175
175
  VersionAdded: '1.7'
176
176
 
177
+ Performance/MapCompact:
178
+ Description: 'Use `filter_map` instead of `collection.map(&:do_something).compact`.'
179
+ Enabled: pending
180
+ SafeAutoCorrect: false
181
+ VersionAdded: '1.11'
182
+
177
183
  Performance/MethodObjectAsBlock:
178
184
  Description: 'Use block explicitly instead of block-passing a method object.'
179
185
  Reference: 'https://github.com/JuanitoFatas/fast-ruby#normal-way-to-apply-method-vs-method-code'
@@ -220,7 +226,9 @@ Performance/RedundantMerge:
220
226
  Description: 'Use Hash#[]=, rather than Hash#merge! with a single key-value pair.'
221
227
  Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashmerge-vs-hash-code'
222
228
  Enabled: true
229
+ Safe: false
223
230
  VersionAdded: '0.36'
231
+ VersionChanged: '1.11'
224
232
  # Max number of key-value pairs to consider an offense
225
233
  MaxKeyValuePairs: 2
226
234
 
@@ -258,6 +266,11 @@ Performance/ReverseFirst:
258
266
  Enabled: 'pending'
259
267
  VersionAdded: '1.7'
260
268
 
269
+ Performance/SelectMap:
270
+ Description: 'Use `filter_map` instead of `ary.select(&:foo).map(&:bar)`.'
271
+ Enabled: false
272
+ VersionAdded: '1.11'
273
+
261
274
  Performance/Size:
262
275
  Description: >-
263
276
  Use `size` instead of `count` for counting
@@ -0,0 +1,7 @@
1
+ #
2
+ # Configuration for obsoletion.
3
+ #
4
+ # See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions
5
+ #
6
+ extracted:
7
+ Performance/*: ~
@@ -63,6 +63,8 @@ module RuboCop
63
63
 
64
64
  def on_send(node)
65
65
  chain_array_allocation?(node) do |fm, sm|
66
+ return if node.each_descendant(:send).any? { |descendant| descendant.method?(:lazy) }
67
+
66
68
  range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
67
69
 
68
70
  add_offense(range, message: format(MSG, method: fm, second_method: sm))
@@ -3,7 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop is used to identify usages of
6
+ # This cop is used to identify usages of `map { ... }.flatten` and
7
+ # change them to use `flat_map { ... }` instead.
7
8
  #
8
9
  # @example
9
10
  # # bad
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # In Ruby 2.7, `Enumerable#filter_map` has been added.
7
+ #
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`.
11
+ #
12
+ # [source,ruby]
13
+ # ----
14
+ # [true, false, nil].compact #=> [true, false]
15
+ # [true, false, nil].filter_map(&:itself) #=> [true]
16
+ # ----
17
+ #
18
+ # @example
19
+ # # bad
20
+ # ary.map(&:foo).compact
21
+ # ary.collect(&:foo).compact
22
+ #
23
+ # # good
24
+ # ary.filter_map(&:foo)
25
+ # ary.map(&:foo).compact!
26
+ # ary.compact.map(&:foo)
27
+ #
28
+ class MapCompact < Base
29
+ include RangeHelp
30
+ extend AutoCorrector
31
+ extend TargetRubyVersion
32
+
33
+ MSG = 'Use `filter_map` instead.'
34
+ RESTRICT_ON_SEND = %i[compact].freeze
35
+
36
+ minimum_target_ruby_version 2.7
37
+
38
+ def_node_matcher :map_compact, <<~PATTERN
39
+ {
40
+ (send
41
+ $(send _ {:map :collect}
42
+ (block_pass
43
+ (sym _))) _)
44
+ (send
45
+ (block
46
+ $(send _ {:map :collect})
47
+ (args ...) _) _)
48
+ }
49
+ PATTERN
50
+
51
+ def on_send(node)
52
+ return unless (map_node = map_compact(node))
53
+
54
+ compact_loc = node.loc
55
+ range = range_between(map_node.loc.selector.begin_pos, compact_loc.selector.end_pos)
56
+
57
+ add_offense(range) do |corrector|
58
+ corrector.replace(map_node.loc.selector, 'filter_map')
59
+ corrector.remove(compact_loc.dot)
60
+ corrector.remove(compact_method_range(node))
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def compact_method_range(compact_node)
67
+ chained_method = compact_node.parent
68
+ compact_method_range = compact_node.loc.selector
69
+
70
+ if compact_node.multiline? && chained_method&.loc.respond_to?(:selector) &&
71
+ !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
+ else
74
+ compact_method_range
75
+ end
76
+ end
77
+
78
+ def invoke_method_after_map_compact_on_same_line?(compact_node, chained_method)
79
+ compact_node.loc.selector.line == chained_method.loc.selector.line
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -78,7 +78,7 @@ module RuboCop
78
78
  end
79
79
 
80
80
  def calls_to_report(argname, body)
81
- return [] if blockarg_assigned?(body, argname)
81
+ return [] if blockarg_assigned?(body, argname) || shadowed_block_argument?(body, argname)
82
82
 
83
83
  blockarg_calls(body, argname).map do |call|
84
84
  return [] if args_include_block_pass?(call)
@@ -87,6 +87,12 @@ module RuboCop
87
87
  end
88
88
  end
89
89
 
90
+ def shadowed_block_argument?(body, block_argument_of_method_signature)
91
+ return false unless body.block_type?
92
+
93
+ body.arguments.map(&:source).include?(block_argument_of_method_signature.to_s)
94
+ end
95
+
90
96
  def args_include_block_pass?(blockcall)
91
97
  _receiver, _call, *args = *blockcall
92
98
 
@@ -35,7 +35,8 @@ module RuboCop
35
35
  IS_A_METHODS = %i[is_a? kind_of?].freeze
36
36
 
37
37
  def on_block(node)
38
- return unless TARGET_METHODS.include?(node.method_name) && node.arguments.one?
38
+ return unless TARGET_METHODS.include?(node.method_name)
39
+ return unless one_block_argument?(node.arguments)
39
40
 
40
41
  block_argument = node.arguments.first
41
42
  block_body = node.body
@@ -53,14 +54,22 @@ module RuboCop
53
54
 
54
55
  private
55
56
 
57
+ def one_block_argument?(block_arguments)
58
+ block_arguments.one? && !block_arguments.source.include?(',')
59
+ end
60
+
56
61
  def use_equality_comparison_block?(block_body)
57
62
  block_body.send_type? && COMPARISON_METHODS.include?(block_body.method_name)
58
63
  end
59
64
 
60
65
  def same_block_argument_and_is_a_argument?(block_body, block_argument)
61
- return false unless IS_A_METHODS.include?(block_body.method_name)
62
-
63
- block_argument.source == block_body.first_argument.source
66
+ if block_body.method?(:===)
67
+ block_argument.source != block_body.children[2].source
68
+ elsif IS_A_METHODS.include?(block_body.method_name)
69
+ block_argument.source == block_body.first_argument.source
70
+ else
71
+ false
72
+ end
64
73
  end
65
74
 
66
75
  def new_argument(block_argument, block_body)
@@ -8,6 +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.
13
+ #
11
14
  # @example
12
15
  # # bad
13
16
  # hash.merge!(a: 1)
@@ -26,7 +26,7 @@ module RuboCop
26
26
 
27
27
  def on_send(node)
28
28
  return unless (regexp_node = split_call_with_regexp?(node))
29
- return if regexp_node.ignore_case?
29
+ return if regexp_node.ignore_case? || regexp_node.content == ' '
30
30
  return unless determinist_regexp?(regexp_node)
31
31
 
32
32
  add_offense(regexp_node) do |corrector|
@@ -6,12 +6,20 @@ module RuboCop
6
6
  # This cop is used to identify usages of `reverse.each` and
7
7
  # change them to use `reverse_each` instead.
8
8
  #
9
+ # If the return value is used, it will not be detected because the result will be different.
10
+ #
11
+ # [source,ruby]
12
+ # ----
13
+ # [1, 2, 3].reverse.each {} #=> [3, 2, 1]
14
+ # [1, 2, 3].reverse_each {} #=> [1, 2, 3]
15
+ # ----
16
+ #
9
17
  # @example
10
18
  # # bad
11
- # [].reverse.each
19
+ # items.reverse.each
12
20
  #
13
21
  # # good
14
- # [].reverse_each
22
+ # items.reverse_each
15
23
  class ReverseEach < Base
16
24
  include RangeHelp
17
25
  extend AutoCorrector
@@ -24,6 +32,8 @@ module RuboCop
24
32
  MATCHER
25
33
 
26
34
  def on_send(node)
35
+ return if use_return_value?(node)
36
+
27
37
  reverse_each?(node) do
28
38
  range = offense_range(node)
29
39
 
@@ -35,6 +45,12 @@ module RuboCop
35
45
 
36
46
  private
37
47
 
48
+ def use_return_value?(node)
49
+ !!node.ancestors.detect do |ancestor|
50
+ ancestor.assignment? || ancestor.send_type? || ancestor.return_type?
51
+ end
52
+ end
53
+
38
54
  def offense_range(node)
39
55
  range_between(node.children.first.loc.selector.begin_pos, node.loc.selector.end_pos)
40
56
  end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # In Ruby 2.7, `Enumerable#filter_map` has been added.
7
+ #
8
+ # This cop identifies places where `select.map` can be replaced by `filter_map`.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # ary.select(&:foo).map(&:bar)
13
+ # ary.filter(&:foo).map(&:bar)
14
+ #
15
+ # # good
16
+ # ary.filter_map { |o| o.bar if o.foo }
17
+ #
18
+ class SelectMap < Base
19
+ include RangeHelp
20
+ extend TargetRubyVersion
21
+
22
+ minimum_target_ruby_version 2.7
23
+
24
+ MSG = 'Use `filter_map` instead of `%<method_name>s.map`.'
25
+ RESTRICT_ON_SEND = %i[select filter].freeze
26
+
27
+ def_node_matcher :bad_method?, <<~PATTERN
28
+ (send nil? :bad_method ...)
29
+ PATTERN
30
+
31
+ def on_send(node)
32
+ return if (first_argument = node.first_argument) && !first_argument.block_pass_type?
33
+ return unless (send_node = map_method_candidate(node))
34
+ return unless send_node.method?(:map)
35
+
36
+ map_method = send_node.parent&.block_type? ? send_node.parent : send_node
37
+
38
+ range = offense_range(node, map_method)
39
+ add_offense(range, message: format(MSG, method_name: node.method_name))
40
+ end
41
+
42
+ private
43
+
44
+ def map_method_candidate(node)
45
+ return unless (parent = node.parent)
46
+
47
+ if parent.block_type? && parent.parent&.send_type?
48
+ parent.parent
49
+ elsif parent.send_type?
50
+ parent
51
+ end
52
+ end
53
+
54
+ def offense_range(node, map_method)
55
+ range_between(node.loc.selector.begin_pos, map_method.loc.expression.end_pos)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -23,6 +23,7 @@ require_relative 'performance/end_with'
23
23
  require_relative 'performance/fixed_size'
24
24
  require_relative 'performance/flat_map'
25
25
  require_relative 'performance/inefficient_hash_search'
26
+ require_relative 'performance/map_compact'
26
27
  require_relative 'performance/method_object_as_block'
27
28
  require_relative 'performance/open_struct'
28
29
  require_relative 'performance/range_include'
@@ -37,6 +38,7 @@ require_relative 'performance/redundant_string_chars'
37
38
  require_relative 'performance/regexp_match'
38
39
  require_relative 'performance/reverse_each'
39
40
  require_relative 'performance/reverse_first'
41
+ require_relative 'performance/select_map'
40
42
  require_relative 'performance/size'
41
43
  require_relative 'performance/sort_reverse'
42
44
  require_relative 'performance/squeeze'
@@ -8,5 +8,7 @@ module RuboCop
8
8
  CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
9
9
 
10
10
  private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
11
+
12
+ ::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join('config', 'obsoletion.yml')
11
13
  end
12
14
  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.10.1'
7
+ STRING = '1.11.3'
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.10.1
4
+ version: 1.11.3
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-03-01 00:00:00.000000000 Z
13
+ date: 2021-05-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.90.0
21
+ version: 1.7.0
22
22
  - - "<"
23
23
  - !ruby/object:Gem::Version
24
24
  version: '2.0'
@@ -28,7 +28,7 @@ dependencies:
28
28
  requirements:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: 0.90.0
31
+ version: 1.7.0
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '2.0'
@@ -59,6 +59,7 @@ files:
59
59
  - LICENSE.txt
60
60
  - README.md
61
61
  - config/default.yml
62
+ - config/obsoletion.yml
62
63
  - lib/rubocop-performance.rb
63
64
  - lib/rubocop/cop/mixin/regexp_metacharacter.rb
64
65
  - lib/rubocop/cop/mixin/sort_block.rb
@@ -84,6 +85,7 @@ files:
84
85
  - lib/rubocop/cop/performance/flat_map.rb
85
86
  - lib/rubocop/cop/performance/inefficient_hash_search.rb
86
87
  - lib/rubocop/cop/performance/io_readlines.rb
88
+ - lib/rubocop/cop/performance/map_compact.rb
87
89
  - lib/rubocop/cop/performance/method_object_as_block.rb
88
90
  - lib/rubocop/cop/performance/open_struct.rb
89
91
  - lib/rubocop/cop/performance/range_include.rb
@@ -97,6 +99,7 @@ files:
97
99
  - lib/rubocop/cop/performance/regexp_match.rb
98
100
  - lib/rubocop/cop/performance/reverse_each.rb
99
101
  - lib/rubocop/cop/performance/reverse_first.rb
102
+ - lib/rubocop/cop/performance/select_map.rb
100
103
  - lib/rubocop/cop/performance/size.rb
101
104
  - lib/rubocop/cop/performance/sort_reverse.rb
102
105
  - lib/rubocop/cop/performance/squeeze.rb
@@ -118,7 +121,7 @@ metadata:
118
121
  homepage_uri: https://docs.rubocop.org/rubocop-performance/
119
122
  changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
120
123
  source_code_uri: https://github.com/rubocop/rubocop-performance/
121
- documentation_uri: https://docs.rubocop.org/rubocop-performance/1.10/
124
+ documentation_uri: https://docs.rubocop.org/rubocop-performance/1.11/
122
125
  bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
123
126
  post_install_message:
124
127
  rdoc_options: []
@@ -128,7 +131,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
128
131
  requirements:
129
132
  - - ">="
130
133
  - !ruby/object:Gem::Version
131
- version: 2.4.0
134
+ version: 2.5.0
132
135
  required_rubygems_version: !ruby/object:Gem::Requirement
133
136
  requirements:
134
137
  - - ">="