rubocop-performance 1.8.0 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/collection_literal_in_loop.rb +1 -1
- 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 +47 -17
- 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 +72 -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 +67 -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 +131 -18
- 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 +29 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c936c552e05f2364a4256d5f0975973ee3a332270bc1af524db3420e9fc70ba5
|
4
|
+
data.tar.gz: 3cd0086460c2db1c5926caef0737a1d9ae4038808b58b7c91f97e349cfe8f1b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cdc03f8c28e3ea1f63a8477fe064cf1df766f6334fc017d5f8bc7a830f189ad11c1f5a65a33008469b4fe8438522f64b56e6b026fdadb208abf18181d2a6d261
|
7
|
+
data.tar.gz: 04034d2353dc721670ac494d40fae7383ba3800923feea6140c8ea9d86ee080028bc8fb05e46deeb475f1365705114d6a3848520e01248076f38f6e4ef18282f
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
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
|
4
|
+
[![CircleCI](https://circleci.com/gh/rubocop/rubocop-performance.svg?style=svg)](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
|