rubocop-performance 1.9.2 → 1.11.1

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: 30b8495304f86e7ef0e9a7f11e12a30ab7986fb4b12cb1921870f31a1b37a42f
4
- data.tar.gz: 1863b8766efff5dd99b2e4f2dbb4e16191f223d12dbfd51826a837f1f75eef08
3
+ metadata.gz: 0fddb9566bda412ba7ab8f26966cca63207064468d2c2da5796a81cd84da1c69
4
+ data.tar.gz: f49da21e50225a0f35fe6959ad3a37a2c26ff73e64df03f5a94025811d380b02
5
5
  SHA512:
6
- metadata.gz: a6071b0e37b9a9683f1992b88b36e0911004e0ec8fc4b41f78ba569ce396d96840acb0eff937d519d132917dec1b0a5af9fe4d1563d743e293ee78239a59b13f
7
- data.tar.gz: 74c457f9d7f7ef240a2fa483100ff1120fc4edba7bb64e999f78a85e106621cba4ddef1a2dae7f375f9541d021a0fa08f054edf83ebd1646423d214b4677e212
6
+ metadata.gz: a70fd0b8cf0778f410098e889dc52c828202f0d197a10a9fb4edff36991204cad23cfba361039b9b80952c7f5f814679d7277e2f9c533fe29fd55e708c4d1bb9
7
+ data.tar.gz: a2ce3b7915ed3c3bc208ef020f031646e3350d46397759eb0c5a772e826dc30ad8d72d75c009b385358ef015be4b6af4c7cd1b6f337b6f34c583432bef608a65
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-20 Bozhidar Batsov
1
+ Copyright (c) 2012-21 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/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # RuboCop Performance
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rubocop-performance.svg)](https://badge.fury.io/rb/rubocop-performance)
4
- [![CircleCI](https://circleci.com/gh/rubocop-hq/rubocop-performance.svg?style=svg)](https://circleci.com/gh/rubocop-hq/rubocop-performance)
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
- Performance optimization analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop-hq/rubocop).
7
+ Performance optimization analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop/rubocop).
7
8
 
8
9
  ## Installation
9
10
 
data/config/default.yml CHANGED
@@ -10,7 +10,7 @@ Performance/AncestorsInclude:
10
10
  Performance/ArraySemiInfiniteRangeSlice:
11
11
  Description: 'Identifies places where slicing arrays with semi-infinite ranges can be replaced by `Array#take` and `Array#drop`.'
12
12
  # This cop was created due to a mistake in microbenchmark.
13
- # Refer https://github.com/rubocop-hq/rubocop-performance/pull/175#issuecomment-731892717
13
+ # Refer https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717
14
14
  Enabled: false
15
15
  # Unsafe for string slices because strings do not have `#take` and `#drop` methods.
16
16
  Safe: false
@@ -80,6 +80,7 @@ Performance/ConstantRegexp:
80
80
  Description: 'Finds regular expressions with dynamic components that are all constants.'
81
81
  Enabled: pending
82
82
  VersionAdded: '1.9'
83
+ VersionChanged: '1.10'
83
84
 
84
85
  Performance/Count:
85
86
  Description: >-
@@ -136,11 +137,10 @@ Performance/EndWith:
136
137
  # object. Switching these methods has to be done with knowledge of the types
137
138
  # of the variables which rubocop doesn't have.
138
139
  SafeAutoCorrect: false
139
- AutoCorrect: false
140
140
  Enabled: true
141
141
  SafeMultiline: true
142
142
  VersionAdded: '0.36'
143
- VersionChanged: '1.6'
143
+ VersionChanged: '1.10'
144
144
 
145
145
  Performance/FixedSize:
146
146
  Description: 'Do not compute the size of statically sized objects except in constants.'
@@ -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'
@@ -200,6 +206,15 @@ Performance/RedundantBlockCall:
200
206
  Enabled: true
201
207
  VersionAdded: '0.36'
202
208
 
209
+ Performance/RedundantEqualityComparisonBlock:
210
+ Description: >-
211
+ Checks for uses `Enumerable#all?`, `Enumerable#any?`, `Enumerable#one?`,
212
+ or `Enumerable#none?` are compared with `===` or similar methods in block.
213
+ Reference: 'https://github.com/rails/rails/pull/41363'
214
+ Enabled: pending
215
+ Safe: false
216
+ VersionAdded: '1.10'
217
+
203
218
  Performance/RedundantMatch:
204
219
  Description: >-
205
220
  Use `=~` instead of `String#match` or `Regexp#match` in a context where the
@@ -211,7 +226,9 @@ Performance/RedundantMerge:
211
226
  Description: 'Use Hash#[]=, rather than Hash#merge! with a single key-value pair.'
212
227
  Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashmerge-vs-hash-code'
213
228
  Enabled: true
229
+ Safe: false
214
230
  VersionAdded: '0.36'
231
+ VersionChanged: '1.11'
215
232
  # Max number of key-value pairs to consider an offense
216
233
  MaxKeyValuePairs: 2
217
234
 
@@ -220,6 +237,11 @@ Performance/RedundantSortBlock:
220
237
  Enabled: 'pending'
221
238
  VersionAdded: '1.7'
222
239
 
240
+ Performance/RedundantSplitRegexpArgument:
241
+ Description: 'This cop identifies places where `split` argument can be replaced from a deterministic regexp to a string.'
242
+ Enabled: pending
243
+ VersionAdded: '1.10'
244
+
223
245
  Performance/RedundantStringChars:
224
246
  Description: 'Checks for redundant `String#chars`.'
225
247
  Enabled: 'pending'
@@ -244,6 +266,11 @@ Performance/ReverseFirst:
244
266
  Enabled: 'pending'
245
267
  VersionAdded: '1.7'
246
268
 
269
+ Performance/SelectMap:
270
+ Description: 'Use `filter_map` instead of `ary.select(&:foo).map(&:bar)`.'
271
+ Enabled: false
272
+ VersionAdded: '1.11'
273
+
247
274
  Performance/Size:
248
275
  Description: >-
249
276
  Use `size` instead of `count` for counting
@@ -270,11 +297,10 @@ Performance/StartWith:
270
297
  # object. Switching these methods has to be done with knowledge of the types
271
298
  # of the variables which rubocop doesn't have.
272
299
  SafeAutoCorrect: false
273
- AutoCorrect: false
274
300
  Enabled: true
275
301
  SafeMultiline: true
276
302
  VersionAdded: '0.36'
277
- VersionChanged: '1.6'
303
+ VersionChanged: '1.10'
278
304
 
279
305
  Performance/StringInclude:
280
306
  Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
@@ -304,7 +330,7 @@ Performance/TimesMap:
304
330
  Enabled: true
305
331
  VersionAdded: '0.36'
306
332
  VersionChanged: '0.50'
307
- SafeAutoCorrect: false # see https://github.com/rubocop-hq/rubocop/issues/4658
333
+ SafeAutoCorrect: false # see https://github.com/rubocop/rubocop/issues/4658
308
334
 
309
335
  Performance/UnfreezeString:
310
336
  Description: 'Use unary plus to get an unfrozen string literal.'
@@ -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/*: ~
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # This cop identifies places where slicing arrays with semi-infinite ranges
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
- # Refer https://github.com/rubocop-hq/rubocop-performance/pull/175#issuecomment-731892717
9
+ # Refer https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717
10
10
  # This cop is also unsafe for string slices because strings do not have `#take` and `#drop` methods.
11
11
  #
12
12
  # @example
@@ -33,7 +33,7 @@ module RuboCop
33
33
  def_node_matcher :bind_with_call_method?, <<~PATTERN
34
34
  (send
35
35
  $(send
36
- (send nil? _) :bind
36
+ _ :bind
37
37
  $(...)) :call
38
38
  $...)
39
39
  PATTERN
@@ -64,7 +64,7 @@ module RuboCop
64
64
 
65
65
  def correction_range(receiver, node)
66
66
  location_of_bind = receiver.loc.selector.begin_pos
67
- location_of_call = node.loc.end.end_pos
67
+ location_of_call = node.source_range.end.end_pos
68
68
 
69
69
  range_between(location_of_bind, location_of_call)
70
70
  end
@@ -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))
@@ -6,9 +6,9 @@ module RuboCop
6
6
  # This cop finds regular expressions with dynamic components that are all constants.
7
7
  #
8
8
  # Ruby allocates a new Regexp object every time it executes a code containing such
9
- # a regular expression. It is more efficient to extract it into a constant
10
- # or add an `/o` option to perform `#{}` interpolation only once and reuse that
11
- # Regexp object.
9
+ # a regular expression. It is more efficient to extract it into a constant,
10
+ # memoize it, or add an `/o` option to perform `#{}` interpolation only once and
11
+ # reuse that Regexp object.
12
12
  #
13
13
  # @example
14
14
  #
@@ -28,13 +28,18 @@ module RuboCop
28
28
  # pattern.scan(TOKEN).reject { |token| token.match?(/\A#{SEPARATORS}\Z/o) }
29
29
  # end
30
30
  #
31
+ # # good
32
+ # def separators
33
+ # @separators ||= /\A#{SEPARATORS}\Z/
34
+ # end
35
+ #
31
36
  class ConstantRegexp < Base
32
37
  extend AutoCorrector
33
38
 
34
- MSG = 'Extract this regexp into a constant or append an `/o` option to its options.'
39
+ MSG = 'Extract this regexp into a constant, memoize it, or append an `/o` option to its options.'
35
40
 
36
41
  def on_regexp(node)
37
- return if within_const_assignment?(node) ||
42
+ return if within_allowed_assignment?(node) ||
38
43
  !include_interpolated_const?(node) ||
39
44
  node.single_interpolation?
40
45
 
@@ -45,8 +50,8 @@ module RuboCop
45
50
 
46
51
  private
47
52
 
48
- def within_const_assignment?(node)
49
- node.each_ancestor(:casgn).any?
53
+ def within_allowed_assignment?(node)
54
+ node.each_ancestor(:casgn, :or_asgn).any?
50
55
  end
51
56
 
52
57
  def_node_matcher :regexp_escape?, <<~PATTERN
@@ -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,77 @@
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
+ #
27
+ class MapCompact < Base
28
+ include RangeHelp
29
+ extend AutoCorrector
30
+ extend TargetRubyVersion
31
+
32
+ MSG = 'Use `filter_map` instead.'
33
+ RESTRICT_ON_SEND = %i[compact].freeze
34
+
35
+ minimum_target_ruby_version 2.7
36
+
37
+ def_node_matcher :map_compact, <<~PATTERN
38
+ {
39
+ (send
40
+ $(send _ {:map :collect}
41
+ (block_pass
42
+ (sym _))) _)
43
+ (send
44
+ (block
45
+ $(send _ {:map :collect})
46
+ (args ...) _) _)
47
+ }
48
+ PATTERN
49
+
50
+ def on_send(node)
51
+ return unless (map_node = map_compact(node))
52
+
53
+ compact_loc = node.loc
54
+ range = range_between(map_node.loc.selector.begin_pos, compact_loc.selector.end_pos)
55
+
56
+ add_offense(range) do |corrector|
57
+ corrector.replace(map_node.loc.selector, 'filter_map')
58
+ corrector.remove(compact_loc.dot)
59
+ corrector.remove(compact_method_range(node))
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def compact_method_range(compact_node)
66
+ compact_method_range = compact_node.loc.selector
67
+
68
+ if compact_node.multiline?
69
+ range_by_whole_lines(compact_method_range, include_final_newline: true)
70
+ else
71
+ compact_method_range
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ 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
 
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # This cop checks for uses `Enumerable#all?`, `Enumerable#any?`, `Enumerable#one?`,
7
+ # and `Enumerable#none?` are compared with `===` or similar methods in block.
8
+ #
9
+ # By default, `Object#===` behaves the same as `Object#==`, but this
10
+ # behavior is appropriately overridden in subclass. For example,
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.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # items.all? { |item| pattern === item }
18
+ # items.all? { |item| item == other }
19
+ # items.all? { |item| item.is_a?(Klass) }
20
+ # items.all? { |item| item.kind_of?(Klass) }
21
+ #
22
+ # # good
23
+ # items.all?(pattern)
24
+ #
25
+ class RedundantEqualityComparisonBlock < Base
26
+ extend AutoCorrector
27
+ extend TargetRubyVersion
28
+
29
+ minimum_target_ruby_version 2.5
30
+
31
+ MSG = 'Use `%<prefer>s` instead of block.'
32
+
33
+ TARGET_METHODS = %i[all? any? one? none?].freeze
34
+ COMPARISON_METHODS = %i[== === is_a? kind_of?].freeze
35
+ IS_A_METHODS = %i[is_a? kind_of?].freeze
36
+
37
+ def on_block(node)
38
+ return unless TARGET_METHODS.include?(node.method_name)
39
+ return unless one_block_argument?(node.arguments)
40
+
41
+ block_argument = node.arguments.first
42
+ block_body = node.body
43
+ return unless use_equality_comparison_block?(block_body)
44
+ return if same_block_argument_and_is_a_argument?(block_body, block_argument)
45
+ return unless (new_argument = new_argument(block_argument, block_body))
46
+
47
+ range = offense_range(node)
48
+ prefer = "#{node.method_name}(#{new_argument})"
49
+
50
+ add_offense(range, message: format(MSG, prefer: prefer)) do |corrector|
51
+ corrector.replace(range, prefer)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def one_block_argument?(block_arguments)
58
+ block_arguments.one? && !block_arguments.source.include?(',')
59
+ end
60
+
61
+ def use_equality_comparison_block?(block_body)
62
+ block_body.send_type? && COMPARISON_METHODS.include?(block_body.method_name)
63
+ end
64
+
65
+ def same_block_argument_and_is_a_argument?(block_body, block_argument)
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
73
+ end
74
+
75
+ def new_argument(block_argument, block_body)
76
+ if block_argument.source == block_body.receiver.source
77
+ block_body.first_argument.source
78
+ elsif block_argument.source == block_body.first_argument.source
79
+ block_body.receiver.source
80
+ end
81
+ end
82
+
83
+ def offense_range(node)
84
+ node.send_node.loc.selector.join(node.source_range.end)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -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)
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Performance
6
+ # This cop identifies places where `split` argument can be replaced from
7
+ # a deterministic regexp to a string.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # 'a,b,c'.split(/,/)
12
+ #
13
+ # # good
14
+ # 'a,b,c'.split(',')
15
+ class RedundantSplitRegexpArgument < Base
16
+ extend AutoCorrector
17
+
18
+ MSG = 'Use string as argument instead of regexp.'
19
+ RESTRICT_ON_SEND = %i[split].freeze
20
+ DETERMINISTIC_REGEX = /\A(?:#{LITERAL_REGEX})+\Z/.freeze
21
+ STR_SPECIAL_CHARS = %w[\n \" \' \\\\ \t \b \f \r].freeze
22
+
23
+ def_node_matcher :split_call_with_regexp?, <<~PATTERN
24
+ {(send !nil? :split $regexp)}
25
+ PATTERN
26
+
27
+ def on_send(node)
28
+ return unless (regexp_node = split_call_with_regexp?(node))
29
+ return if regexp_node.ignore_case? || regexp_node.content == ' '
30
+ return unless determinist_regexp?(regexp_node)
31
+
32
+ add_offense(regexp_node) do |corrector|
33
+ new_argument = replacement(regexp_node)
34
+
35
+ corrector.replace(regexp_node, "\"#{new_argument}\"")
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def determinist_regexp?(regexp_node)
42
+ DETERMINISTIC_REGEX.match?(regexp_node.source)
43
+ end
44
+
45
+ def replacement(regexp_node)
46
+ regexp_content = regexp_node.content
47
+ stack = []
48
+ chars = regexp_content.chars.each_with_object([]) do |char, strings|
49
+ if stack.empty? && char == '\\'
50
+ stack.push(char)
51
+ else
52
+ strings << "#{stack.pop}#{char}"
53
+ end
54
+ end
55
+ chars.map do |char|
56
+ char = char.dup
57
+ char.delete!('\\') unless STR_SPECIAL_CHARS.include?(char)
58
+ char
59
+ end.join
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -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
@@ -150,7 +150,9 @@ module RuboCop
150
150
  replacement = build_good_method(init, block_pass)
151
151
 
152
152
  corrector.remove(sum_range)
153
- corrector.replace(map_range, ".#{replacement}")
153
+
154
+ dot = '.' if map.receiver
155
+ corrector.replace(map_range, "#{dot}#{replacement}")
154
156
  end
155
157
 
156
158
  def sum_method_range(node)
@@ -228,7 +230,11 @@ module RuboCop
228
230
  end
229
231
 
230
232
  def method_call_with_args_range(node)
231
- node.receiver.source_range.end.join(node.source_range.end)
233
+ if (receiver = node.receiver)
234
+ receiver.source_range.end.join(node.source_range.end)
235
+ else
236
+ node.source_range
237
+ end
232
238
  end
233
239
  end
234
240
  end
@@ -23,18 +23,22 @@ 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'
29
30
  require_relative 'performance/io_readlines'
30
31
  require_relative 'performance/redundant_block_call'
32
+ require_relative 'performance/redundant_equality_comparison_block'
31
33
  require_relative 'performance/redundant_match'
32
34
  require_relative 'performance/redundant_merge'
33
35
  require_relative 'performance/redundant_sort_block'
36
+ require_relative 'performance/redundant_split_regexp_argument'
34
37
  require_relative 'performance/redundant_string_chars'
35
38
  require_relative 'performance/regexp_match'
36
39
  require_relative 'performance/reverse_each'
37
40
  require_relative 'performance/reverse_first'
41
+ require_relative 'performance/select_map'
38
42
  require_relative 'performance/size'
39
43
  require_relative 'performance/sort_reverse'
40
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.9.2'
7
+ STRING = '1.11.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.9.2
4
+ version: 1.11.1
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-01-01 00:00:00.000000000 Z
13
+ date: 2021-05-01 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,17 +85,21 @@ 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
90
92
  - lib/rubocop/cop/performance/redundant_block_call.rb
93
+ - lib/rubocop/cop/performance/redundant_equality_comparison_block.rb
91
94
  - lib/rubocop/cop/performance/redundant_match.rb
92
95
  - lib/rubocop/cop/performance/redundant_merge.rb
93
96
  - lib/rubocop/cop/performance/redundant_sort_block.rb
97
+ - lib/rubocop/cop/performance/redundant_split_regexp_argument.rb
94
98
  - lib/rubocop/cop/performance/redundant_string_chars.rb
95
99
  - lib/rubocop/cop/performance/regexp_match.rb
96
100
  - lib/rubocop/cop/performance/reverse_each.rb
97
101
  - lib/rubocop/cop/performance/reverse_first.rb
102
+ - lib/rubocop/cop/performance/select_map.rb
98
103
  - lib/rubocop/cop/performance/size.rb
99
104
  - lib/rubocop/cop/performance/sort_reverse.rb
100
105
  - lib/rubocop/cop/performance/squeeze.rb
@@ -109,15 +114,15 @@ files:
109
114
  - lib/rubocop/performance.rb
110
115
  - lib/rubocop/performance/inject.rb
111
116
  - lib/rubocop/performance/version.rb
112
- homepage: https://github.com/rubocop-hq/rubocop-performance
117
+ homepage: https://github.com/rubocop/rubocop-performance
113
118
  licenses:
114
119
  - MIT
115
120
  metadata:
116
121
  homepage_uri: https://docs.rubocop.org/rubocop-performance/
117
- changelog_uri: https://github.com/rubocop-hq/rubocop-performance/blob/master/CHANGELOG.md
118
- source_code_uri: https://github.com/rubocop-hq/rubocop-performance/
119
- documentation_uri: https://docs.rubocop.org/rubocop-performance/1.9/
120
- bug_tracker_uri: https://github.com/rubocop-hq/rubocop-performance/issues
122
+ changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
123
+ source_code_uri: https://github.com/rubocop/rubocop-performance/
124
+ documentation_uri: https://docs.rubocop.org/rubocop-performance/1.11/
125
+ bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
121
126
  post_install_message:
122
127
  rdoc_options: []
123
128
  require_paths:
@@ -126,14 +131,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
126
131
  requirements:
127
132
  - - ">="
128
133
  - !ruby/object:Gem::Version
129
- version: 2.4.0
134
+ version: 2.5.0
130
135
  required_rubygems_version: !ruby/object:Gem::Requirement
131
136
  requirements:
132
137
  - - ">="
133
138
  - !ruby/object:Gem::Version
134
139
  version: '0'
135
140
  requirements: []
136
- rubygems_version: 3.2.3
141
+ rubygems_version: 3.2.12
137
142
  signing_key:
138
143
  specification_version: 4
139
144
  summary: Automatic performance checking tool for Ruby code.