rubocop-performance 1.6.1 → 1.9.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 +4 -4
- data/README.md +8 -0
- data/config/default.yml +95 -8
- data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +4 -4
- data/lib/rubocop/cop/mixin/sort_block.rb +28 -0
- data/lib/rubocop/cop/performance/ancestors_include.rb +49 -0
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +74 -0
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +46 -0
- data/lib/rubocop/cop/performance/bind_call.rb +9 -18
- data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +52 -0
- data/lib/rubocop/cop/performance/caller.rb +14 -15
- data/lib/rubocop/cop/performance/case_when_splat.rb +18 -11
- data/lib/rubocop/cop/performance/casecmp.rb +13 -20
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +4 -10
- data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +140 -0
- data/lib/rubocop/cop/performance/compare_with_block.rb +10 -21
- data/lib/rubocop/cop/performance/constant_regexp.rb +68 -0
- data/lib/rubocop/cop/performance/count.rb +14 -16
- data/lib/rubocop/cop/performance/delete_prefix.rb +14 -22
- data/lib/rubocop/cop/performance/delete_suffix.rb +14 -22
- data/lib/rubocop/cop/performance/detect.rb +65 -32
- data/lib/rubocop/cop/performance/double_start_end_with.rb +16 -24
- data/lib/rubocop/cop/performance/end_with.rb +9 -13
- data/lib/rubocop/cop/performance/fixed_size.rb +2 -1
- data/lib/rubocop/cop/performance/flat_map.rb +21 -22
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +15 -14
- data/lib/rubocop/cop/performance/io_readlines.rb +112 -0
- data/lib/rubocop/cop/performance/method_object_as_block.rb +32 -0
- data/lib/rubocop/cop/performance/open_struct.rb +3 -2
- data/lib/rubocop/cop/performance/range_include.rb +15 -11
- data/lib/rubocop/cop/performance/redundant_block_call.rb +15 -10
- data/lib/rubocop/cop/performance/redundant_match.rb +12 -6
- data/lib/rubocop/cop/performance/redundant_merge.rb +19 -17
- data/lib/rubocop/cop/performance/redundant_sort_block.rb +43 -0
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +129 -0
- data/lib/rubocop/cop/performance/regexp_match.rb +20 -20
- data/lib/rubocop/cop/performance/reverse_each.rb +10 -5
- data/lib/rubocop/cop/performance/reverse_first.rb +73 -0
- data/lib/rubocop/cop/performance/size.rb +42 -43
- data/lib/rubocop/cop/performance/sort_reverse.rb +45 -0
- data/lib/rubocop/cop/performance/squeeze.rb +67 -0
- data/lib/rubocop/cop/performance/start_with.rb +9 -13
- data/lib/rubocop/cop/performance/string_include.rb +56 -0
- data/lib/rubocop/cop/performance/string_replacement.rb +24 -27
- data/lib/rubocop/cop/performance/sum.rb +236 -0
- data/lib/rubocop/cop/performance/times_map.rb +12 -18
- data/lib/rubocop/cop/performance/unfreeze_string.rb +20 -2
- data/lib/rubocop/cop/performance/uri_default_parser.rb +7 -12
- data/lib/rubocop/cop/performance_cops.rb +16 -0
- data/lib/rubocop/performance/version.rb +6 -1
- metadata +35 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b44c147120a9f64f16a0bf21782f1dbe0a51c64170c3a5c217e548eded4e106
|
4
|
+
data.tar.gz: 7b4e6e464ee3631071f3bd3f447acde2a59763d326a86658412f4ec9527850a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e450740a348bd17e276af8393f4e8225521afc4c9fac5816c9a3bbd9883d16a15f28a1044e24b89c9037593f4d2931cf3dc900385d42d7ad035dbb1dd461a306
|
7
|
+
data.tar.gz: feef1ae1d9735d3abadf17799ecfb4840ce359fa932902387633e67dc15e1eeb62573ae0a2832c050a8722e004f614c109483a9d8857143f28c866dbd65bc5bf
|
data/README.md
CHANGED
@@ -76,6 +76,14 @@ Performance/Size:
|
|
76
76
|
|
77
77
|
You can read a lot more about RuboCop Performance in its [official docs](https://docs.rubocop.org/rubocop-performance/).
|
78
78
|
|
79
|
+
## Compatibility
|
80
|
+
|
81
|
+
RuboCop Performance complies with the RuboCop core compatibility.
|
82
|
+
|
83
|
+
See the [compatibility documentation](https://docs.rubocop.org/rubocop/compatibility.html) for further details.
|
84
|
+
|
85
|
+
**Note:** Performance cops are all MRI focused and are highly dependent of the version of MRI you're using.
|
86
|
+
|
79
87
|
## Contributing
|
80
88
|
|
81
89
|
Checkout the [contribution guidelines](CONTRIBUTING.md).
|
data/config/default.yml
CHANGED
@@ -1,15 +1,38 @@
|
|
1
1
|
# This is the default configuration file.
|
2
2
|
|
3
|
+
Performance/AncestorsInclude:
|
4
|
+
Description: 'Use `A <= B` instead of `A.ancestors.include?(B)`.'
|
5
|
+
Reference: 'https://github.com/JuanitoFatas/fast-ruby#ancestorsinclude-vs--code'
|
6
|
+
Enabled: 'pending'
|
7
|
+
Safe: false
|
8
|
+
VersionAdded: '1.7'
|
9
|
+
|
10
|
+
Performance/ArraySemiInfiniteRangeSlice:
|
11
|
+
Description: 'Identifies places where slicing arrays with semi-infinite ranges can be replaced by `Array#take` and `Array#drop`.'
|
12
|
+
Enabled: pending
|
13
|
+
VersionAdded: '1.9'
|
14
|
+
|
15
|
+
Performance/BigDecimalWithNumericArgument:
|
16
|
+
Description: 'Convert numeric argument to string before passing to BigDecimal.'
|
17
|
+
Enabled: 'pending'
|
18
|
+
VersionAdded: '1.7'
|
19
|
+
|
3
20
|
Performance/BindCall:
|
4
21
|
Description: 'Use `bind_call(obj, args, ...)` instead of `bind(obj).call(args, ...)`.'
|
5
22
|
Enabled: true
|
6
23
|
VersionAdded: '1.6'
|
7
24
|
|
25
|
+
Performance/BlockGivenWithExplicitBlock:
|
26
|
+
Description: 'Check block argument explicitly instead of using `block_given?`.'
|
27
|
+
Enabled: pending
|
28
|
+
VersionAdded: '1.9'
|
29
|
+
|
8
30
|
Performance/Caller:
|
9
31
|
Description: >-
|
10
32
|
Use `caller(n..n)` instead of `caller`.
|
11
33
|
Enabled: true
|
12
34
|
VersionAdded: '0.49'
|
35
|
+
VersionChanged: '1.9'
|
13
36
|
|
14
37
|
Performance/CaseWhenSplat:
|
15
38
|
Description: >-
|
@@ -37,23 +60,33 @@ Performance/ChainArrayAllocation:
|
|
37
60
|
Enabled: false
|
38
61
|
VersionAdded: '0.59'
|
39
62
|
|
63
|
+
Performance/CollectionLiteralInLoop:
|
64
|
+
Description: 'Extract Array and Hash literals outside of loops into local variables or constants.'
|
65
|
+
Enabled: 'pending'
|
66
|
+
VersionAdded: '1.8'
|
67
|
+
# Min number of elements to consider an offense
|
68
|
+
MinSize: 1
|
69
|
+
|
40
70
|
Performance/CompareWithBlock:
|
41
71
|
Description: 'Use `sort_by(&:foo)` instead of `sort { |a, b| a.foo <=> b.foo }`.'
|
42
72
|
Enabled: true
|
43
73
|
VersionAdded: '0.46'
|
44
74
|
|
75
|
+
Performance/ConstantRegexp:
|
76
|
+
Description: 'Finds regular expressions with dynamic components that are all constants.'
|
77
|
+
Enabled: pending
|
78
|
+
VersionAdded: '1.9'
|
79
|
+
|
45
80
|
Performance/Count:
|
46
81
|
Description: >-
|
47
|
-
Use `count` instead of `select
|
48
|
-
`select...count`, `reject...count`, `select...length`,
|
49
|
-
and `reject...length`.
|
82
|
+
Use `count` instead of `{select,find_all,filter,reject}...{size,count,length}`.
|
50
83
|
# This cop has known compatibility issues with `ActiveRecord` and other
|
51
84
|
# frameworks. ActiveRecord's `count` ignores the block that is passed to it.
|
52
85
|
# For more information, see the documentation in the cop itself.
|
53
86
|
SafeAutoCorrect: false
|
54
87
|
Enabled: true
|
55
88
|
VersionAdded: '0.31'
|
56
|
-
VersionChanged: '1.
|
89
|
+
VersionChanged: '1.8'
|
57
90
|
|
58
91
|
Performance/DeletePrefix:
|
59
92
|
Description: 'Use `delete_prefix` instead of `gsub`.'
|
@@ -69,8 +102,8 @@ Performance/DeleteSuffix:
|
|
69
102
|
|
70
103
|
Performance/Detect:
|
71
104
|
Description: >-
|
72
|
-
Use `detect` instead of `select.first`, `find_all.first`,
|
73
|
-
`select.last`, and `
|
105
|
+
Use `detect` instead of `select.first`, `find_all.first`, `filter.first`,
|
106
|
+
`select.last`, `find_all.last`, and `filter.last`.
|
74
107
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
|
75
108
|
# This cop has known compatibility issues with `ActiveRecord` and other
|
76
109
|
# frameworks. `ActiveRecord` does not implement a `detect` method and `find`
|
@@ -79,7 +112,7 @@ Performance/Detect:
|
|
79
112
|
SafeAutoCorrect: false
|
80
113
|
Enabled: true
|
81
114
|
VersionAdded: '0.30'
|
82
|
-
VersionChanged: '1.
|
115
|
+
VersionChanged: '1.8'
|
83
116
|
|
84
117
|
Performance/DoubleStartEndWith:
|
85
118
|
Description: >-
|
@@ -131,6 +164,18 @@ Performance/InefficientHashSearch:
|
|
131
164
|
VersionAdded: '0.56'
|
132
165
|
Safe: false
|
133
166
|
|
167
|
+
Performance/IoReadlines:
|
168
|
+
Description: 'Use `IO.each_line` (`IO#each_line`) instead of `IO.readlines` (`IO#readlines`).'
|
169
|
+
Reference: 'https://docs.gitlab.com/ee/development/performance.html#reading-from-files-and-other-data-sources'
|
170
|
+
Enabled: false
|
171
|
+
VersionAdded: '1.7'
|
172
|
+
|
173
|
+
Performance/MethodObjectAsBlock:
|
174
|
+
Description: 'Use block explicitly instead of block-passing a method object.'
|
175
|
+
Reference: 'https://github.com/JuanitoFatas/fast-ruby#normal-way-to-apply-method-vs-method-code'
|
176
|
+
Enabled: pending
|
177
|
+
VersionAdded: '1.9'
|
178
|
+
|
134
179
|
Performance/OpenStruct:
|
135
180
|
Description: 'Use `Struct` instead of `OpenStruct`.'
|
136
181
|
Enabled: false
|
@@ -138,10 +183,11 @@ Performance/OpenStruct:
|
|
138
183
|
Safe: false
|
139
184
|
|
140
185
|
Performance/RangeInclude:
|
141
|
-
Description: 'Use `Range#cover?` instead of `Range#include
|
186
|
+
Description: 'Use `Range#cover?` instead of `Range#include?` (or `Range#member?`).'
|
142
187
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#cover-vs-include-code'
|
143
188
|
Enabled: true
|
144
189
|
VersionAdded: '0.36'
|
190
|
+
VersionChanged: '1.7'
|
145
191
|
Safe: false
|
146
192
|
|
147
193
|
Performance/RedundantBlockCall:
|
@@ -165,6 +211,16 @@ Performance/RedundantMerge:
|
|
165
211
|
# Max number of key-value pairs to consider an offense
|
166
212
|
MaxKeyValuePairs: 2
|
167
213
|
|
214
|
+
Performance/RedundantSortBlock:
|
215
|
+
Description: 'Use `sort` instead of `sort { |a, b| a <=> b }`.'
|
216
|
+
Enabled: 'pending'
|
217
|
+
VersionAdded: '1.7'
|
218
|
+
|
219
|
+
Performance/RedundantStringChars:
|
220
|
+
Description: 'Checks for redundant `String#chars`.'
|
221
|
+
Enabled: 'pending'
|
222
|
+
VersionAdded: '1.7'
|
223
|
+
|
168
224
|
Performance/RegexpMatch:
|
169
225
|
Description: >-
|
170
226
|
Use `match?` instead of `Regexp#match`, `String#match`, `Symbol#match`,
|
@@ -179,6 +235,11 @@ Performance/ReverseEach:
|
|
179
235
|
Enabled: true
|
180
236
|
VersionAdded: '0.30'
|
181
237
|
|
238
|
+
Performance/ReverseFirst:
|
239
|
+
Description: 'Use `last(n).reverse` instead of `reverse.first(n)`.'
|
240
|
+
Enabled: 'pending'
|
241
|
+
VersionAdded: '1.7'
|
242
|
+
|
182
243
|
Performance/Size:
|
183
244
|
Description: >-
|
184
245
|
Use `size` instead of `count` for counting
|
@@ -187,6 +248,17 @@ Performance/Size:
|
|
187
248
|
Enabled: true
|
188
249
|
VersionAdded: '0.30'
|
189
250
|
|
251
|
+
Performance/SortReverse:
|
252
|
+
Description: 'Use `sort.reverse` instead of `sort { |a, b| b <=> a }`.'
|
253
|
+
Enabled: 'pending'
|
254
|
+
VersionAdded: '1.7'
|
255
|
+
|
256
|
+
Performance/Squeeze:
|
257
|
+
Description: "Use `squeeze('a')` instead of `gsub(/a+/, 'a')`."
|
258
|
+
Reference: 'https://github.com/JuanitoFatas/fast-ruby#remove-extra-spaces-or-other-contiguous-characters-code'
|
259
|
+
Enabled: 'pending'
|
260
|
+
VersionAdded: '1.7'
|
261
|
+
|
190
262
|
Performance/StartWith:
|
191
263
|
Description: 'Use `start_with?` instead of a regex match anchored to the beginning of a string.'
|
192
264
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
|
@@ -200,6 +272,13 @@ Performance/StartWith:
|
|
200
272
|
VersionAdded: '0.36'
|
201
273
|
VersionChanged: '1.6'
|
202
274
|
|
275
|
+
Performance/StringInclude:
|
276
|
+
Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
|
277
|
+
Enabled: 'pending'
|
278
|
+
AutoCorrect: false
|
279
|
+
SafeAutoCorrect: false
|
280
|
+
VersionAdded: '1.7'
|
281
|
+
|
203
282
|
Performance/StringReplacement:
|
204
283
|
Description: >-
|
205
284
|
Use `tr` instead of `gsub` when you are replacing the same
|
@@ -209,6 +288,12 @@ Performance/StringReplacement:
|
|
209
288
|
Enabled: true
|
210
289
|
VersionAdded: '0.33'
|
211
290
|
|
291
|
+
Performance/Sum:
|
292
|
+
Description: 'Use `sum` instead of a custom array summation.'
|
293
|
+
Reference: 'https://blog.bigbinary.com/2016/11/02/ruby-2-4-introduces-enumerable-sum.html'
|
294
|
+
Enabled: 'pending'
|
295
|
+
VersionAdded: '1.8'
|
296
|
+
|
212
297
|
Performance/TimesMap:
|
213
298
|
Description: 'Checks for .times.map calls.'
|
214
299
|
AutoCorrect: false
|
@@ -220,7 +305,9 @@ Performance/TimesMap:
|
|
220
305
|
Performance/UnfreezeString:
|
221
306
|
Description: 'Use unary plus to get an unfrozen string literal.'
|
222
307
|
Enabled: true
|
308
|
+
SafeAutoCorrect: false
|
223
309
|
VersionAdded: '0.50'
|
310
|
+
VersionChanged: '1.9'
|
224
311
|
|
225
312
|
Performance/UriDefaultParser:
|
226
313
|
Description: 'Use `URI::DEFAULT_PARSER` instead of `URI::Parser.new`.'
|
@@ -25,7 +25,7 @@ module RuboCop
|
|
25
25
|
# (tricky: \s, \d, and so on are metacharacters, but other characters
|
26
26
|
# escaped with a slash are just literals. LITERAL_REGEX takes all
|
27
27
|
# that into account.)
|
28
|
-
/\A\\A(?:#{Util::LITERAL_REGEX})+\z
|
28
|
+
/\A\\A(?:#{Util::LITERAL_REGEX})+\z/o.match?(regex_str)
|
29
29
|
end
|
30
30
|
|
31
31
|
def literal_at_start_with_caret?(regex_str)
|
@@ -35,21 +35,21 @@ module RuboCop
|
|
35
35
|
# (tricky: \s, \d, and so on are metacharacters, but other characters
|
36
36
|
# escaped with a slash are just literals. LITERAL_REGEX takes all
|
37
37
|
# that into account.)
|
38
|
-
/\A\^(?:#{Util::LITERAL_REGEX})+\z
|
38
|
+
/\A\^(?:#{Util::LITERAL_REGEX})+\z/o.match?(regex_str)
|
39
39
|
end
|
40
40
|
|
41
41
|
def literal_at_end_with_backslash_z?(regex_str)
|
42
42
|
# is this regexp 'literal' in the sense of only matching literal
|
43
43
|
# chars, rather than using metachars like . and * and so on?
|
44
44
|
# also, is it anchored at the end of the string?
|
45
|
-
/\A(?:#{Util::LITERAL_REGEX})+\\z\z
|
45
|
+
/\A(?:#{Util::LITERAL_REGEX})+\\z\z/o.match?(regex_str)
|
46
46
|
end
|
47
47
|
|
48
48
|
def literal_at_end_with_dollar?(regex_str)
|
49
49
|
# is this regexp 'literal' in the sense of only matching literal
|
50
50
|
# chars, rather than using metachars like . and * and so on?
|
51
51
|
# also, is it anchored at the end of the string?
|
52
|
-
/\A(?:#{Util::LITERAL_REGEX})+\$\z
|
52
|
+
/\A(?:#{Util::LITERAL_REGEX})+\$\z/o.match?(regex_str)
|
53
53
|
end
|
54
54
|
|
55
55
|
def drop_start_metacharacter(regexp_string)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for cops checking `Enumerable#sort` blocks.
|
6
|
+
module SortBlock
|
7
|
+
extend NodePattern::Macros
|
8
|
+
include RangeHelp
|
9
|
+
|
10
|
+
def_node_matcher :sort_with_block?, <<~PATTERN
|
11
|
+
(block
|
12
|
+
$(send _ :sort)
|
13
|
+
(args (arg $_a) (arg $_b))
|
14
|
+
$send)
|
15
|
+
PATTERN
|
16
|
+
|
17
|
+
def_node_matcher :replaceable_body?, <<~PATTERN
|
18
|
+
(send (lvar %1) :<=> (lvar %2))
|
19
|
+
PATTERN
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def sort_range(send, node)
|
24
|
+
range_between(send.loc.selector.begin_pos, node.loc.end.end_pos)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop is used to identify usages of `ancestors.include?` and
|
7
|
+
# change them to use `<=` instead.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# A.ancestors.include?(B)
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# A <= B
|
15
|
+
#
|
16
|
+
class AncestorsInclude < Base
|
17
|
+
include RangeHelp
|
18
|
+
extend AutoCorrector
|
19
|
+
|
20
|
+
MSG = 'Use `<=` instead of `ancestors.include?`.'
|
21
|
+
RESTRICT_ON_SEND = %i[include?].freeze
|
22
|
+
|
23
|
+
def_node_matcher :ancestors_include_candidate?, <<~PATTERN
|
24
|
+
(send (send $_subclass :ancestors) :include? $_superclass)
|
25
|
+
PATTERN
|
26
|
+
|
27
|
+
def on_send(node)
|
28
|
+
return unless (subclass, superclass = ancestors_include_candidate?(node))
|
29
|
+
return if subclass && !subclass.const_type?
|
30
|
+
|
31
|
+
add_offense(range(node)) do |corrector|
|
32
|
+
subclass_source = subclass ? subclass.source : 'self'
|
33
|
+
|
34
|
+
corrector.replace(node, "#{subclass_source} <= #{superclass.source}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def range(node)
|
41
|
+
location_of_ancestors = node.children[0].loc.selector.begin_pos
|
42
|
+
end_location = node.loc.selector.end_pos
|
43
|
+
|
44
|
+
range_between(location_of_ancestors, end_location)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop identifies places where slicing arrays with semi-infinite ranges
|
7
|
+
# can be replaced by `Array#take` and `Array#drop`.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# # array[..2]
|
12
|
+
# # array[...2]
|
13
|
+
# # array[2..]
|
14
|
+
# # array[2...]
|
15
|
+
# # array.slice(..2)
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# array.take(3)
|
19
|
+
# array.take(2)
|
20
|
+
# array.drop(2)
|
21
|
+
# array.drop(2)
|
22
|
+
# array.take(3)
|
23
|
+
#
|
24
|
+
class ArraySemiInfiniteRangeSlice < Base
|
25
|
+
include RangeHelp
|
26
|
+
extend AutoCorrector
|
27
|
+
extend TargetRubyVersion
|
28
|
+
|
29
|
+
minimum_target_ruby_version 2.7
|
30
|
+
|
31
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s` with semi-infinite range.'
|
32
|
+
|
33
|
+
SLICE_METHODS = Set[:[], :slice].freeze
|
34
|
+
RESTRICT_ON_SEND = SLICE_METHODS
|
35
|
+
|
36
|
+
def_node_matcher :endless_range_slice?, <<~PATTERN
|
37
|
+
(send $_ $%SLICE_METHODS $#endless_range?)
|
38
|
+
PATTERN
|
39
|
+
|
40
|
+
def_node_matcher :endless_range?, <<~PATTERN
|
41
|
+
{
|
42
|
+
({irange erange} nil? (int positive?))
|
43
|
+
({irange erange} (int positive?) nil?)
|
44
|
+
}
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
def on_send(node)
|
48
|
+
endless_range_slice?(node) do |receiver, method_name, range_node|
|
49
|
+
prefer = range_node.begin ? :drop : :take
|
50
|
+
message = format(MSG, prefer: prefer, current: method_name)
|
51
|
+
|
52
|
+
add_offense(node, message: message) do |corrector|
|
53
|
+
corrector.replace(node, correction(receiver, range_node))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def correction(receiver, range_node)
|
61
|
+
method_call = if range_node.begin
|
62
|
+
"drop(#{range_node.begin.value})"
|
63
|
+
elsif range_node.irange_type?
|
64
|
+
"take(#{range_node.end.value + 1})"
|
65
|
+
else
|
66
|
+
"take(#{range_node.end.value})"
|
67
|
+
end
|
68
|
+
|
69
|
+
"#{receiver.source}.#{method_call}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop identifies places where numeric argument to BigDecimal should be
|
7
|
+
# converted to string. Initializing from String is faster
|
8
|
+
# than from Numeric for BigDecimal.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# BigDecimal(1, 2)
|
13
|
+
# BigDecimal(1.2, 3, exception: true)
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# BigDecimal('1', 2)
|
17
|
+
# BigDecimal('1.2', 3, exception: true)
|
18
|
+
#
|
19
|
+
class BigDecimalWithNumericArgument < Base
|
20
|
+
extend AutoCorrector
|
21
|
+
|
22
|
+
MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'
|
23
|
+
RESTRICT_ON_SEND = %i[BigDecimal].freeze
|
24
|
+
|
25
|
+
def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
|
26
|
+
(send nil? :BigDecimal $numeric_type? ...)
|
27
|
+
PATTERN
|
28
|
+
|
29
|
+
def on_send(node)
|
30
|
+
return unless (numeric = big_decimal_with_numeric_argument?(node))
|
31
|
+
return if numeric.float_type? && specifies_precision?(node)
|
32
|
+
|
33
|
+
add_offense(numeric.source_range) do |corrector|
|
34
|
+
corrector.wrap(numeric, "'", "'")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def specifies_precision?(node)
|
41
|
+
node.arguments.size > 1 && !node.arguments[1].hash_type?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|