rubocop-performance 1.6.0 → 1.8.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 +5 -5
- data/README.md +1 -1
- data/config/default.yml +77 -10
- data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +39 -4
- data/lib/rubocop/cop/mixin/sort_block.rb +28 -0
- data/lib/rubocop/cop/performance/ancestors_include.rb +48 -0
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +45 -0
- data/lib/rubocop/cop/performance/bind_call.rb +8 -18
- data/lib/rubocop/cop/performance/caller.rb +3 -2
- data/lib/rubocop/cop/performance/case_when_splat.rb +18 -11
- data/lib/rubocop/cop/performance/casecmp.rb +12 -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/count.rb +13 -16
- data/lib/rubocop/cop/performance/delete_prefix.rb +43 -28
- data/lib/rubocop/cop/performance/delete_suffix.rb +43 -28
- data/lib/rubocop/cop/performance/detect.rb +63 -31
- data/lib/rubocop/cop/performance/double_start_end_with.rb +16 -24
- data/lib/rubocop/cop/performance/end_with.rb +29 -17
- data/lib/rubocop/cop/performance/fixed_size.rb +1 -1
- data/lib/rubocop/cop/performance/flat_map.rb +20 -22
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +13 -14
- data/lib/rubocop/cop/performance/io_readlines.rb +116 -0
- data/lib/rubocop/cop/performance/open_struct.rb +2 -2
- data/lib/rubocop/cop/performance/range_include.rb +14 -11
- data/lib/rubocop/cop/performance/redundant_block_call.rb +11 -6
- data/lib/rubocop/cop/performance/redundant_match.rb +11 -6
- data/lib/rubocop/cop/performance/redundant_merge.rb +18 -17
- data/lib/rubocop/cop/performance/redundant_sort_block.rb +43 -0
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +133 -0
- data/lib/rubocop/cop/performance/regexp_match.rb +20 -20
- data/lib/rubocop/cop/performance/reverse_each.rb +9 -5
- data/lib/rubocop/cop/performance/reverse_first.rb +72 -0
- data/lib/rubocop/cop/performance/size.rb +41 -43
- data/lib/rubocop/cop/performance/sort_reverse.rb +45 -0
- data/lib/rubocop/cop/performance/squeeze.rb +66 -0
- data/lib/rubocop/cop/performance/start_with.rb +29 -17
- data/lib/rubocop/cop/performance/string_include.rb +55 -0
- data/lib/rubocop/cop/performance/string_replacement.rb +23 -27
- data/lib/rubocop/cop/performance/sum.rb +134 -0
- data/lib/rubocop/cop/performance/times_map.rb +11 -18
- data/lib/rubocop/cop/performance/unfreeze_string.rb +2 -2
- data/lib/rubocop/cop/performance/uri_default_parser.rb +6 -12
- data/lib/rubocop/cop/performance_cops.rb +12 -0
- data/lib/rubocop/performance/version.rb +1 -1
- metadata +33 -8
@@ -5,27 +5,48 @@ module RuboCop
|
|
5
5
|
module Performance
|
6
6
|
# In Ruby 2.5, `String#delete_suffix` has been added.
|
7
7
|
#
|
8
|
-
# This cop identifies places where `gsub(/suffix\z/, '')`
|
8
|
+
# This cop identifies places where `gsub(/suffix\z/, '')` and `sub(/suffix\z/, '')`
|
9
9
|
# can be replaced by `delete_suffix('suffix')`.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# `
|
11
|
+
# This cop has `SafeMultiline` configuration option that `true` by default because
|
12
|
+
# `suffix$` is unsafe as it will behave incompatible with `delete_suffix?`
|
13
|
+
# for receiver is multiline string.
|
14
|
+
#
|
15
|
+
# The `delete_suffix('suffix')` method is faster than `gsub(/suffix\z/, '')`.
|
13
16
|
#
|
14
17
|
# @example
|
15
18
|
#
|
16
19
|
# # bad
|
17
20
|
# str.gsub(/suffix\z/, '')
|
18
21
|
# str.gsub!(/suffix\z/, '')
|
19
|
-
#
|
20
|
-
# str.
|
22
|
+
#
|
23
|
+
# str.sub(/suffix\z/, '')
|
24
|
+
# str.sub!(/suffix\z/, '')
|
21
25
|
#
|
22
26
|
# # good
|
23
27
|
# str.delete_suffix('suffix')
|
24
28
|
# str.delete_suffix!('suffix')
|
25
29
|
#
|
26
|
-
|
27
|
-
|
30
|
+
# @example SafeMultiline: true (default)
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# str.gsub(/suffix$/, '')
|
34
|
+
# str.gsub!(/suffix$/, '')
|
35
|
+
# str.sub(/suffix$/, '')
|
36
|
+
# str.sub!(/suffix$/, '')
|
37
|
+
#
|
38
|
+
# @example SafeMultiline: false
|
39
|
+
#
|
40
|
+
# # bad
|
41
|
+
# str.gsub(/suffix$/, '')
|
42
|
+
# str.gsub!(/suffix$/, '')
|
43
|
+
# str.sub(/suffix$/, '')
|
44
|
+
# str.sub!(/suffix$/, '')
|
45
|
+
#
|
46
|
+
class DeleteSuffix < Base
|
28
47
|
include RegexpMetacharacter
|
48
|
+
extend AutoCorrector
|
49
|
+
extend TargetRubyVersion
|
29
50
|
|
30
51
|
minimum_target_ruby_version 2.5
|
31
52
|
|
@@ -33,37 +54,31 @@ module RuboCop
|
|
33
54
|
|
34
55
|
PREFERRED_METHODS = {
|
35
56
|
gsub: :delete_suffix,
|
36
|
-
gsub!: :delete_suffix
|
57
|
+
gsub!: :delete_suffix!,
|
58
|
+
sub: :delete_suffix,
|
59
|
+
sub!: :delete_suffix!
|
37
60
|
}.freeze
|
38
61
|
|
39
|
-
def_node_matcher :
|
40
|
-
(send $!nil? ${:gsub :gsub!} (regexp (str $#literal_at_end?) (regopt)) (str $_))
|
62
|
+
def_node_matcher :delete_suffix_candidate?, <<~PATTERN
|
63
|
+
(send $!nil? ${:gsub :gsub! :sub :sub!} (regexp (str $#literal_at_end?) (regopt)) (str $_))
|
41
64
|
PATTERN
|
42
65
|
|
43
66
|
def on_send(node)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
good_method = PREFERRED_METHODS[bad_method]
|
67
|
+
return unless (receiver, bad_method, regexp_str, replace_string = delete_suffix_candidate?(node))
|
68
|
+
return unless replace_string.blank?
|
48
69
|
|
49
|
-
|
70
|
+
good_method = PREFERRED_METHODS[bad_method]
|
50
71
|
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|
72
|
+
message = format(MSG, current: bad_method, prefer: good_method)
|
54
73
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
regexp_str = drop_end_metacharacter(regexp_str)
|
60
|
-
regexp_str = interpret_string_escapes(regexp_str)
|
61
|
-
string_literal = to_string_literal(regexp_str)
|
74
|
+
add_offense(node.loc.selector, message: message) do |corrector|
|
75
|
+
regexp_str = drop_end_metacharacter(regexp_str)
|
76
|
+
regexp_str = interpret_string_escapes(regexp_str)
|
77
|
+
string_literal = to_string_literal(regexp_str)
|
62
78
|
|
63
|
-
|
79
|
+
new_code = "#{receiver.source}.#{good_method}(#{string_literal})"
|
64
80
|
|
65
|
-
|
66
|
-
end
|
81
|
+
corrector.replace(node, new_code)
|
67
82
|
end
|
68
83
|
end
|
69
84
|
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
# This cop is used to identify usages of
|
7
|
-
#
|
6
|
+
# This cop is used to identify usages of `first`, `last`, `[0]` or `[-1]`
|
7
|
+
# chained to `select`, `find_all`, or `find_all`
|
8
8
|
# and change them to use `detect` instead.
|
9
9
|
#
|
10
10
|
# @example
|
@@ -13,6 +13,10 @@ module RuboCop
|
|
13
13
|
# [].select { |item| true }.last
|
14
14
|
# [].find_all { |item| true }.first
|
15
15
|
# [].find_all { |item| true }.last
|
16
|
+
# [].filter { |item| true }.first
|
17
|
+
# [].filter { |item| true }.last
|
18
|
+
# [].filter { |item| true }[0]
|
19
|
+
# [].filter { |item| true }[-1]
|
16
20
|
#
|
17
21
|
# # good
|
18
22
|
# [].detect { |item| true }
|
@@ -22,47 +26,43 @@ module RuboCop
|
|
22
26
|
# `ActiveRecord` does not implement a `detect` method and `find` has its
|
23
27
|
# own meaning. Correcting ActiveRecord methods with this cop should be
|
24
28
|
# considered unsafe.
|
25
|
-
class Detect <
|
29
|
+
class Detect < Base
|
30
|
+
extend AutoCorrector
|
31
|
+
|
32
|
+
CANDIDATE_METHODS = Set[:select, :find_all, :filter].freeze
|
33
|
+
|
26
34
|
MSG = 'Use `%<prefer>s` instead of ' \
|
27
35
|
'`%<first_method>s.%<second_method>s`.'
|
28
36
|
REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of ' \
|
29
37
|
'`%<first_method>s.%<second_method>s`.'
|
38
|
+
INDEX_MSG = 'Use `%<prefer>s` instead of ' \
|
39
|
+
'`%<first_method>s[%<index>i]`.'
|
40
|
+
INDEX_REVERSE_MSG = 'Use `reverse.%<prefer>s` instead of ' \
|
41
|
+
'`%<first_method>s[%<index>i]`.'
|
30
42
|
|
31
43
|
def_node_matcher :detect_candidate?, <<~PATTERN
|
32
44
|
{
|
33
|
-
(send $(block (send _
|
34
|
-
(send $(send _
|
45
|
+
(send $(block (send _ %CANDIDATE_METHODS) ...) ${:first :last} $...)
|
46
|
+
(send $(block (send _ %CANDIDATE_METHODS) ...) $:[] (int ${0 -1}))
|
47
|
+
(send $(send _ %CANDIDATE_METHODS ...) ${:first :last} $...)
|
48
|
+
(send $(send _ %CANDIDATE_METHODS ...) $:[] (int ${0 -1}))
|
35
49
|
}
|
36
50
|
PATTERN
|
37
51
|
|
38
52
|
def on_send(node)
|
39
53
|
detect_candidate?(node) do |receiver, second_method, args|
|
54
|
+
if second_method == :[]
|
55
|
+
index = args
|
56
|
+
args = {}
|
57
|
+
end
|
58
|
+
|
40
59
|
return unless args.empty?
|
41
60
|
return unless receiver
|
42
61
|
|
43
62
|
receiver, _args, body = *receiver if receiver.block_type?
|
44
63
|
return if accept_first_call?(receiver, body)
|
45
64
|
|
46
|
-
register_offense(node, receiver, second_method)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def autocorrect(node)
|
51
|
-
receiver, first_method = *node
|
52
|
-
|
53
|
-
replacement = if first_method == :last
|
54
|
-
"reverse.#{preferred_method}"
|
55
|
-
else
|
56
|
-
preferred_method
|
57
|
-
end
|
58
|
-
|
59
|
-
first_range = receiver.source_range.end.join(node.loc.selector)
|
60
|
-
|
61
|
-
receiver, _args, _body = *receiver if receiver.block_type?
|
62
|
-
|
63
|
-
lambda do |corrector|
|
64
|
-
corrector.remove(first_range)
|
65
|
-
corrector.replace(receiver.loc.selector, replacement)
|
65
|
+
register_offense(node, receiver, second_method, index)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -77,21 +77,53 @@ module RuboCop
|
|
77
77
|
lazy?(caller)
|
78
78
|
end
|
79
79
|
|
80
|
-
def register_offense(node, receiver, second_method)
|
80
|
+
def register_offense(node, receiver, second_method, index)
|
81
81
|
_caller, first_method, _args = *receiver
|
82
82
|
range = receiver.loc.selector.join(node.loc.selector)
|
83
83
|
|
84
|
-
message = second_method
|
84
|
+
message = message_for_method(second_method, index)
|
85
85
|
formatted_message = format(message, prefer: preferred_method,
|
86
86
|
first_method: first_method,
|
87
|
-
second_method: second_method
|
87
|
+
second_method: second_method,
|
88
|
+
index: index)
|
89
|
+
|
90
|
+
add_offense(range, message: formatted_message) do |corrector|
|
91
|
+
autocorrect(corrector, node, replacement(second_method, index))
|
92
|
+
end
|
93
|
+
end
|
88
94
|
|
89
|
-
|
95
|
+
def replacement(method, index)
|
96
|
+
if method == :last || method == :[] && index == -1
|
97
|
+
"reverse.#{preferred_method}"
|
98
|
+
else
|
99
|
+
preferred_method
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def autocorrect(corrector, node, replacement)
|
104
|
+
receiver, _first_method = *node
|
105
|
+
|
106
|
+
first_range = receiver.source_range.end.join(node.loc.selector)
|
107
|
+
|
108
|
+
receiver, _args, _body = *receiver if receiver.block_type?
|
109
|
+
|
110
|
+
corrector.remove(first_range)
|
111
|
+
corrector.replace(receiver.loc.selector, replacement)
|
112
|
+
end
|
113
|
+
|
114
|
+
def message_for_method(method, index)
|
115
|
+
case method
|
116
|
+
when :[]
|
117
|
+
index == -1 ? INDEX_REVERSE_MSG : INDEX_MSG
|
118
|
+
when :last
|
119
|
+
REVERSE_MSG
|
120
|
+
else
|
121
|
+
MSG
|
122
|
+
end
|
90
123
|
end
|
91
124
|
|
92
125
|
def preferred_method
|
93
|
-
config.for_cop('Style/CollectionMethods')
|
94
|
-
['PreferredMethods']['detect'] || 'detect'
|
126
|
+
config.for_cop('Style/CollectionMethods')['PreferredMethods']['detect'] || 'detect'
|
95
127
|
end
|
96
128
|
|
97
129
|
def lazy?(node)
|
@@ -17,39 +17,34 @@ module RuboCop
|
|
17
17
|
# str.start_with?("a", Some::CONST)
|
18
18
|
# str.start_with?("a", "b", "c")
|
19
19
|
# str.end_with?(var1, var2)
|
20
|
-
class DoubleStartEndWith <
|
20
|
+
class DoubleStartEndWith < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
21
23
|
MSG = 'Use `%<receiver>s.%<method>s(%<combined_args>s)` ' \
|
22
24
|
'instead of `%<original_code>s`.'
|
23
25
|
|
24
26
|
def on_or(node)
|
25
|
-
receiver,
|
26
|
-
method,
|
27
|
-
first_call_args,
|
28
|
-
second_call_args = process_source(node)
|
27
|
+
receiver, method, first_call_args, second_call_args = process_source(node)
|
29
28
|
|
30
29
|
return unless receiver && second_call_args.all?(&:pure?)
|
31
30
|
|
32
31
|
combined_args = combine_args(first_call_args, second_call_args)
|
33
32
|
|
34
|
-
|
33
|
+
add_offense(node, message: message(node, receiver, method, combined_args)) do |corrector|
|
34
|
+
autocorrect(corrector, first_call_args, second_call_args, combined_args)
|
35
|
+
end
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
-
_receiver, _method,
|
39
|
-
first_call_args, second_call_args = process_source(node)
|
38
|
+
private
|
40
39
|
|
41
|
-
|
40
|
+
def autocorrect(corrector, first_call_args, second_call_args, combined_args)
|
42
41
|
first_argument = first_call_args.first.loc.expression
|
43
42
|
last_argument = second_call_args.last.loc.expression
|
44
43
|
range = first_argument.join(last_argument)
|
45
44
|
|
46
|
-
|
47
|
-
corrector.replace(range, combined_args)
|
48
|
-
end
|
45
|
+
corrector.replace(range, combined_args)
|
49
46
|
end
|
50
47
|
|
51
|
-
private
|
52
|
-
|
53
48
|
def process_source(node)
|
54
49
|
if check_for_active_support_aliases?
|
55
50
|
check_with_active_support_aliases(node)
|
@@ -58,17 +53,14 @@ module RuboCop
|
|
58
53
|
end
|
59
54
|
end
|
60
55
|
|
61
|
-
def
|
62
|
-
(
|
56
|
+
def message(node, receiver, method, combined_args)
|
57
|
+
format(
|
58
|
+
MSG, receiver: receiver.source, method: method, combined_args: combined_args, original_code: node.source
|
59
|
+
)
|
63
60
|
end
|
64
61
|
|
65
|
-
def
|
66
|
-
|
67
|
-
method: method,
|
68
|
-
combined_args: combined_args,
|
69
|
-
original_code: node.source)
|
70
|
-
|
71
|
-
add_offense(node, message: msg)
|
62
|
+
def combine_args(first_call_args, second_call_args)
|
63
|
+
(first_call_args + second_call_args).map(&:source).join(', ')
|
72
64
|
end
|
73
65
|
|
74
66
|
def check_for_active_support_aliases?
|
@@ -3,8 +3,11 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
|
-
# This cop identifies unnecessary use of a regex where `String#end_with?`
|
7
|
-
#
|
6
|
+
# This cop identifies unnecessary use of a regex where `String#end_with?` would suffice.
|
7
|
+
#
|
8
|
+
# This cop has `SafeMultiline` configuration option that `true` by default because
|
9
|
+
# `end$` is unsafe as it will behave incompatible with `end_with?`
|
10
|
+
# for receiver is multiline string.
|
8
11
|
#
|
9
12
|
# @example
|
10
13
|
# # bad
|
@@ -15,6 +18,12 @@ module RuboCop
|
|
15
18
|
# 'abc'.match(/bc\Z/)
|
16
19
|
# /bc\Z/.match('abc')
|
17
20
|
#
|
21
|
+
# # good
|
22
|
+
# 'abc'.end_with?('bc')
|
23
|
+
#
|
24
|
+
# @example SafeMultiline: true (default)
|
25
|
+
#
|
26
|
+
# # good
|
18
27
|
# 'abc'.match?(/bc$/)
|
19
28
|
# /bc$/.match?('abc')
|
20
29
|
# 'abc' =~ /bc$/
|
@@ -22,10 +31,19 @@ module RuboCop
|
|
22
31
|
# 'abc'.match(/bc$/)
|
23
32
|
# /bc$/.match('abc')
|
24
33
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
|
34
|
+
# @example SafeMultiline: false
|
35
|
+
#
|
36
|
+
# # bad
|
37
|
+
# 'abc'.match?(/bc$/)
|
38
|
+
# /bc$/.match?('abc')
|
39
|
+
# 'abc' =~ /bc$/
|
40
|
+
# /bc$/ =~ 'abc'
|
41
|
+
# 'abc'.match(/bc$/)
|
42
|
+
# /bc$/.match('abc')
|
43
|
+
#
|
44
|
+
class EndWith < Base
|
28
45
|
include RegexpMetacharacter
|
46
|
+
extend AutoCorrector
|
29
47
|
|
30
48
|
MSG = 'Use `String#end_with?` instead of a regex match anchored to ' \
|
31
49
|
'the end of the string.'
|
@@ -37,25 +55,19 @@ module RuboCop
|
|
37
55
|
PATTERN
|
38
56
|
|
39
57
|
def on_send(node)
|
40
|
-
return unless redundant_regex?(node)
|
58
|
+
return unless (receiver, regex_str = redundant_regex?(node))
|
41
59
|
|
42
|
-
add_offense(node)
|
43
|
-
end
|
44
|
-
alias on_match_with_lvasgn on_send
|
45
|
-
|
46
|
-
def autocorrect(node)
|
47
|
-
redundant_regex?(node) do |receiver, regex_str|
|
60
|
+
add_offense(node) do |corrector|
|
48
61
|
receiver, regex_str = regex_str, receiver if receiver.is_a?(String)
|
49
62
|
regex_str = drop_end_metacharacter(regex_str)
|
50
63
|
regex_str = interpret_string_escapes(regex_str)
|
51
64
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
corrector.replace(node.source_range, new_source)
|
56
|
-
end
|
65
|
+
new_source = "#{receiver.source}.end_with?(#{to_string_literal(regex_str)})"
|
66
|
+
|
67
|
+
corrector.replace(node.source_range, new_source)
|
57
68
|
end
|
58
69
|
end
|
70
|
+
alias on_match_with_lvasgn on_send
|
59
71
|
end
|
60
72
|
end
|
61
73
|
end
|
@@ -14,8 +14,9 @@ module RuboCop
|
|
14
14
|
# [1, 2, 3, 4].flat_map { |e| [e, e] }
|
15
15
|
# [1, 2, 3, 4].map { |e| [e, e] }.flatten
|
16
16
|
# [1, 2, 3, 4].collect { |e| [e, e] }.flatten
|
17
|
-
class FlatMap <
|
17
|
+
class FlatMap < Base
|
18
18
|
include RangeHelp
|
19
|
+
extend AutoCorrector
|
19
20
|
|
20
21
|
MSG = 'Use `flat_map` instead of `%<method>s...%<flatten>s`.'
|
21
22
|
FLATTEN_MULTIPLE_LEVELS = ' Beware, `flat_map` only flattens 1 level ' \
|
@@ -44,25 +45,11 @@ module RuboCop
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
def autocorrect(node)
|
48
|
-
map_node, _first_method, _flatten, params = flat_map_candidate?(node)
|
49
|
-
flatten_level, = *params.first
|
50
|
-
|
51
|
-
return unless flatten_level
|
52
|
-
|
53
|
-
range = range_between(node.loc.dot.begin_pos,
|
54
|
-
node.source_range.end_pos)
|
55
|
-
|
56
|
-
lambda do |corrector|
|
57
|
-
corrector.remove(range)
|
58
|
-
corrector.replace(map_node.loc.selector, 'flat_map')
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
48
|
private
|
63
49
|
|
64
50
|
def offense_for_levels(node, map_node, first_method, flatten)
|
65
51
|
message = MSG + FLATTEN_MULTIPLE_LEVELS
|
52
|
+
|
66
53
|
register_offense(node, map_node, first_method, flatten, message)
|
67
54
|
end
|
68
55
|
|
@@ -71,13 +58,24 @@ module RuboCop
|
|
71
58
|
end
|
72
59
|
|
73
60
|
def register_offense(node, map_node, first_method, flatten, message)
|
74
|
-
range = range_between(map_node.loc.selector.begin_pos,
|
75
|
-
|
61
|
+
range = range_between(map_node.loc.selector.begin_pos, node.loc.expression.end_pos)
|
62
|
+
message = format(message, method: first_method, flatten: flatten)
|
63
|
+
|
64
|
+
add_offense(range, message: message) do |corrector|
|
65
|
+
autocorrect(corrector, node)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def autocorrect(corrector, node)
|
70
|
+
map_node, _first_method, _flatten, params = flat_map_candidate?(node)
|
71
|
+
flatten_level, = *params.first
|
72
|
+
|
73
|
+
return unless flatten_level
|
74
|
+
|
75
|
+
range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
message: format(message, method: first_method,
|
80
|
-
flatten: flatten))
|
77
|
+
corrector.remove(range)
|
78
|
+
corrector.replace(map_node.loc.selector, 'flat_map')
|
81
79
|
end
|
82
80
|
end
|
83
81
|
end
|