rubocop-performance 1.7.0 → 1.9.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/README.md +8 -0
- data/config/default.yml +49 -7
- data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +4 -4
- data/lib/rubocop/cop/performance/ancestors_include.rb +16 -12
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +77 -0
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +17 -14
- 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 +24 -28
- 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 +27 -42
- 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 +8 -6
- 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 +6 -16
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +10 -18
- 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 +5 -10
- data/lib/rubocop/cop/performance/size.rb +7 -6
- data/lib/rubocop/cop/performance/sort_reverse.rb +6 -15
- data/lib/rubocop/cop/performance/squeeze.rb +8 -11
- data/lib/rubocop/cop/performance/start_with.rb +9 -13
- data/lib/rubocop/cop/performance/string_include.rb +13 -14
- 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 +6 -0
- data/lib/rubocop/performance/version.rb +6 -1
- metadata +25 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c90f0ddd451c37a5c2187423524462aaa583fc0a7d4fb0342077eb792f03bfcc
|
4
|
+
data.tar.gz: 7606efa668ec94c24a35b93df1062a5a6f39e8c787e013d2707f69448841b7e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2a0094a2edfa59ee9a517cbf5d71ae1fa0fc67042bf0c35b129872a1b6cb6f892c182a0777da2a4e34f1a4c4b4292c30d19a34083b65844802e75b021f75322
|
7
|
+
data.tar.gz: e24dab2beb33688d61cf110a748d5295921c185324df366c0e02478ff44c34acb0857d8b603ca308021c7eaaf6e13d9ecbaeda1f80572b180d499c1b4e5fec5d
|
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
@@ -4,8 +4,18 @@ Performance/AncestorsInclude:
|
|
4
4
|
Description: 'Use `A <= B` instead of `A.ancestors.include?(B)`.'
|
5
5
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#ancestorsinclude-vs--code'
|
6
6
|
Enabled: 'pending'
|
7
|
+
Safe: false
|
7
8
|
VersionAdded: '1.7'
|
8
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-hq/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
|
+
|
9
19
|
Performance/BigDecimalWithNumericArgument:
|
10
20
|
Description: 'Convert numeric argument to string before passing to BigDecimal.'
|
11
21
|
Enabled: 'pending'
|
@@ -16,11 +26,17 @@ Performance/BindCall:
|
|
16
26
|
Enabled: true
|
17
27
|
VersionAdded: '1.6'
|
18
28
|
|
29
|
+
Performance/BlockGivenWithExplicitBlock:
|
30
|
+
Description: 'Check block argument explicitly instead of using `block_given?`.'
|
31
|
+
Enabled: pending
|
32
|
+
VersionAdded: '1.9'
|
33
|
+
|
19
34
|
Performance/Caller:
|
20
35
|
Description: >-
|
21
36
|
Use `caller(n..n)` instead of `caller`.
|
22
37
|
Enabled: true
|
23
38
|
VersionAdded: '0.49'
|
39
|
+
VersionChanged: '1.9'
|
24
40
|
|
25
41
|
Performance/CaseWhenSplat:
|
26
42
|
Description: >-
|
@@ -48,23 +64,33 @@ Performance/ChainArrayAllocation:
|
|
48
64
|
Enabled: false
|
49
65
|
VersionAdded: '0.59'
|
50
66
|
|
67
|
+
Performance/CollectionLiteralInLoop:
|
68
|
+
Description: 'Extract Array and Hash literals outside of loops into local variables or constants.'
|
69
|
+
Enabled: 'pending'
|
70
|
+
VersionAdded: '1.8'
|
71
|
+
# Min number of elements to consider an offense
|
72
|
+
MinSize: 1
|
73
|
+
|
51
74
|
Performance/CompareWithBlock:
|
52
75
|
Description: 'Use `sort_by(&:foo)` instead of `sort { |a, b| a.foo <=> b.foo }`.'
|
53
76
|
Enabled: true
|
54
77
|
VersionAdded: '0.46'
|
55
78
|
|
79
|
+
Performance/ConstantRegexp:
|
80
|
+
Description: 'Finds regular expressions with dynamic components that are all constants.'
|
81
|
+
Enabled: pending
|
82
|
+
VersionAdded: '1.9'
|
83
|
+
|
56
84
|
Performance/Count:
|
57
85
|
Description: >-
|
58
|
-
Use `count` instead of `select
|
59
|
-
`select...count`, `reject...count`, `select...length`,
|
60
|
-
and `reject...length`.
|
86
|
+
Use `count` instead of `{select,find_all,filter,reject}...{size,count,length}`.
|
61
87
|
# This cop has known compatibility issues with `ActiveRecord` and other
|
62
88
|
# frameworks. ActiveRecord's `count` ignores the block that is passed to it.
|
63
89
|
# For more information, see the documentation in the cop itself.
|
64
90
|
SafeAutoCorrect: false
|
65
91
|
Enabled: true
|
66
92
|
VersionAdded: '0.31'
|
67
|
-
VersionChanged: '1.
|
93
|
+
VersionChanged: '1.8'
|
68
94
|
|
69
95
|
Performance/DeletePrefix:
|
70
96
|
Description: 'Use `delete_prefix` instead of `gsub`.'
|
@@ -80,8 +106,8 @@ Performance/DeleteSuffix:
|
|
80
106
|
|
81
107
|
Performance/Detect:
|
82
108
|
Description: >-
|
83
|
-
Use `detect` instead of `select.first`, `find_all.first`,
|
84
|
-
`select.last`, and `
|
109
|
+
Use `detect` instead of `select.first`, `find_all.first`, `filter.first`,
|
110
|
+
`select.last`, `find_all.last`, and `filter.last`.
|
85
111
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
|
86
112
|
# This cop has known compatibility issues with `ActiveRecord` and other
|
87
113
|
# frameworks. `ActiveRecord` does not implement a `detect` method and `find`
|
@@ -90,7 +116,7 @@ Performance/Detect:
|
|
90
116
|
SafeAutoCorrect: false
|
91
117
|
Enabled: true
|
92
118
|
VersionAdded: '0.30'
|
93
|
-
VersionChanged: '1.
|
119
|
+
VersionChanged: '1.8'
|
94
120
|
|
95
121
|
Performance/DoubleStartEndWith:
|
96
122
|
Description: >-
|
@@ -148,6 +174,12 @@ Performance/IoReadlines:
|
|
148
174
|
Enabled: false
|
149
175
|
VersionAdded: '1.7'
|
150
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
|
+
|
151
183
|
Performance/OpenStruct:
|
152
184
|
Description: 'Use `Struct` instead of `OpenStruct`.'
|
153
185
|
Enabled: false
|
@@ -247,6 +279,8 @@ Performance/StartWith:
|
|
247
279
|
Performance/StringInclude:
|
248
280
|
Description: 'Use `String#include?` instead of a regex match with literal-only pattern.'
|
249
281
|
Enabled: 'pending'
|
282
|
+
AutoCorrect: false
|
283
|
+
SafeAutoCorrect: false
|
250
284
|
VersionAdded: '1.7'
|
251
285
|
|
252
286
|
Performance/StringReplacement:
|
@@ -258,6 +292,12 @@ Performance/StringReplacement:
|
|
258
292
|
Enabled: true
|
259
293
|
VersionAdded: '0.33'
|
260
294
|
|
295
|
+
Performance/Sum:
|
296
|
+
Description: 'Use `sum` instead of a custom array summation.'
|
297
|
+
Reference: 'https://blog.bigbinary.com/2016/11/02/ruby-2-4-introduces-enumerable-sum.html'
|
298
|
+
Enabled: 'pending'
|
299
|
+
VersionAdded: '1.8'
|
300
|
+
|
261
301
|
Performance/TimesMap:
|
262
302
|
Description: 'Checks for .times.map calls.'
|
263
303
|
AutoCorrect: false
|
@@ -269,7 +309,9 @@ Performance/TimesMap:
|
|
269
309
|
Performance/UnfreezeString:
|
270
310
|
Description: 'Use unary plus to get an unfrozen string literal.'
|
271
311
|
Enabled: true
|
312
|
+
SafeAutoCorrect: false
|
272
313
|
VersionAdded: '0.50'
|
314
|
+
VersionChanged: '1.9'
|
273
315
|
|
274
316
|
Performance/UriDefaultParser:
|
275
317
|
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)
|
@@ -13,31 +13,35 @@ module RuboCop
|
|
13
13
|
# # good
|
14
14
|
# A <= B
|
15
15
|
#
|
16
|
-
class AncestorsInclude <
|
16
|
+
class AncestorsInclude < Base
|
17
17
|
include RangeHelp
|
18
|
+
extend AutoCorrector
|
18
19
|
|
19
20
|
MSG = 'Use `<=` instead of `ancestors.include?`.'
|
21
|
+
RESTRICT_ON_SEND = %i[include?].freeze
|
20
22
|
|
21
23
|
def_node_matcher :ancestors_include_candidate?, <<~PATTERN
|
22
24
|
(send (send $_subclass :ancestors) :include? $_superclass)
|
23
25
|
PATTERN
|
24
26
|
|
25
27
|
def on_send(node)
|
26
|
-
return unless ancestors_include_candidate?(node)
|
28
|
+
return unless (subclass, superclass = ancestors_include_candidate?(node))
|
29
|
+
return if subclass && !subclass.const_type?
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
range = range_between(location_of_ancestors, end_location)
|
31
|
+
add_offense(range(node)) do |corrector|
|
32
|
+
subclass_source = subclass ? subclass.source : 'self'
|
31
33
|
|
32
|
-
|
34
|
+
corrector.replace(node, "#{subclass_source} <= #{superclass.source}")
|
35
|
+
end
|
33
36
|
end
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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)
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
@@ -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-hq/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
|
@@ -8,34 +8,37 @@ module RuboCop
|
|
8
8
|
# than from Numeric for BigDecimal.
|
9
9
|
#
|
10
10
|
# @example
|
11
|
-
#
|
12
11
|
# # bad
|
13
|
-
#
|
14
|
-
#
|
12
|
+
# BigDecimal(1, 2)
|
13
|
+
# BigDecimal(1.2, 3, exception: true)
|
15
14
|
#
|
16
15
|
# # good
|
17
|
-
#
|
18
|
-
#
|
16
|
+
# BigDecimal('1', 2)
|
17
|
+
# BigDecimal('1.2', 3, exception: true)
|
19
18
|
#
|
20
|
-
class BigDecimalWithNumericArgument <
|
19
|
+
class BigDecimalWithNumericArgument < Base
|
20
|
+
extend AutoCorrector
|
21
|
+
|
21
22
|
MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'
|
23
|
+
RESTRICT_ON_SEND = %i[BigDecimal].freeze
|
22
24
|
|
23
25
|
def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
|
24
26
|
(send nil? :BigDecimal $numeric_type? ...)
|
25
27
|
PATTERN
|
26
28
|
|
27
29
|
def on_send(node)
|
28
|
-
big_decimal_with_numeric_argument?(node)
|
29
|
-
|
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, "'", "'")
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
end
|
38
|
+
private
|
39
|
+
|
40
|
+
def specifies_precision?(node)
|
41
|
+
node.arguments.size > 1 && !node.arguments[1].hash_type?
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
@@ -19,14 +19,16 @@ module RuboCop
|
|
19
19
|
# # good
|
20
20
|
# umethod.bind_call(obj, foo, bar)
|
21
21
|
#
|
22
|
-
class BindCall <
|
22
|
+
class BindCall < Base
|
23
23
|
include RangeHelp
|
24
|
+
extend AutoCorrector
|
24
25
|
extend TargetRubyVersion
|
25
26
|
|
26
27
|
minimum_target_ruby_version 2.7
|
27
28
|
|
28
29
|
MSG = 'Use `bind_call(%<bind_arg>s%<comma>s%<call_args>s)` ' \
|
29
30
|
'instead of `bind(%<bind_arg>s).call(%<call_args>s)`.'
|
31
|
+
RESTRICT_ON_SEND = %i[call].freeze
|
30
32
|
|
31
33
|
def_node_matcher :bind_with_call_method?, <<~PATTERN
|
32
34
|
(send
|
@@ -37,28 +39,17 @@ module RuboCop
|
|
37
39
|
PATTERN
|
38
40
|
|
39
41
|
def on_send(node)
|
40
|
-
|
41
|
-
range = correction_range(receiver, node)
|
42
|
-
|
43
|
-
call_args = build_call_args(call_args_node)
|
44
|
-
|
45
|
-
message = message(bind_arg.source, call_args)
|
46
|
-
|
47
|
-
add_offense(node, location: range, message: message)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def autocorrect(node)
|
52
|
-
receiver, bind_arg, call_args_node = bind_with_call_method?(node)
|
42
|
+
return unless (receiver, bind_arg, call_args_node = bind_with_call_method?(node))
|
53
43
|
|
54
44
|
range = correction_range(receiver, node)
|
55
|
-
|
56
45
|
call_args = build_call_args(call_args_node)
|
57
|
-
|
46
|
+
message = message(bind_arg.source, call_args)
|
47
|
+
|
48
|
+
add_offense(range, message: message) do |corrector|
|
49
|
+
call_args = ", #{call_args}" unless call_args.empty?
|
58
50
|
|
59
|
-
|
51
|
+
replacement_method = "bind_call(#{bind_arg.source}#{call_args})"
|
60
52
|
|
61
|
-
lambda do |corrector|
|
62
53
|
corrector.replace(range, replacement_method)
|
63
54
|
end
|
64
55
|
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
|