rubocop-performance 1.8.1 → 1.10.1
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/LICENSE.txt +1 -1
- data/README.md +10 -2
- data/config/default.yml +47 -6
- data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +4 -4
- data/lib/rubocop/cop/performance/ancestors_include.rb +1 -0
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +77 -0
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +1 -0
- data/lib/rubocop/cop/performance/bind_call.rb +3 -2
- data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +52 -0
- data/lib/rubocop/cop/performance/caller.rb +13 -15
- data/lib/rubocop/cop/performance/casecmp.rb +1 -0
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +20 -18
- data/lib/rubocop/cop/performance/constant_regexp.rb +73 -0
- data/lib/rubocop/cop/performance/count.rb +1 -0
- data/lib/rubocop/cop/performance/delete_prefix.rb +1 -0
- data/lib/rubocop/cop/performance/delete_suffix.rb +1 -0
- data/lib/rubocop/cop/performance/detect.rb +3 -2
- data/lib/rubocop/cop/performance/end_with.rb +1 -0
- data/lib/rubocop/cop/performance/fixed_size.rb +1 -0
- data/lib/rubocop/cop/performance/flat_map.rb +1 -0
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +2 -0
- data/lib/rubocop/cop/performance/io_readlines.rb +3 -7
- data/lib/rubocop/cop/performance/method_object_as_block.rb +32 -0
- data/lib/rubocop/cop/performance/open_struct.rb +1 -0
- data/lib/rubocop/cop/performance/range_include.rb +1 -0
- data/lib/rubocop/cop/performance/redundant_block_call.rb +4 -4
- data/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb +80 -0
- data/lib/rubocop/cop/performance/redundant_match.rb +1 -0
- data/lib/rubocop/cop/performance/redundant_merge.rb +1 -0
- data/lib/rubocop/cop/performance/redundant_split_regexp_argument.rb +64 -0
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +2 -6
- data/lib/rubocop/cop/performance/reverse_each.rb +7 -10
- data/lib/rubocop/cop/performance/reverse_first.rb +1 -0
- data/lib/rubocop/cop/performance/size.rb +1 -0
- data/lib/rubocop/cop/performance/squeeze.rb +2 -1
- data/lib/rubocop/cop/performance/start_with.rb +1 -0
- data/lib/rubocop/cop/performance/string_include.rb +2 -1
- data/lib/rubocop/cop/performance/string_replacement.rb +1 -0
- data/lib/rubocop/cop/performance/sum.rb +123 -15
- data/lib/rubocop/cop/performance/times_map.rb +1 -0
- data/lib/rubocop/cop/performance/unfreeze_string.rb +19 -1
- data/lib/rubocop/cop/performance/uri_default_parser.rb +1 -0
- data/lib/rubocop/cop/performance_cops.rb +6 -0
- data/lib/rubocop/performance/version.rb +6 -1
- metadata +25 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 026fa40bed33c9e7867599f1024ddf6c1ab430b00beae5f5ec52d9b32f5adef9
|
4
|
+
data.tar.gz: d0997dd1a5255e217f5faf2adc4f27b64a43266ff24264aa80307b474cbfa936
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a09ace7478bf3d87dc35897bb677c802c6b191ce0206e1b94e04826091ce8075ad9f267cd7805cd68ba3476c679e3cdb59c219fd71760ac4756c26a209c51bc
|
7
|
+
data.tar.gz: f9ccef454d4c9ff9a8d67db5276d2249d03a2882b169abfc5d4bacc28f9f09391edb15100750480c354fe9cc161463156169f216d482c9504f7d6a17da524a0c
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# RuboCop Performance
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/rubocop-performance)
|
4
|
-
[](https://circleci.com/gh/rubocop/rubocop-performance)
|
5
5
|
|
6
|
-
Performance optimization analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop
|
6
|
+
Performance optimization analysis for your projects, as an extension to [RuboCop](https://github.com/rubocop/rubocop).
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -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
@@ -7,6 +7,15 @@ Performance/AncestorsInclude:
|
|
7
7
|
Safe: false
|
8
8
|
VersionAdded: '1.7'
|
9
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
|
+
# This cop was created due to a mistake in microbenchmark.
|
13
|
+
# Refer https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717
|
14
|
+
Enabled: false
|
15
|
+
# Unsafe for string slices because strings do not have `#take` and `#drop` methods.
|
16
|
+
Safe: false
|
17
|
+
VersionAdded: '1.9'
|
18
|
+
|
10
19
|
Performance/BigDecimalWithNumericArgument:
|
11
20
|
Description: 'Convert numeric argument to string before passing to BigDecimal.'
|
12
21
|
Enabled: 'pending'
|
@@ -17,11 +26,17 @@ Performance/BindCall:
|
|
17
26
|
Enabled: true
|
18
27
|
VersionAdded: '1.6'
|
19
28
|
|
29
|
+
Performance/BlockGivenWithExplicitBlock:
|
30
|
+
Description: 'Check block argument explicitly instead of using `block_given?`.'
|
31
|
+
Enabled: pending
|
32
|
+
VersionAdded: '1.9'
|
33
|
+
|
20
34
|
Performance/Caller:
|
21
35
|
Description: >-
|
22
36
|
Use `caller(n..n)` instead of `caller`.
|
23
37
|
Enabled: true
|
24
38
|
VersionAdded: '0.49'
|
39
|
+
VersionChanged: '1.9'
|
25
40
|
|
26
41
|
Performance/CaseWhenSplat:
|
27
42
|
Description: >-
|
@@ -51,7 +66,7 @@ Performance/ChainArrayAllocation:
|
|
51
66
|
|
52
67
|
Performance/CollectionLiteralInLoop:
|
53
68
|
Description: 'Extract Array and Hash literals outside of loops into local variables or constants.'
|
54
|
-
Enabled:
|
69
|
+
Enabled: 'pending'
|
55
70
|
VersionAdded: '1.8'
|
56
71
|
# Min number of elements to consider an offense
|
57
72
|
MinSize: 1
|
@@ -61,6 +76,12 @@ Performance/CompareWithBlock:
|
|
61
76
|
Enabled: true
|
62
77
|
VersionAdded: '0.46'
|
63
78
|
|
79
|
+
Performance/ConstantRegexp:
|
80
|
+
Description: 'Finds regular expressions with dynamic components that are all constants.'
|
81
|
+
Enabled: pending
|
82
|
+
VersionAdded: '1.9'
|
83
|
+
VersionChanged: '1.10'
|
84
|
+
|
64
85
|
Performance/Count:
|
65
86
|
Description: >-
|
66
87
|
Use `count` instead of `{select,find_all,filter,reject}...{size,count,length}`.
|
@@ -116,11 +137,10 @@ Performance/EndWith:
|
|
116
137
|
# object. Switching these methods has to be done with knowledge of the types
|
117
138
|
# of the variables which rubocop doesn't have.
|
118
139
|
SafeAutoCorrect: false
|
119
|
-
AutoCorrect: false
|
120
140
|
Enabled: true
|
121
141
|
SafeMultiline: true
|
122
142
|
VersionAdded: '0.36'
|
123
|
-
VersionChanged: '1.
|
143
|
+
VersionChanged: '1.10'
|
124
144
|
|
125
145
|
Performance/FixedSize:
|
126
146
|
Description: 'Do not compute the size of statically sized objects except in constants.'
|
@@ -154,6 +174,12 @@ Performance/IoReadlines:
|
|
154
174
|
Enabled: false
|
155
175
|
VersionAdded: '1.7'
|
156
176
|
|
177
|
+
Performance/MethodObjectAsBlock:
|
178
|
+
Description: 'Use block explicitly instead of block-passing a method object.'
|
179
|
+
Reference: 'https://github.com/JuanitoFatas/fast-ruby#normal-way-to-apply-method-vs-method-code'
|
180
|
+
Enabled: pending
|
181
|
+
VersionAdded: '1.9'
|
182
|
+
|
157
183
|
Performance/OpenStruct:
|
158
184
|
Description: 'Use `Struct` instead of `OpenStruct`.'
|
159
185
|
Enabled: false
|
@@ -174,6 +200,15 @@ Performance/RedundantBlockCall:
|
|
174
200
|
Enabled: true
|
175
201
|
VersionAdded: '0.36'
|
176
202
|
|
203
|
+
Performance/RedundantEqualityComparisonBlock:
|
204
|
+
Description: >-
|
205
|
+
Checks for uses `Enumerable#all?`, `Enumerable#any?`, `Enumerable#one?`,
|
206
|
+
or `Enumerable#none?` are compared with `===` or similar methods in block.
|
207
|
+
Reference: 'https://github.com/rails/rails/pull/41363'
|
208
|
+
Enabled: pending
|
209
|
+
Safe: false
|
210
|
+
VersionAdded: '1.10'
|
211
|
+
|
177
212
|
Performance/RedundantMatch:
|
178
213
|
Description: >-
|
179
214
|
Use `=~` instead of `String#match` or `Regexp#match` in a context where the
|
@@ -194,6 +229,11 @@ Performance/RedundantSortBlock:
|
|
194
229
|
Enabled: 'pending'
|
195
230
|
VersionAdded: '1.7'
|
196
231
|
|
232
|
+
Performance/RedundantSplitRegexpArgument:
|
233
|
+
Description: 'This cop identifies places where `split` argument can be replaced from a deterministic regexp to a string.'
|
234
|
+
Enabled: pending
|
235
|
+
VersionAdded: '1.10'
|
236
|
+
|
197
237
|
Performance/RedundantStringChars:
|
198
238
|
Description: 'Checks for redundant `String#chars`.'
|
199
239
|
Enabled: 'pending'
|
@@ -244,11 +284,10 @@ Performance/StartWith:
|
|
244
284
|
# object. Switching these methods has to be done with knowledge of the types
|
245
285
|
# of the variables which rubocop doesn't have.
|
246
286
|
SafeAutoCorrect: false
|
247
|
-
AutoCorrect: false
|
248
287
|
Enabled: true
|
249
288
|
SafeMultiline: true
|
250
289
|
VersionAdded: '0.36'
|
251
|
-
VersionChanged: '1.
|
290
|
+
VersionChanged: '1.10'
|
252
291
|
|
253
292
|
Performance/StringInclude:
|
254
293
|
Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
|
@@ -278,12 +317,14 @@ Performance/TimesMap:
|
|
278
317
|
Enabled: true
|
279
318
|
VersionAdded: '0.36'
|
280
319
|
VersionChanged: '0.50'
|
281
|
-
SafeAutoCorrect: false # see https://github.com/rubocop
|
320
|
+
SafeAutoCorrect: false # see https://github.com/rubocop/rubocop/issues/4658
|
282
321
|
|
283
322
|
Performance/UnfreezeString:
|
284
323
|
Description: 'Use unary plus to get an unfrozen string literal.'
|
285
324
|
Enabled: true
|
325
|
+
SafeAutoCorrect: false
|
286
326
|
VersionAdded: '0.50'
|
327
|
+
VersionChanged: '1.9'
|
287
328
|
|
288
329
|
Performance/UriDefaultParser:
|
289
330
|
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)
|
@@ -18,6 +18,7 @@ module RuboCop
|
|
18
18
|
extend AutoCorrector
|
19
19
|
|
20
20
|
MSG = 'Use `<=` instead of `ancestors.include?`.'
|
21
|
+
RESTRICT_ON_SEND = %i[include?].freeze
|
21
22
|
|
22
23
|
def_node_matcher :ancestors_include_candidate?, <<~PATTERN
|
23
24
|
(send (send $_subclass :ancestors) :include? $_superclass)
|
@@ -0,0 +1,77 @@
|
|
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
|
+
# This cop was created due to a mistake in microbenchmark and hence is disabled by default.
|
9
|
+
# Refer https://github.com/rubocop/rubocop-performance/pull/175#issuecomment-731892717
|
10
|
+
# This cop is also unsafe for string slices because strings do not have `#take` and `#drop` methods.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# # bad
|
14
|
+
# # array[..2]
|
15
|
+
# # array[...2]
|
16
|
+
# # array[2..]
|
17
|
+
# # array[2...]
|
18
|
+
# # array.slice(..2)
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# array.take(3)
|
22
|
+
# array.take(2)
|
23
|
+
# array.drop(2)
|
24
|
+
# array.drop(2)
|
25
|
+
# array.take(3)
|
26
|
+
#
|
27
|
+
class ArraySemiInfiniteRangeSlice < Base
|
28
|
+
include RangeHelp
|
29
|
+
extend AutoCorrector
|
30
|
+
extend TargetRubyVersion
|
31
|
+
|
32
|
+
minimum_target_ruby_version 2.7
|
33
|
+
|
34
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s` with semi-infinite range.'
|
35
|
+
|
36
|
+
SLICE_METHODS = Set[:[], :slice].freeze
|
37
|
+
RESTRICT_ON_SEND = SLICE_METHODS
|
38
|
+
|
39
|
+
def_node_matcher :endless_range_slice?, <<~PATTERN
|
40
|
+
(send $_ $%SLICE_METHODS $#endless_range?)
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def_node_matcher :endless_range?, <<~PATTERN
|
44
|
+
{
|
45
|
+
({irange erange} nil? (int positive?))
|
46
|
+
({irange erange} (int positive?) nil?)
|
47
|
+
}
|
48
|
+
PATTERN
|
49
|
+
|
50
|
+
def on_send(node)
|
51
|
+
endless_range_slice?(node) do |receiver, method_name, range_node|
|
52
|
+
prefer = range_node.begin ? :drop : :take
|
53
|
+
message = format(MSG, prefer: prefer, current: method_name)
|
54
|
+
|
55
|
+
add_offense(node, message: message) do |corrector|
|
56
|
+
corrector.replace(node, correction(receiver, range_node))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def correction(receiver, range_node)
|
64
|
+
method_call = if range_node.begin
|
65
|
+
"drop(#{range_node.begin.value})"
|
66
|
+
elsif range_node.irange_type?
|
67
|
+
"take(#{range_node.end.value + 1})"
|
68
|
+
else
|
69
|
+
"take(#{range_node.end.value})"
|
70
|
+
end
|
71
|
+
|
72
|
+
"#{receiver.source}.#{method_call}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -20,6 +20,7 @@ module RuboCop
|
|
20
20
|
extend AutoCorrector
|
21
21
|
|
22
22
|
MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'
|
23
|
+
RESTRICT_ON_SEND = %i[BigDecimal].freeze
|
23
24
|
|
24
25
|
def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
|
25
26
|
(send nil? :BigDecimal $numeric_type? ...)
|
@@ -28,11 +28,12 @@ module RuboCop
|
|
28
28
|
|
29
29
|
MSG = 'Use `bind_call(%<bind_arg>s%<comma>s%<call_args>s)` ' \
|
30
30
|
'instead of `bind(%<bind_arg>s).call(%<call_args>s)`.'
|
31
|
+
RESTRICT_ON_SEND = %i[call].freeze
|
31
32
|
|
32
33
|
def_node_matcher :bind_with_call_method?, <<~PATTERN
|
33
34
|
(send
|
34
35
|
$(send
|
35
|
-
|
36
|
+
_ :bind
|
36
37
|
$(...)) :call
|
37
38
|
$...)
|
38
39
|
PATTERN
|
@@ -63,7 +64,7 @@ module RuboCop
|
|
63
64
|
|
64
65
|
def correction_range(receiver, node)
|
65
66
|
location_of_bind = receiver.loc.selector.begin_pos
|
66
|
-
location_of_call = node.
|
67
|
+
location_of_call = node.source_range.end.end_pos
|
67
68
|
|
68
69
|
range_between(location_of_bind, location_of_call)
|
69
70
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop identifies unnecessary use of a `block_given?` where explicit check
|
7
|
+
# of block argument would suffice.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# def method(&block)
|
12
|
+
# do_something if block_given?
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# def method(&block)
|
17
|
+
# do_something if block
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good - block is reassigned
|
21
|
+
# def method(&block)
|
22
|
+
# block ||= -> { do_something }
|
23
|
+
# warn "Using default ..." unless block_given?
|
24
|
+
# # ...
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
class BlockGivenWithExplicitBlock < Base
|
28
|
+
extend AutoCorrector
|
29
|
+
|
30
|
+
RESTRICT_ON_SEND = %i[block_given?].freeze
|
31
|
+
MSG = 'Check block argument explicitly instead of using `block_given?`.'
|
32
|
+
|
33
|
+
def_node_matcher :reassigns_block_arg?, '`(lvasgn %1 ...)'
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
def_node = node.each_ancestor(:def, :defs).first
|
37
|
+
return unless def_node
|
38
|
+
|
39
|
+
block_arg = def_node.arguments.find(&:blockarg_type?)
|
40
|
+
return unless block_arg
|
41
|
+
|
42
|
+
block_arg_name = block_arg.loc.name.source.to_sym
|
43
|
+
return if reassigns_block_arg?(def_node, block_arg_name)
|
44
|
+
|
45
|
+
add_offense(node) do |corrector|
|
46
|
+
corrector.replace(node, block_arg_name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -19,10 +19,10 @@ module RuboCop
|
|
19
19
|
# caller_locations(2..2).first
|
20
20
|
# caller_locations(1..1).first
|
21
21
|
class Caller < Base
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
extend AutoCorrector
|
23
|
+
|
24
|
+
MSG = 'Use `%<preferred_method>s` instead of `%<current_method>s`.'
|
25
|
+
RESTRICT_ON_SEND = %i[first []].freeze
|
26
26
|
|
27
27
|
def_node_matcher :slow_caller?, <<~PATTERN
|
28
28
|
{
|
@@ -41,26 +41,24 @@ module RuboCop
|
|
41
41
|
def on_send(node)
|
42
42
|
return unless caller_with_scope_method?(node)
|
43
43
|
|
44
|
-
message = message(node)
|
45
|
-
add_offense(node, message: message)
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def message(node)
|
51
44
|
method_name = node.receiver.method_name
|
52
45
|
caller_arg = node.receiver.first_argument
|
53
46
|
n = caller_arg ? int_value(caller_arg) : 1
|
54
|
-
|
55
47
|
if node.method?(:[])
|
56
48
|
m = int_value(node.first_argument)
|
57
49
|
n += m
|
58
|
-
|
59
|
-
|
60
|
-
|
50
|
+
end
|
51
|
+
|
52
|
+
preferred_method = "#{method_name}(#{n}..#{n}).first"
|
53
|
+
|
54
|
+
message = format(MSG, preferred_method: preferred_method, current_method: node.source)
|
55
|
+
add_offense(node, message: message) do |corrector|
|
56
|
+
corrector.replace(node, preferred_method)
|
61
57
|
end
|
62
58
|
end
|
63
59
|
|
60
|
+
private
|
61
|
+
|
64
62
|
def int_value(node)
|
65
63
|
node.children[0]
|
66
64
|
end
|