rubocop-performance 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab226ddbd8840eb8a3c4281e137a727b4514d9ee99c0f321de8e5d16621622cd
4
- data.tar.gz: 04e64315a9ecbbb6cbef28c1dfecb953069b3282f0749caede003c00c93b981c
3
+ metadata.gz: 4c816f114aca2b788180d1ee5869c0a56431f9d98ff5c4d02d664ca7f90fd3e6
4
+ data.tar.gz: 6c7fc284ea2f60d098e53f0b9518b0ca1676e1b4659d0b30e230b044ad089316
5
5
  SHA512:
6
- metadata.gz: 59f5c83e64695cb149d5babfa5e8be759fa11f23f4395810e928b627c236f0d7206f20527a1b2a96953e585f39a89c25f18ac68a44a3dd56ae2daffbc2513990
7
- data.tar.gz: '0189ac9e3a329fec641134b595776cb04ba34fe13f1a3f72fc506bc95cb2021402a113090edc3be86bccd251f23768afe6cf81c6f64cfb9855ba3b32b30a0a9e'
6
+ metadata.gz: e2b576ba2e2d34fccfd31dbda2f34d85c9e359ed0c34195393fac93d6918070dbd64fb07d3e9a60f3f7074e09a969c5e78caaf15a231d614fc9e3d5100926c64
7
+ data.tar.gz: 8c9a0db760475847abcd14a41a403c294e3bbbe75a8fa7070b0047ff043a2ea840beff2a550500727aae98ec2262ebaaa2fba57b160aa1aec0b9afc0f54212b1
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # RuboCop Performance
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/rubocop-performance.svg)](https://badge.fury.io/rb/rubocop-performance)
3
4
  [![CircleCI](https://circleci.com/gh/rubocop-hq/rubocop-performance.svg?style=svg)](https://circleci.com/gh/rubocop-hq/rubocop-performance)
4
5
 
5
6
  Performance optimization analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop-hq/rubocop).
data/config/default.yml CHANGED
@@ -113,11 +113,6 @@ Performance/InefficientHashSearch:
113
113
  VersionAdded: '0.56'
114
114
  Safe: false
115
115
 
116
- Performance/LstripRstrip:
117
- Description: 'Use `strip` instead of `lstrip.rstrip`.'
118
- Enabled: true
119
- VersionAdded: '0.36'
120
-
121
116
  Performance/OpenStruct:
122
117
  Description: 'Use `Struct` instead of `OpenStruct`.'
123
118
  Enabled: false
@@ -152,11 +147,6 @@ Performance/RedundantMerge:
152
147
  # Max number of key-value pairs to consider an offense
153
148
  MaxKeyValuePairs: 2
154
149
 
155
- Performance/RedundantSortBy:
156
- Description: 'Use `sort` instead of `sort_by { |x| x }`.'
157
- Enabled: true
158
- VersionAdded: '0.36'
159
-
160
150
  Performance/RegexpMatch:
161
151
  Description: >-
162
152
  Use `match?` instead of `Regexp#match`, `String#match`, `Symbol#match`,
@@ -171,14 +161,6 @@ Performance/ReverseEach:
171
161
  Enabled: true
172
162
  VersionAdded: '0.30'
173
163
 
174
- Performance/Sample:
175
- Description: >-
176
- Use `sample` instead of `shuffle.first`,
177
- `shuffle.last`, and `shuffle[Integer]`.
178
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code'
179
- Enabled: true
180
- VersionAdded: '0.30'
181
-
182
164
  Performance/Size:
183
165
  Description: >-
184
166
  Use `size` instead of `count` for counting
@@ -221,13 +203,6 @@ Performance/UnfreezeString:
221
203
  Enabled: true
222
204
  VersionAdded: '0.50'
223
205
 
224
- Performance/UnneededSort:
225
- Description: >-
226
- Use `min` instead of `sort.first`,
227
- `max_by` instead of `sort_by...last`, etc.
228
- Enabled: true
229
- VersionAdded: '0.55'
230
-
231
206
  Performance/UriDefaultParser:
232
207
  Description: 'Use `URI::DEFAULT_PARSER` instead of `URI::Parser.new`.'
233
208
  Enabled: true
@@ -19,21 +19,17 @@ require_relative 'performance/end_with'
19
19
  require_relative 'performance/fixed_size'
20
20
  require_relative 'performance/flat_map'
21
21
  require_relative 'performance/inefficient_hash_search'
22
- require_relative 'performance/lstrip_rstrip'
23
22
  require_relative 'performance/open_struct'
24
23
  require_relative 'performance/range_include'
25
24
  require_relative 'performance/redundant_block_call'
26
25
  require_relative 'performance/redundant_match'
27
26
  require_relative 'performance/redundant_merge'
28
- require_relative 'performance/redundant_sort_by'
29
27
  require_relative 'performance/regexp_match'
30
28
  require_relative 'performance/reverse_each'
31
- require_relative 'performance/sample'
32
29
  require_relative 'performance/size'
33
30
  require_relative 'performance/start_with'
34
31
  require_relative 'performance/string_replacement'
35
32
  require_relative 'performance/times_map'
36
33
  require_relative 'performance/unfreeze_string'
37
- require_relative 'performance/unneeded_sort'
38
34
  require_relative 'performance/uri_default_parser'
39
35
  require_relative 'performance/chain_array_allocation'
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Performance
5
5
  module Version
6
- STRING = '1.0.0'.freeze
6
+ STRING = '1.1.0'.freeze
7
7
  end
8
8
  end
9
9
  end
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.0.0
4
+ version: 1.1.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: 2019-03-14 00:00:00.000000000 Z
13
+ date: 2019-04-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 0.58.0
21
+ version: 0.67.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 0.58.0
28
+ version: 0.67.0
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: simplecov
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -66,22 +66,18 @@ files:
66
66
  - lib/rubocop/cop/performance/fixed_size.rb
67
67
  - lib/rubocop/cop/performance/flat_map.rb
68
68
  - lib/rubocop/cop/performance/inefficient_hash_search.rb
69
- - lib/rubocop/cop/performance/lstrip_rstrip.rb
70
69
  - lib/rubocop/cop/performance/open_struct.rb
71
70
  - lib/rubocop/cop/performance/range_include.rb
72
71
  - lib/rubocop/cop/performance/redundant_block_call.rb
73
72
  - lib/rubocop/cop/performance/redundant_match.rb
74
73
  - lib/rubocop/cop/performance/redundant_merge.rb
75
- - lib/rubocop/cop/performance/redundant_sort_by.rb
76
74
  - lib/rubocop/cop/performance/regexp_match.rb
77
75
  - lib/rubocop/cop/performance/reverse_each.rb
78
- - lib/rubocop/cop/performance/sample.rb
79
76
  - lib/rubocop/cop/performance/size.rb
80
77
  - lib/rubocop/cop/performance/start_with.rb
81
78
  - lib/rubocop/cop/performance/string_replacement.rb
82
79
  - lib/rubocop/cop/performance/times_map.rb
83
80
  - lib/rubocop/cop/performance/unfreeze_string.rb
84
- - lib/rubocop/cop/performance/unneeded_sort.rb
85
81
  - lib/rubocop/cop/performance/uri_default_parser.rb
86
82
  - lib/rubocop/cop/performance_cops.rb
87
83
  - lib/rubocop/performance.rb
@@ -104,7 +100,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
100
  requirements:
105
101
  - - ">="
106
102
  - !ruby/object:Gem::Version
107
- version: 2.2.0
103
+ version: 2.2.2
108
104
  required_rubygems_version: !ruby/object:Gem::Requirement
109
105
  requirements:
110
106
  - - ">="
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop identifies places where `lstrip.rstrip` can be replaced by
7
- # `strip`.
8
- #
9
- # @example
10
- # # bad
11
- # 'abc'.lstrip.rstrip
12
- # 'abc'.rstrip.lstrip
13
- #
14
- # # good
15
- # 'abc'.strip
16
- class LstripRstrip < Cop
17
- include RangeHelp
18
-
19
- MSG = 'Use `strip` instead of `%<methods>s`.'.freeze
20
-
21
- def_node_matcher :lstrip_rstrip, <<-PATTERN
22
- {(send $(send _ $:rstrip) $:lstrip)
23
- (send $(send _ $:lstrip) $:rstrip)}
24
- PATTERN
25
-
26
- def on_send(node)
27
- lstrip_rstrip(node) do |first_send, method_one, method_two|
28
- range = range_between(first_send.loc.selector.begin_pos,
29
- node.source_range.end_pos)
30
- add_offense(node,
31
- location: range,
32
- message: format(MSG,
33
- methods: "#{method_one}.#{method_two}"))
34
- end
35
- end
36
-
37
- def autocorrect(node)
38
- range = range_between(node.receiver.loc.selector.begin_pos,
39
- node.source_range.end_pos)
40
-
41
- ->(corrector) { corrector.replace(range, 'strip') }
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop identifies places where `sort_by { ... }` can be replaced by
7
- # `sort`.
8
- #
9
- # @example
10
- # # bad
11
- # array.sort_by { |x| x }
12
- # array.sort_by do |var|
13
- # var
14
- # end
15
- #
16
- # # good
17
- # array.sort
18
- class RedundantSortBy < Cop
19
- include RangeHelp
20
-
21
- MSG = 'Use `sort` instead of `sort_by { |%<var>s| %<var>s }`.'.freeze
22
-
23
- def_node_matcher :redundant_sort_by, <<-PATTERN
24
- (block $(send _ :sort_by) (args (arg $_x)) (lvar _x))
25
- PATTERN
26
-
27
- def on_block(node)
28
- redundant_sort_by(node) do |send, var_name|
29
- range = sort_by_range(send, node)
30
-
31
- add_offense(node,
32
- location: range,
33
- message: format(MSG, var: var_name))
34
- end
35
- end
36
-
37
- def autocorrect(node)
38
- send, = *node
39
- ->(corrector) { corrector.replace(sort_by_range(send, node), 'sort') }
40
- end
41
-
42
- private
43
-
44
- def sort_by_range(send, node)
45
- range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
46
- end
47
- end
48
- end
49
- end
50
- end
@@ -1,145 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop is used to identify usages of `shuffle.first`,
7
- # `shuffle.last`, and `shuffle[]` and change them to use
8
- # `sample` instead.
9
- #
10
- # @example
11
- # # bad
12
- # [1, 2, 3].shuffle.first
13
- # [1, 2, 3].shuffle.first(2)
14
- # [1, 2, 3].shuffle.last
15
- # [2, 1, 3].shuffle.at(0)
16
- # [2, 1, 3].shuffle.slice(0)
17
- # [1, 2, 3].shuffle[2]
18
- # [1, 2, 3].shuffle[0, 2] # sample(2) will do the same
19
- # [1, 2, 3].shuffle[0..2] # sample(3) will do the same
20
- # [1, 2, 3].shuffle(random: Random.new).first
21
- #
22
- # # good
23
- # [1, 2, 3].shuffle
24
- # [1, 2, 3].sample
25
- # [1, 2, 3].sample(3)
26
- # [1, 2, 3].shuffle[1, 3] # sample(3) might return a longer Array
27
- # [1, 2, 3].shuffle[1..3] # sample(3) might return a longer Array
28
- # [1, 2, 3].shuffle[foo, bar]
29
- # [1, 2, 3].shuffle(random: Random.new)
30
- class Sample < Cop
31
- MSG = 'Use `%<correct>s` instead of `%<incorrect>s`.'.freeze
32
-
33
- def_node_matcher :sample_candidate?, <<-PATTERN
34
- (send $(send _ :shuffle $...) ${:first :last :[] :at :slice} $...)
35
- PATTERN
36
-
37
- def on_send(node)
38
- sample_candidate?(node) do |shuffle, shuffle_arg, method, method_args|
39
- return unless offensive?(method, method_args)
40
-
41
- range = source_range(shuffle, node)
42
- message = message(shuffle_arg, method, method_args, range)
43
- add_offense(node, location: range, message: message)
44
- end
45
- end
46
-
47
- def autocorrect(node)
48
- shuffle_node, shuffle_arg, method, method_args =
49
- sample_candidate?(node)
50
-
51
- lambda do |corrector|
52
- corrector.replace(source_range(shuffle_node, node),
53
- correction(shuffle_arg, method, method_args))
54
- end
55
- end
56
-
57
- private
58
-
59
- def offensive?(method, method_args)
60
- case method
61
- when :first, :last
62
- true
63
- when :[], :at, :slice
64
- sample_size(method_args) != :unknown
65
- else
66
- false
67
- end
68
- end
69
-
70
- def sample_size(method_args)
71
- case method_args.size
72
- when 1
73
- sample_size_for_one_arg(method_args.first)
74
- when 2
75
- sample_size_for_two_args(*method_args)
76
- end
77
- end
78
-
79
- def sample_size_for_one_arg(arg)
80
- case arg.type
81
- when :erange, :irange
82
- range_size(arg)
83
- when :int
84
- [0, -1].include?(arg.to_a.first) ? nil : :unknown
85
- else
86
- :unknown
87
- end
88
- end
89
-
90
- def sample_size_for_two_args(first, second)
91
- return :unknown unless first.int_type? && first.to_a.first.zero?
92
-
93
- second.int_type? ? second.to_a.first : :unknown
94
- end
95
-
96
- def range_size(range_node)
97
- vals = range_node.to_a
98
- return :unknown unless vals.all?(&:int_type?)
99
-
100
- low, high = vals.map { |val| val.children[0] }
101
- return :unknown unless low.zero? && high >= 0
102
-
103
- case range_node.type
104
- when :erange
105
- (low...high).size
106
- when :irange
107
- (low..high).size
108
- end
109
- end
110
-
111
- def source_range(shuffle_node, node)
112
- Parser::Source::Range.new(shuffle_node.source_range.source_buffer,
113
- shuffle_node.loc.selector.begin_pos,
114
- node.source_range.end_pos)
115
- end
116
-
117
- def message(shuffle_arg, method, method_args, range)
118
- format(MSG,
119
- correct: correction(shuffle_arg, method, method_args),
120
- incorrect: range.source)
121
- end
122
-
123
- def correction(shuffle_arg, method, method_args)
124
- shuffle_arg = extract_source(shuffle_arg)
125
- sample_arg = sample_arg(method, method_args)
126
- args = [sample_arg, shuffle_arg].compact.join(', ')
127
- args.empty? ? 'sample' : "sample(#{args})"
128
- end
129
-
130
- def sample_arg(method, method_args)
131
- case method
132
- when :first, :last
133
- extract_source(method_args)
134
- when :[], :slice
135
- sample_size(method_args)
136
- end
137
- end
138
-
139
- def extract_source(args)
140
- args.empty? ? nil : args.first.source
141
- end
142
- end
143
- end
144
- end
145
- end
@@ -1,165 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Performance
6
- # This cop is used to identify instances of sorting and then
7
- # taking only the first or last element. The same behavior can
8
- # be accomplished without a relatively expensive sort by using
9
- # `Enumerable#min` instead of sorting and taking the first
10
- # element and `Enumerable#max` instead of sorting and taking the
11
- # last element. Similarly, `Enumerable#min_by` and
12
- # `Enumerable#max_by` can replace `Enumerable#sort_by` calls
13
- # after which only the first or last element is used.
14
- #
15
- # @example
16
- # # bad
17
- # [2, 1, 3].sort.first
18
- # [2, 1, 3].sort[0]
19
- # [2, 1, 3].sort.at(0)
20
- # [2, 1, 3].sort.slice(0)
21
- #
22
- # # good
23
- # [2, 1, 3].min
24
- #
25
- # # bad
26
- # [2, 1, 3].sort.last
27
- # [2, 1, 3].sort[-1]
28
- # [2, 1, 3].sort.at(-1)
29
- # [2, 1, 3].sort.slice(-1)
30
- #
31
- # # good
32
- # [2, 1, 3].max
33
- #
34
- # # bad
35
- # arr.sort_by(&:foo).first
36
- # arr.sort_by(&:foo)[0]
37
- # arr.sort_by(&:foo).at(0)
38
- # arr.sort_by(&:foo).slice(0)
39
- #
40
- # # good
41
- # arr.min_by(&:foo)
42
- #
43
- # # bad
44
- # arr.sort_by(&:foo).last
45
- # arr.sort_by(&:foo)[-1]
46
- # arr.sort_by(&:foo).at(-1)
47
- # arr.sort_by(&:foo).slice(-1)
48
- #
49
- # # good
50
- # arr.max_by(&:foo)
51
- #
52
- class UnneededSort < Cop
53
- include RangeHelp
54
-
55
- MSG = 'Use `%<suggestion>s` instead of '\
56
- '`%<sorter>s...%<accessor_source>s`.'.freeze
57
-
58
- def_node_matcher :unneeded_sort?, <<-MATCHER
59
- {
60
- (send $(send _ $:sort ...) ${:last :first})
61
- (send $(send _ $:sort ...) ${:[] :at :slice} {(int 0) (int -1)})
62
-
63
- (send $(send _ $:sort_by _) ${:last :first})
64
- (send $(send _ $:sort_by _) ${:[] :at :slice} {(int 0) (int -1)})
65
-
66
- (send (block $(send _ ${:sort_by :sort}) ...) ${:last :first})
67
- (send
68
- (block $(send _ ${:sort_by :sort}) ...)
69
- ${:[] :at :slice} {(int 0) (int -1)}
70
- )
71
- }
72
- MATCHER
73
-
74
- def on_send(node)
75
- unneeded_sort?(node) do |sort_node, sorter, accessor|
76
- range = range_between(
77
- sort_node.loc.selector.begin_pos,
78
- node.loc.expression.end_pos
79
- )
80
-
81
- add_offense(node,
82
- location: range,
83
- message: message(node,
84
- sorter,
85
- accessor))
86
- end
87
- end
88
-
89
- def autocorrect(node)
90
- sort_node, sorter, accessor = unneeded_sort?(node)
91
-
92
- lambda do |corrector|
93
- # Remove accessor, e.g. `first` or `[-1]`.
94
- corrector.remove(
95
- range_between(
96
- accessor_start(node),
97
- node.loc.expression.end_pos
98
- )
99
- )
100
-
101
- # Replace "sort" or "sort_by" with the appropriate min/max method.
102
- corrector.replace(
103
- sort_node.loc.selector,
104
- suggestion(sorter, accessor, arg_value(node))
105
- )
106
- end
107
- end
108
-
109
- private
110
-
111
- def message(node, sorter, accessor)
112
- accessor_source = range_between(
113
- node.loc.selector.begin_pos,
114
- node.loc.expression.end_pos
115
- ).source
116
-
117
- format(MSG,
118
- suggestion: suggestion(sorter,
119
- accessor,
120
- arg_value(node)),
121
- sorter: sorter,
122
- accessor_source: accessor_source)
123
- end
124
-
125
- def suggestion(sorter, accessor, arg)
126
- base(accessor, arg) + suffix(sorter)
127
- end
128
-
129
- def base(accessor, arg)
130
- if accessor == :first || (arg && arg.zero?)
131
- 'min'
132
- elsif accessor == :last || arg == -1
133
- 'max'
134
- end
135
- end
136
-
137
- def suffix(sorter)
138
- if sorter == :sort
139
- ''
140
- elsif sorter == :sort_by
141
- '_by'
142
- end
143
- end
144
-
145
- def arg_node(node)
146
- node.arguments.first
147
- end
148
-
149
- def arg_value(node)
150
- arg_node(node).nil? ? nil : arg_node(node).node_parts.first
151
- end
152
-
153
- # This gets the start of the accessor whether it has a dot
154
- # (e.g. `.first`) or doesn't (e.g. `[0]`)
155
- def accessor_start(node)
156
- if node.loc.dot
157
- node.loc.dot.begin_pos
158
- else
159
- node.loc.selector.begin_pos
160
- end
161
- end
162
- end
163
- end
164
- end
165
- end