rubocop-performance 1.0.0 → 1.1.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: 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