rubocop-performance 1.5.2 → 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 +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +5 -1
- data/config/default.yml +96 -13
- data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +76 -0
- 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 +77 -0
- data/lib/rubocop/cop/performance/caller.rb +5 -4
- data/lib/rubocop/cop/performance/case_when_splat.rb +18 -11
- data/lib/rubocop/cop/performance/casecmp.rb +17 -23
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +5 -11
- data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +140 -0
- data/lib/rubocop/cop/performance/compare_with_block.rb +12 -23
- data/lib/rubocop/cop/performance/count.rb +14 -17
- data/lib/rubocop/cop/performance/delete_prefix.rb +87 -0
- data/lib/rubocop/cop/performance/delete_suffix.rb +87 -0
- data/lib/rubocop/cop/performance/detect.rb +64 -32
- data/lib/rubocop/cop/performance/double_start_end_with.rb +18 -26
- data/lib/rubocop/cop/performance/end_with.rb +38 -25
- data/lib/rubocop/cop/performance/fixed_size.rb +2 -2
- data/lib/rubocop/cop/performance/flat_map.rb +21 -23
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +14 -15
- data/lib/rubocop/cop/performance/io_readlines.rb +116 -0
- data/lib/rubocop/cop/performance/open_struct.rb +3 -3
- data/lib/rubocop/cop/performance/range_include.rb +15 -12
- data/lib/rubocop/cop/performance/redundant_block_call.rb +14 -9
- data/lib/rubocop/cop/performance/redundant_match.rb +13 -8
- data/lib/rubocop/cop/performance/redundant_merge.rb +36 -23
- 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 +32 -32
- data/lib/rubocop/cop/performance/reverse_each.rb +10 -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 +38 -28
- data/lib/rubocop/cop/performance/string_include.rb +55 -0
- data/lib/rubocop/cop/performance/string_replacement.rb +25 -36
- data/lib/rubocop/cop/performance/sum.rb +134 -0
- data/lib/rubocop/cop/performance/times_map.rb +12 -19
- data/lib/rubocop/cop/performance/unfreeze_string.rb +4 -8
- data/lib/rubocop/cop/performance/uri_default_parser.rb +7 -13
- data/lib/rubocop/cop/performance_cops.rb +17 -0
- data/lib/rubocop/performance/inject.rb +1 -1
- data/lib/rubocop/performance/version.rb +1 -1
- metadata +41 -11
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Performance
|
6
6
|
# This cop is used to identify usages of `count` on an `Enumerable` that
|
7
|
-
# follow calls to `select` or `reject`. Querying logic can instead be
|
7
|
+
# follow calls to `select`, `find_all`, `filter` or `reject`. Querying logic can instead be
|
8
8
|
# passed to the `count` call.
|
9
9
|
#
|
10
10
|
# @example
|
@@ -37,15 +37,16 @@ module RuboCop
|
|
37
37
|
# becomes:
|
38
38
|
#
|
39
39
|
# `Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }`
|
40
|
-
class Count <
|
40
|
+
class Count < Base
|
41
41
|
include RangeHelp
|
42
|
+
extend AutoCorrector
|
42
43
|
|
43
44
|
MSG = 'Use `count` instead of `%<selector>s...%<counter>s`.'
|
44
45
|
|
45
|
-
def_node_matcher :count_candidate?,
|
46
|
+
def_node_matcher :count_candidate?, <<~PATTERN
|
46
47
|
{
|
47
|
-
(send (block $(send _ ${:select :reject}) ...) ${:count :length :size})
|
48
|
-
(send $(send _ ${:select :reject} (:block_pass _)) ${:count :length :size})
|
48
|
+
(send (block $(send _ ${:select :filter :find_all :reject}) ...) ${:count :length :size})
|
49
|
+
(send $(send _ ${:select :filter :find_all :reject} (:block_pass _)) ${:count :length :size})
|
49
50
|
}
|
50
51
|
PATTERN
|
51
52
|
|
@@ -57,29 +58,25 @@ module RuboCop
|
|
57
58
|
selector_node.loc.selector.begin_pos
|
58
59
|
end
|
59
60
|
|
60
|
-
add_offense(
|
61
|
-
|
62
|
-
|
63
|
-
counter: counter))
|
61
|
+
add_offense(range, message: format(MSG, selector: selector, counter: counter)) do |corrector|
|
62
|
+
autocorrect(corrector, node, selector_node, selector)
|
63
|
+
end
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
|
-
|
67
|
+
private
|
68
|
+
|
69
|
+
def autocorrect(corrector, node, selector_node, selector)
|
69
70
|
selector_loc = selector_node.loc.selector
|
70
71
|
|
71
72
|
return if selector == :reject
|
72
73
|
|
73
74
|
range = source_starting_at(node) { |n| n.loc.dot.begin_pos }
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
corrector.replace(selector_loc, 'count')
|
78
|
-
end
|
76
|
+
corrector.remove(range)
|
77
|
+
corrector.replace(selector_loc, 'count')
|
79
78
|
end
|
80
79
|
|
81
|
-
private
|
82
|
-
|
83
80
|
def eligible_node?(node)
|
84
81
|
!(node.parent && node.parent.block_type?)
|
85
82
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# In Ruby 2.5, `String#delete_prefix` has been added.
|
7
|
+
#
|
8
|
+
# This cop identifies places where `gsub(/\Aprefix/, '')` and `sub(/\Aprefix/, '')`
|
9
|
+
# can be replaced by `delete_prefix('prefix')`.
|
10
|
+
#
|
11
|
+
# This cop has `SafeMultiline` configuration option that `true` by default because
|
12
|
+
# `^prefix` is unsafe as it will behave incompatible with `delete_prefix`
|
13
|
+
# for receiver is multiline string.
|
14
|
+
#
|
15
|
+
# The `delete_prefix('prefix')` method is faster than `gsub(/\Aprefix/, '')`.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# str.gsub(/\Aprefix/, '')
|
21
|
+
# str.gsub!(/\Aprefix/, '')
|
22
|
+
#
|
23
|
+
# str.sub(/\Aprefix/, '')
|
24
|
+
# str.sub!(/\Aprefix/, '')
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# str.delete_prefix('prefix')
|
28
|
+
# str.delete_prefix!('prefix')
|
29
|
+
#
|
30
|
+
# @example SafeMultiline: true (default)
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# str.gsub(/^prefix/, '')
|
34
|
+
# str.gsub!(/^prefix/, '')
|
35
|
+
# str.sub(/^prefix/, '')
|
36
|
+
# str.sub!(/^prefix/, '')
|
37
|
+
#
|
38
|
+
# @example SafeMultiline: false
|
39
|
+
#
|
40
|
+
# # bad
|
41
|
+
# str.gsub(/^prefix/, '')
|
42
|
+
# str.gsub!(/^prefix/, '')
|
43
|
+
# str.sub(/^prefix/, '')
|
44
|
+
# str.sub!(/^prefix/, '')
|
45
|
+
#
|
46
|
+
class DeletePrefix < Base
|
47
|
+
include RegexpMetacharacter
|
48
|
+
extend AutoCorrector
|
49
|
+
extend TargetRubyVersion
|
50
|
+
|
51
|
+
minimum_target_ruby_version 2.5
|
52
|
+
|
53
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
54
|
+
|
55
|
+
PREFERRED_METHODS = {
|
56
|
+
gsub: :delete_prefix,
|
57
|
+
gsub!: :delete_prefix!,
|
58
|
+
sub: :delete_prefix,
|
59
|
+
sub!: :delete_prefix!
|
60
|
+
}.freeze
|
61
|
+
|
62
|
+
def_node_matcher :delete_prefix_candidate?, <<~PATTERN
|
63
|
+
(send $!nil? ${:gsub :gsub! :sub :sub!} (regexp (str $#literal_at_start?) (regopt)) (str $_))
|
64
|
+
PATTERN
|
65
|
+
|
66
|
+
def on_send(node)
|
67
|
+
return unless (receiver, bad_method, regexp_str, replace_string = delete_prefix_candidate?(node))
|
68
|
+
return unless replace_string.blank?
|
69
|
+
|
70
|
+
good_method = PREFERRED_METHODS[bad_method]
|
71
|
+
|
72
|
+
message = format(MSG, current: bad_method, prefer: good_method)
|
73
|
+
|
74
|
+
add_offense(node.loc.selector, message: message) do |corrector|
|
75
|
+
regexp_str = drop_start_metacharacter(regexp_str)
|
76
|
+
regexp_str = interpret_string_escapes(regexp_str)
|
77
|
+
string_literal = to_string_literal(regexp_str)
|
78
|
+
|
79
|
+
new_code = "#{receiver.source}.#{good_method}(#{string_literal})"
|
80
|
+
|
81
|
+
corrector.replace(node, new_code)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# In Ruby 2.5, `String#delete_suffix` has been added.
|
7
|
+
#
|
8
|
+
# This cop identifies places where `gsub(/suffix\z/, '')` and `sub(/suffix\z/, '')`
|
9
|
+
# can be replaced by `delete_suffix('suffix')`.
|
10
|
+
#
|
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/, '')`.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# str.gsub(/suffix\z/, '')
|
21
|
+
# str.gsub!(/suffix\z/, '')
|
22
|
+
#
|
23
|
+
# str.sub(/suffix\z/, '')
|
24
|
+
# str.sub!(/suffix\z/, '')
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# str.delete_suffix('suffix')
|
28
|
+
# str.delete_suffix!('suffix')
|
29
|
+
#
|
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
|
47
|
+
include RegexpMetacharacter
|
48
|
+
extend AutoCorrector
|
49
|
+
extend TargetRubyVersion
|
50
|
+
|
51
|
+
minimum_target_ruby_version 2.5
|
52
|
+
|
53
|
+
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
54
|
+
|
55
|
+
PREFERRED_METHODS = {
|
56
|
+
gsub: :delete_suffix,
|
57
|
+
gsub!: :delete_suffix!,
|
58
|
+
sub: :delete_suffix,
|
59
|
+
sub!: :delete_suffix!
|
60
|
+
}.freeze
|
61
|
+
|
62
|
+
def_node_matcher :delete_suffix_candidate?, <<~PATTERN
|
63
|
+
(send $!nil? ${:gsub :gsub! :sub :sub!} (regexp (str $#literal_at_end?) (regopt)) (str $_))
|
64
|
+
PATTERN
|
65
|
+
|
66
|
+
def on_send(node)
|
67
|
+
return unless (receiver, bad_method, regexp_str, replace_string = delete_suffix_candidate?(node))
|
68
|
+
return unless replace_string.blank?
|
69
|
+
|
70
|
+
good_method = PREFERRED_METHODS[bad_method]
|
71
|
+
|
72
|
+
message = format(MSG, current: bad_method, prefer: good_method)
|
73
|
+
|
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)
|
78
|
+
|
79
|
+
new_code = "#{receiver.source}.#{good_method}(#{string_literal})"
|
80
|
+
|
81
|
+
corrector.replace(node, new_code)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
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
|
-
def_node_matcher :detect_candidate?,
|
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,30 +53,27 @@ 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?
|
75
67
|
cop_config['IncludeActiveSupportAliases']
|
76
68
|
end
|
77
69
|
|
78
|
-
def_node_matcher :two_start_end_with_calls,
|
70
|
+
def_node_matcher :two_start_end_with_calls, <<~PATTERN
|
79
71
|
(or
|
80
72
|
(send $_recv [{:start_with? :end_with?} $_method] $...)
|
81
73
|
(send _recv _method $...))
|
82
74
|
PATTERN
|
83
75
|
|
84
|
-
def_node_matcher :check_with_active_support_aliases,
|
76
|
+
def_node_matcher :check_with_active_support_aliases, <<~PATTERN
|
85
77
|
(or
|
86
78
|
(send $_recv
|
87
79
|
[{:start_with? :starts_with? :end_with? :ends_with?} $_method]
|