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
@@ -17,18 +17,20 @@ module RuboCop
|
|
17
17
|
# # good
|
18
18
|
# method(str =~ /regex/)
|
19
19
|
# return value unless regex =~ 'str'
|
20
|
-
class RedundantMatch <
|
20
|
+
class RedundantMatch < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
21
23
|
MSG = 'Use `=~` in places where the `MatchData` returned by ' \
|
22
24
|
'`#match` will not be used.'
|
23
25
|
|
24
26
|
# 'match' is a fairly generic name, so we don't flag it unless we see
|
25
27
|
# a string or regexp literal on one side or the other
|
26
|
-
def_node_matcher :match_call?,
|
28
|
+
def_node_matcher :match_call?, <<~PATTERN
|
27
29
|
{(send {str regexp} :match _)
|
28
30
|
(send !nil? :match {str regexp})}
|
29
31
|
PATTERN
|
30
32
|
|
31
|
-
def_node_matcher :only_truthiness_matters?,
|
33
|
+
def_node_matcher :only_truthiness_matters?, <<~PATTERN
|
32
34
|
^({if while until case while_post until_post} equal?(%0) ...)
|
33
35
|
PATTERN
|
34
36
|
|
@@ -37,18 +39,21 @@ module RuboCop
|
|
37
39
|
(!node.value_used? || only_truthiness_matters?(node)) &&
|
38
40
|
!(node.parent && node.parent.block_type?)
|
39
41
|
|
40
|
-
add_offense(node)
|
42
|
+
add_offense(node) do |corrector|
|
43
|
+
autocorrect(corrector, node)
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
43
|
-
|
47
|
+
private
|
48
|
+
|
49
|
+
def autocorrect(corrector, node)
|
44
50
|
# Regexp#match can take a second argument, but this cop doesn't
|
45
51
|
# register an offense in that case
|
46
52
|
return unless node.first_argument.regexp_type?
|
47
53
|
|
48
|
-
new_source =
|
49
|
-
node.receiver.source + ' =~ ' + node.first_argument.source
|
54
|
+
new_source = "#{node.receiver.source} =~ #{node.first_argument.source}"
|
50
55
|
|
51
|
-
|
56
|
+
corrector.replace(node.source_range, new_source)
|
52
57
|
end
|
53
58
|
end
|
54
59
|
end
|
@@ -5,12 +5,28 @@ module RuboCop
|
|
5
5
|
module Performance
|
6
6
|
# This cop identifies places where `Hash#merge!` can be replaced by
|
7
7
|
# `Hash#[]=`.
|
8
|
+
# You can set the maximum number of key-value pairs to consider
|
9
|
+
# an offense with `MaxKeyValuePairs`.
|
8
10
|
#
|
9
11
|
# @example
|
12
|
+
# # bad
|
10
13
|
# hash.merge!(a: 1)
|
11
14
|
# hash.merge!({'key' => 'value'})
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# hash[:a] = 1
|
18
|
+
# hash['key'] = 'value'
|
19
|
+
#
|
20
|
+
# @example MaxKeyValuePairs: 2 (default)
|
21
|
+
# # bad
|
12
22
|
# hash.merge!(a: 1, b: 2)
|
13
|
-
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# hash[:a] = 1
|
26
|
+
# hash[:b] = 2
|
27
|
+
class RedundantMerge < Base
|
28
|
+
extend AutoCorrector
|
29
|
+
|
14
30
|
AREF_ASGN = '%<receiver>s[%<key>s] = %<value>s'
|
15
31
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
16
32
|
|
@@ -20,28 +36,27 @@ module RuboCop
|
|
20
36
|
%<leading_space>send
|
21
37
|
RUBY
|
22
38
|
|
23
|
-
def_node_matcher :redundant_merge_candidate,
|
39
|
+
def_node_matcher :redundant_merge_candidate, <<~PATTERN
|
24
40
|
(send $!nil? :merge! [(hash $...) !kwsplat_type?])
|
25
41
|
PATTERN
|
26
42
|
|
27
|
-
def_node_matcher :modifier_flow_control?,
|
43
|
+
def_node_matcher :modifier_flow_control?, <<~PATTERN
|
28
44
|
[{if while until} modifier_form?]
|
29
45
|
PATTERN
|
30
46
|
|
31
47
|
def on_send(node)
|
32
48
|
each_redundant_merge(node) do |redundant_merge_node|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
correct_single_element(node, new_source)
|
49
|
+
message = message(node)
|
50
|
+
add_offense(redundant_merge_node, message: message) do |corrector|
|
51
|
+
redundant_merge_candidate(node) do |receiver, pairs|
|
52
|
+
new_source = to_assignments(receiver, pairs).join("\n")
|
53
|
+
|
54
|
+
if node.parent && pairs.size > 1
|
55
|
+
correct_multiple_elements(corrector, node, node.parent, new_source)
|
56
|
+
else
|
57
|
+
correct_single_element(corrector, node, new_source)
|
58
|
+
end
|
59
|
+
end
|
45
60
|
end
|
46
61
|
end
|
47
62
|
end
|
@@ -84,7 +99,7 @@ module RuboCop
|
|
84
99
|
!EachWithObjectInspector.new(node, receiver).value_used?
|
85
100
|
end
|
86
101
|
|
87
|
-
def correct_multiple_elements(node, parent, new_source)
|
102
|
+
def correct_multiple_elements(corrector, node, parent, new_source)
|
88
103
|
if modifier_flow_control?(parent)
|
89
104
|
new_source = rewrite_with_modifier(node, parent, new_source)
|
90
105
|
node = parent
|
@@ -93,11 +108,11 @@ module RuboCop
|
|
93
108
|
new_source.gsub!(/\n/, padding)
|
94
109
|
end
|
95
110
|
|
96
|
-
|
111
|
+
corrector.replace(node.source_range, new_source)
|
97
112
|
end
|
98
113
|
|
99
|
-
def correct_single_element(node, new_source)
|
100
|
-
|
114
|
+
def correct_single_element(corrector, node, new_source)
|
115
|
+
corrector.replace(node.source_range, new_source)
|
101
116
|
end
|
102
117
|
|
103
118
|
def to_assignments(receiver, pairs)
|
@@ -168,13 +183,11 @@ module RuboCop
|
|
168
183
|
end
|
169
184
|
|
170
185
|
def unwind(receiver)
|
171
|
-
while receiver.respond_to?(:send_type?) && receiver.send_type?
|
172
|
-
receiver, = *receiver
|
173
|
-
end
|
186
|
+
receiver, = *receiver while receiver.respond_to?(:send_type?) && receiver.send_type?
|
174
187
|
receiver
|
175
188
|
end
|
176
189
|
|
177
|
-
def_node_matcher :each_with_object_node,
|
190
|
+
def_node_matcher :each_with_object_node, <<~PATTERN
|
178
191
|
(block (send _ :each_with_object _) (args _ $_) ...)
|
179
192
|
PATTERN
|
180
193
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop identifies places where `sort { |a, b| a <=> b }`
|
7
|
+
# can be replaced with `sort`.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# array.sort { |a, b| a <=> b }
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# array.sort
|
15
|
+
#
|
16
|
+
class RedundantSortBlock < Base
|
17
|
+
include SortBlock
|
18
|
+
extend AutoCorrector
|
19
|
+
|
20
|
+
MSG = 'Use `sort` instead of `%<bad_method>s`.'
|
21
|
+
|
22
|
+
def on_block(node)
|
23
|
+
return unless (send, var_a, var_b, body = sort_with_block?(node))
|
24
|
+
|
25
|
+
replaceable_body?(body, var_a, var_b) do
|
26
|
+
range = sort_range(send, node)
|
27
|
+
|
28
|
+
add_offense(range, message: message(var_a, var_b)) do |corrector|
|
29
|
+
corrector.replace(range, 'sort')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def message(var_a, var_b)
|
37
|
+
bad_method = "sort { |#{var_a}, #{var_b}| #{var_a} <=> #{var_b} }"
|
38
|
+
format(MSG, bad_method: bad_method)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Performance
|
6
|
+
# This cop checks for redundant `String#chars`.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# str.chars[0..2]
|
11
|
+
# str.chars.slice(0..2)
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# str[0..2].chars
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# str.chars.first
|
18
|
+
# str.chars.first(2)
|
19
|
+
# str.chars.last
|
20
|
+
# str.chars.last(2)
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# str[0]
|
24
|
+
# str[0...2].chars
|
25
|
+
# str[-1]
|
26
|
+
# str[-2..-1].chars
|
27
|
+
#
|
28
|
+
# # bad
|
29
|
+
# str.chars.take(2)
|
30
|
+
# str.chars.drop(2)
|
31
|
+
# str.chars.length
|
32
|
+
# str.chars.size
|
33
|
+
# str.chars.empty?
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# str[0...2].chars
|
37
|
+
# str[2..-1].chars
|
38
|
+
# str.length
|
39
|
+
# str.size
|
40
|
+
# str.empty?
|
41
|
+
#
|
42
|
+
class RedundantStringChars < Base
|
43
|
+
include RangeHelp
|
44
|
+
extend AutoCorrector
|
45
|
+
|
46
|
+
MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
|
47
|
+
REPLACEABLE_METHODS = %i[[] slice first last take drop length size empty?].freeze
|
48
|
+
|
49
|
+
def_node_matcher :redundant_chars_call?, <<~PATTERN
|
50
|
+
(send $(send _ :chars) $#replaceable_method? $...)
|
51
|
+
PATTERN
|
52
|
+
|
53
|
+
def on_send(node)
|
54
|
+
return unless (receiver, method, args = redundant_chars_call?(node))
|
55
|
+
|
56
|
+
range = offense_range(receiver, node)
|
57
|
+
message = build_message(method, args)
|
58
|
+
|
59
|
+
add_offense(range, message: message) do |corrector|
|
60
|
+
range = correction_range(receiver, node)
|
61
|
+
replacement = build_good_method(method, args)
|
62
|
+
|
63
|
+
corrector.replace(range, replacement)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def replaceable_method?(method_name)
|
70
|
+
REPLACEABLE_METHODS.include?(method_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def offense_range(receiver, node)
|
74
|
+
range_between(receiver.loc.selector.begin_pos, node.loc.expression.end_pos)
|
75
|
+
end
|
76
|
+
|
77
|
+
def correction_range(receiver, node)
|
78
|
+
range_between(receiver.loc.dot.begin_pos, node.loc.expression.end_pos)
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_message(method, args)
|
82
|
+
good_method = build_good_method(method, args)
|
83
|
+
bad_method = build_bad_method(method, args)
|
84
|
+
format(MSG, good_method: good_method, bad_method: bad_method)
|
85
|
+
end
|
86
|
+
|
87
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
88
|
+
def build_good_method(method, args)
|
89
|
+
case method
|
90
|
+
when :[], :slice
|
91
|
+
"[#{build_call_args(args)}].chars"
|
92
|
+
when :first
|
93
|
+
if args.any?
|
94
|
+
"[0...#{args.first.source}].chars"
|
95
|
+
else
|
96
|
+
'[0]'
|
97
|
+
end
|
98
|
+
when :last
|
99
|
+
if args.any?
|
100
|
+
"[-#{args.first.source}..-1].chars"
|
101
|
+
else
|
102
|
+
'[-1]'
|
103
|
+
end
|
104
|
+
when :take
|
105
|
+
"[0...#{args.first.source}].chars"
|
106
|
+
when :drop
|
107
|
+
"[#{args.first.source}..-1].chars"
|
108
|
+
else
|
109
|
+
".#{method}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
113
|
+
|
114
|
+
def build_bad_method(method, args)
|
115
|
+
case method
|
116
|
+
when :[]
|
117
|
+
"chars[#{build_call_args(args)}]"
|
118
|
+
else
|
119
|
+
if args.any?
|
120
|
+
"chars.#{method}(#{build_call_args(args)})"
|
121
|
+
else
|
122
|
+
"chars.#{method}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def build_call_args(call_args_node)
|
128
|
+
call_args_node.map(&:source).join(', ')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -72,10 +72,8 @@ module RuboCop
|
|
72
72
|
# do_something($~)
|
73
73
|
# end
|
74
74
|
# end
|
75
|
-
class RegexpMatch <
|
76
|
-
extend
|
77
|
-
|
78
|
-
minimum_target_ruby_version 2.4
|
75
|
+
class RegexpMatch < Base
|
76
|
+
extend AutoCorrector
|
79
77
|
|
80
78
|
# Constants are included in this list because it is unlikely that
|
81
79
|
# someone will store `nil` as a constant and then use it for comparison
|
@@ -83,22 +81,22 @@ module RuboCop
|
|
83
81
|
MSG = 'Use `match?` instead of `%<current>s` when `MatchData` ' \
|
84
82
|
'is not used.'
|
85
83
|
|
86
|
-
def_node_matcher :match_method?,
|
84
|
+
def_node_matcher :match_method?, <<~PATTERN
|
87
85
|
{
|
88
86
|
(send _recv :match {regexp str sym})
|
89
87
|
(send {regexp str sym} :match _)
|
90
88
|
}
|
91
89
|
PATTERN
|
92
90
|
|
93
|
-
def_node_matcher :match_with_int_arg_method?,
|
91
|
+
def_node_matcher :match_with_int_arg_method?, <<~PATTERN
|
94
92
|
(send _recv :match _ (int ...))
|
95
93
|
PATTERN
|
96
94
|
|
97
|
-
def_node_matcher :match_operator?,
|
95
|
+
def_node_matcher :match_operator?, <<~PATTERN
|
98
96
|
(send !nil? {:=~ :!~} !nil?)
|
99
97
|
PATTERN
|
100
98
|
|
101
|
-
def_node_matcher :match_threequals?,
|
99
|
+
def_node_matcher :match_threequals?, <<~PATTERN
|
102
100
|
(send (regexp (str _) {(regopt) (regopt _)}) :=== !nil?)
|
103
101
|
PATTERN
|
104
102
|
|
@@ -109,7 +107,7 @@ module RuboCop
|
|
109
107
|
regexp.to_regexp.named_captures.empty?
|
110
108
|
end
|
111
109
|
|
112
|
-
MATCH_NODE_PATTERN =
|
110
|
+
MATCH_NODE_PATTERN = <<~PATTERN
|
113
111
|
{
|
114
112
|
#match_method?
|
115
113
|
#match_with_int_arg_method?
|
@@ -122,7 +120,7 @@ module RuboCop
|
|
122
120
|
def_node_matcher :match_node?, MATCH_NODE_PATTERN
|
123
121
|
def_node_search :search_match_nodes, MATCH_NODE_PATTERN
|
124
122
|
|
125
|
-
def_node_search :last_matches,
|
123
|
+
def_node_search :last_matches, <<~PATTERN
|
126
124
|
{
|
127
125
|
(send (const nil? :Regexp) :last_match)
|
128
126
|
(send (const nil? :Regexp) :last_match _)
|
@@ -145,27 +143,28 @@ module RuboCop
|
|
145
143
|
end
|
146
144
|
end
|
147
145
|
|
148
|
-
def autocorrect(node)
|
149
|
-
lambda do |corrector|
|
150
|
-
if match_method?(node) || match_with_int_arg_method?(node)
|
151
|
-
corrector.replace(node.loc.selector, 'match?')
|
152
|
-
elsif match_operator?(node) || match_threequals?(node)
|
153
|
-
recv, oper, arg = *node
|
154
|
-
correct_operator(corrector, recv, arg, oper)
|
155
|
-
elsif match_with_lvasgn?(node)
|
156
|
-
recv, arg = *node
|
157
|
-
correct_operator(corrector, recv, arg)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
146
|
private
|
163
147
|
|
164
148
|
def check_condition(cond)
|
165
149
|
match_node?(cond) do
|
166
150
|
return if last_match_used?(cond)
|
167
151
|
|
168
|
-
|
152
|
+
message = message(cond)
|
153
|
+
add_offense(cond, message: message) do |corrector|
|
154
|
+
autocorrect(corrector, cond)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def autocorrect(corrector, node)
|
160
|
+
if match_method?(node) || match_with_int_arg_method?(node)
|
161
|
+
corrector.replace(node.loc.selector, 'match?')
|
162
|
+
elsif match_operator?(node) || match_threequals?(node)
|
163
|
+
recv, oper, arg = *node
|
164
|
+
correct_operator(corrector, recv, arg, oper)
|
165
|
+
elsif match_with_lvasgn?(node)
|
166
|
+
recv, arg = *node
|
167
|
+
correct_operator(corrector, recv, arg)
|
169
168
|
end
|
170
169
|
end
|
171
170
|
|
@@ -235,10 +234,7 @@ module RuboCop
|
|
235
234
|
|
236
235
|
def scope_root(node)
|
237
236
|
node.each_ancestor.find do |ancestor|
|
238
|
-
ancestor.def_type? ||
|
239
|
-
ancestor.defs_type? ||
|
240
|
-
ancestor.class_type? ||
|
241
|
-
ancestor.module_type?
|
237
|
+
ancestor.def_type? || ancestor.defs_type? || ancestor.class_type? || ancestor.module_type?
|
242
238
|
end
|
243
239
|
end
|
244
240
|
|
@@ -256,6 +252,13 @@ module RuboCop
|
|
256
252
|
def correct_operator(corrector, recv, arg, oper = nil)
|
257
253
|
op_range = correction_range(recv, arg)
|
258
254
|
|
255
|
+
replace_with_match_predicate_method(corrector, recv, arg, op_range)
|
256
|
+
|
257
|
+
corrector.insert_after(arg.loc.expression, ')') unless op_range.source.end_with?('(')
|
258
|
+
corrector.insert_before(recv.loc.expression, '!') if oper == :!~
|
259
|
+
end
|
260
|
+
|
261
|
+
def replace_with_match_predicate_method(corrector, recv, arg, op_range)
|
259
262
|
if TYPES_IMPLEMENTING_MATCH.include?(recv.type)
|
260
263
|
corrector.replace(op_range, '.match?(')
|
261
264
|
elsif TYPES_IMPLEMENTING_MATCH.include?(arg.type)
|
@@ -264,9 +267,6 @@ module RuboCop
|
|
264
267
|
else
|
265
268
|
corrector.replace(op_range, '&.match?(')
|
266
269
|
end
|
267
|
-
|
268
|
-
corrector.insert_after(arg.loc.expression, ')')
|
269
|
-
corrector.insert_before(recv.loc.expression, '!') if oper == :!~
|
270
270
|
end
|
271
271
|
|
272
272
|
def swap_receiver_and_arg(corrector, recv, arg)
|