rubocop-performance 1.7.1 → 1.9.2
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 +46 -7
- data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +4 -4
- data/lib/rubocop/cop/performance/ancestors_include.rb +15 -13
- data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +77 -0
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +8 -12
- 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 +13 -12
- 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 +11 -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: 30b8495304f86e7ef0e9a7f11e12a30ab7986fb4b12cb1921870f31a1b37a42f
|
4
|
+
data.tar.gz: 1863b8766efff5dd99b2e4f2dbb4e16191f223d12dbfd51826a837f1f75eef08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6071b0e37b9a9683f1992b88b36e0911004e0ec8fc4b41f78ba569ce396d96840acb0eff937d519d132917dec1b0a5af9fe4d1563d743e293ee78239a59b13f
|
7
|
+
data.tar.gz: 74c457f9d7f7ef240a2fa483100ff1120fc4edba7bb64e999f78a85e106621cba4ddef1a2dae7f375f9541d021a0fa08f054edf83ebd1646423d214b4677e212
|
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
@@ -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-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
|
+
|
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: >-
|
@@ -49,23 +64,33 @@ Performance/ChainArrayAllocation:
|
|
49
64
|
Enabled: false
|
50
65
|
VersionAdded: '0.59'
|
51
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
|
+
|
52
74
|
Performance/CompareWithBlock:
|
53
75
|
Description: 'Use `sort_by(&:foo)` instead of `sort { |a, b| a.foo <=> b.foo }`.'
|
54
76
|
Enabled: true
|
55
77
|
VersionAdded: '0.46'
|
56
78
|
|
79
|
+
Performance/ConstantRegexp:
|
80
|
+
Description: 'Finds regular expressions with dynamic components that are all constants.'
|
81
|
+
Enabled: pending
|
82
|
+
VersionAdded: '1.9'
|
83
|
+
|
57
84
|
Performance/Count:
|
58
85
|
Description: >-
|
59
|
-
Use `count` instead of `select
|
60
|
-
`select...count`, `reject...count`, `select...length`,
|
61
|
-
and `reject...length`.
|
86
|
+
Use `count` instead of `{select,find_all,filter,reject}...{size,count,length}`.
|
62
87
|
# This cop has known compatibility issues with `ActiveRecord` and other
|
63
88
|
# frameworks. ActiveRecord's `count` ignores the block that is passed to it.
|
64
89
|
# For more information, see the documentation in the cop itself.
|
65
90
|
SafeAutoCorrect: false
|
66
91
|
Enabled: true
|
67
92
|
VersionAdded: '0.31'
|
68
|
-
VersionChanged: '1.
|
93
|
+
VersionChanged: '1.8'
|
69
94
|
|
70
95
|
Performance/DeletePrefix:
|
71
96
|
Description: 'Use `delete_prefix` instead of `gsub`.'
|
@@ -81,8 +106,8 @@ Performance/DeleteSuffix:
|
|
81
106
|
|
82
107
|
Performance/Detect:
|
83
108
|
Description: >-
|
84
|
-
Use `detect` instead of `select.first`, `find_all.first`,
|
85
|
-
`select.last`, and `
|
109
|
+
Use `detect` instead of `select.first`, `find_all.first`, `filter.first`,
|
110
|
+
`select.last`, `find_all.last`, and `filter.last`.
|
86
111
|
Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
|
87
112
|
# This cop has known compatibility issues with `ActiveRecord` and other
|
88
113
|
# frameworks. `ActiveRecord` does not implement a `detect` method and `find`
|
@@ -91,7 +116,7 @@ Performance/Detect:
|
|
91
116
|
SafeAutoCorrect: false
|
92
117
|
Enabled: true
|
93
118
|
VersionAdded: '0.30'
|
94
|
-
VersionChanged: '1.
|
119
|
+
VersionChanged: '1.8'
|
95
120
|
|
96
121
|
Performance/DoubleStartEndWith:
|
97
122
|
Description: >-
|
@@ -149,6 +174,12 @@ Performance/IoReadlines:
|
|
149
174
|
Enabled: false
|
150
175
|
VersionAdded: '1.7'
|
151
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
|
+
|
152
183
|
Performance/OpenStruct:
|
153
184
|
Description: 'Use `Struct` instead of `OpenStruct`.'
|
154
185
|
Enabled: false
|
@@ -261,6 +292,12 @@ Performance/StringReplacement:
|
|
261
292
|
Enabled: true
|
262
293
|
VersionAdded: '0.33'
|
263
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
|
+
|
264
301
|
Performance/TimesMap:
|
265
302
|
Description: 'Checks for .times.map calls.'
|
266
303
|
AutoCorrect: false
|
@@ -272,7 +309,9 @@ Performance/TimesMap:
|
|
272
309
|
Performance/UnfreezeString:
|
273
310
|
Description: 'Use unary plus to get an unfrozen string literal.'
|
274
311
|
Enabled: true
|
312
|
+
SafeAutoCorrect: false
|
275
313
|
VersionAdded: '0.50'
|
314
|
+
VersionChanged: '1.9'
|
276
315
|
|
277
316
|
Performance/UriDefaultParser:
|
278
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,33 +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
|
-
ancestors_include_candidate?(node) do |subclass, superclass|
|
37
|
-
lambda do |corrector|
|
38
|
-
subclass_source = subclass ? subclass.source : 'self'
|
38
|
+
private
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
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)
|
43
45
|
end
|
44
46
|
end
|
45
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
|
@@ -16,26 +16,22 @@ module RuboCop
|
|
16
16
|
# BigDecimal('1', 2)
|
17
17
|
# BigDecimal('1.2', 3, exception: true)
|
18
18
|
#
|
19
|
-
class BigDecimalWithNumericArgument <
|
19
|
+
class BigDecimalWithNumericArgument < Base
|
20
|
+
extend AutoCorrector
|
21
|
+
|
20
22
|
MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'
|
23
|
+
RESTRICT_ON_SEND = %i[BigDecimal].freeze
|
21
24
|
|
22
25
|
def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
|
23
26
|
(send nil? :BigDecimal $numeric_type? ...)
|
24
27
|
PATTERN
|
25
28
|
|
26
29
|
def on_send(node)
|
27
|
-
big_decimal_with_numeric_argument?(node)
|
28
|
-
|
29
|
-
|
30
|
-
add_offense(node, location: numeric.source_range)
|
31
|
-
end
|
32
|
-
end
|
30
|
+
return unless (numeric = big_decimal_with_numeric_argument?(node))
|
31
|
+
return if numeric.float_type? && specifies_precision?(node)
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
lambda do |corrector|
|
37
|
-
corrector.wrap(numeric, "'", "'")
|
38
|
-
end
|
33
|
+
add_offense(numeric.source_range) do |corrector|
|
34
|
+
corrector.wrap(numeric, "'", "'")
|
39
35
|
end
|
40
36
|
end
|
41
37
|
|
@@ -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
|