rubocop 0.36.0 → 0.37.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -2
- data/README.md +10 -1
- data/assets/output.html.erb +55 -1
- data/config/default.yml +9 -3
- data/config/disabled.yml +21 -0
- data/config/enabled.yml +11 -10
- data/lib/rubocop.rb +9 -2
- data/lib/rubocop/ast_node.rb +67 -19
- data/lib/rubocop/ast_node/builder.rb +1 -0
- data/lib/rubocop/ast_node/sexp.rb +1 -0
- data/lib/rubocop/ast_node/traversal.rb +171 -0
- data/lib/rubocop/cached_data.rb +4 -1
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +36 -20
- data/lib/rubocop/config_loader.rb +6 -5
- data/lib/rubocop/cop/commissioner.rb +27 -18
- data/lib/rubocop/cop/cop.rb +7 -6
- data/lib/rubocop/cop/lint/duplicated_key.rb +1 -8
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
- data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
- data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
- data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -0
- data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +9 -2
- data/lib/rubocop/cop/mixin/check_assignment.rb +1 -1
- data/lib/rubocop/cop/mixin/classish_length.rb +3 -4
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +8 -4
- data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +35 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/min_body_length.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +58 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -2
- data/lib/rubocop/cop/performance/case_when_splat.rb +7 -0
- data/lib/rubocop/cop/performance/casecmp.rb +56 -17
- data/lib/rubocop/cop/performance/redundant_block_call.rb +17 -3
- data/lib/rubocop/cop/performance/redundant_merge.rb +7 -1
- data/lib/rubocop/cop/performance/times_map.rb +3 -4
- data/lib/rubocop/cop/severity.rb +1 -1
- data/lib/rubocop/cop/style/align_hash.rb +1 -1
- data/lib/rubocop/cop/style/align_parameters.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -1
- data/lib/rubocop/cop/style/block_comments.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -0
- data/lib/rubocop/cop/style/copyright.rb +2 -2
- data/lib/rubocop/cop/style/documentation.rb +19 -29
- data/lib/rubocop/cop/style/each_with_object.rb +1 -1
- data/lib/rubocop/cop/style/else_alignment.rb +2 -2
- data/lib/rubocop/cop/style/encoding.rb +1 -1
- data/lib/rubocop/cop/style/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -12
- data/lib/rubocop/cop/style/guard_clause.rb +2 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -8
- data/lib/rubocop/cop/style/indent_assignment.rb +1 -1
- data/lib/rubocop/cop/style/indentation_width.rb +3 -7
- data/lib/rubocop/cop/style/method_call_parentheses.rb +2 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +3 -41
- data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +57 -0
- data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +65 -0
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +5 -4
- data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +62 -0
- data/lib/rubocop/cop/style/multiline_operation_indentation.rb +9 -3
- data/lib/rubocop/cop/style/mutable_constant.rb +18 -3
- data/lib/rubocop/cop/style/nested_modifier.rb +5 -2
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -1
- data/lib/rubocop/cop/style/next.rb +32 -11
- data/lib/rubocop/cop/style/option_hash.rb +1 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +13 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -7
- data/lib/rubocop/cop/style/send.rb +1 -1
- data/lib/rubocop/cop/style/space_around_keyword.rb +198 -0
- data/lib/rubocop/cop/style/space_around_operators.rb +2 -12
- data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -4
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +1 -0
- data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/zero_length_predicate.rb +55 -0
- data/lib/rubocop/cop/team.rb +30 -5
- data/lib/rubocop/cop/util.rb +16 -1
- data/lib/rubocop/cop/variable_force.rb +3 -12
- data/lib/rubocop/cop/variable_force/assignment.rb +3 -3
- data/lib/rubocop/cop/variable_force/locatable.rb +25 -6
- data/lib/rubocop/cop/variable_force/reference.rb +3 -3
- data/lib/rubocop/cop/variable_force/scope.rb +8 -7
- data/lib/rubocop/cop/variable_force/variable.rb +3 -3
- data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
- data/lib/rubocop/formatter/formatter_set.rb +2 -2
- data/lib/rubocop/node_pattern.rb +1 -1
- data/lib/rubocop/options.rb +10 -10
- data/lib/rubocop/path_util.rb +5 -0
- data/lib/rubocop/processed_source.rb +8 -2
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/token.rb +2 -2
- data/lib/rubocop/version.rb +1 -1
- data/relnotes/v0.30.1.md +1 -0
- data/relnotes/v0.33.0.md +1 -1
- data/relnotes/v0.36.0.md +2 -1
- data/relnotes/v0.37.0.md +200 -0
- data/rubocop.gemspec +2 -1
- metadata +28 -7
- data/lib/rubocop/cop/style/space_after_control_keyword.rb +0 -35
- data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +0 -38
@@ -13,20 +13,13 @@ module RuboCop
|
|
13
13
|
class DuplicatedKey < Cop
|
14
14
|
MSG = 'Duplicated key in hash literal.'.freeze
|
15
15
|
|
16
|
-
LITERALS = [:sym, :str, :float, :int].freeze
|
17
|
-
|
18
16
|
def on_hash(node)
|
19
17
|
keys = []
|
20
18
|
|
21
19
|
hash_pairs = *node
|
22
20
|
hash_pairs.each do |pair|
|
23
21
|
key, _value = *pair
|
24
|
-
if keys.include?(key) &&
|
25
|
-
add_offense(key, :expression)
|
26
|
-
elsif keys.include?(key) && key.type == :array
|
27
|
-
key.children.each do |child|
|
28
|
-
return false unless LITERALS.include?(child.type)
|
29
|
-
end
|
22
|
+
if keys.include?(key) && key.recursive_basic_literal?
|
30
23
|
add_offense(key, :expression)
|
31
24
|
end
|
32
25
|
keys << key
|
@@ -17,6 +17,7 @@ module RuboCop
|
|
17
17
|
final_node = begin_node.children.last
|
18
18
|
next unless final_node
|
19
19
|
next if special_keyword?(final_node)
|
20
|
+
next if final_node.xstr_type?
|
20
21
|
next unless final_node.literal?
|
21
22
|
|
22
23
|
add_offense(final_node, :expression)
|
@@ -37,7 +38,23 @@ module RuboCop
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def autocorrected_value(node)
|
40
|
-
|
41
|
+
case node.type
|
42
|
+
when :str
|
43
|
+
node.children.last
|
44
|
+
when :sym
|
45
|
+
autocorrected_value_for_symbol(node)
|
46
|
+
else
|
47
|
+
node.source
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def autocorrected_value_for_symbol(node)
|
52
|
+
end_pos =
|
53
|
+
node.loc.end ? node.loc.end.begin_pos : node.loc.expression.end_pos
|
54
|
+
|
55
|
+
Parser::Source::Range.new(node.source_range.source_buffer,
|
56
|
+
node.loc.begin.end_pos,
|
57
|
+
end_pos).source
|
41
58
|
end
|
42
59
|
end
|
43
60
|
end
|
@@ -26,6 +26,10 @@ module RuboCop
|
|
26
26
|
(block (send _ {:instance_eval :class_eval :module_eval} ...) ...)
|
27
27
|
PATTERN
|
28
28
|
|
29
|
+
def_node_matcher :class_or_module_new_call?, <<-PATTERN
|
30
|
+
(block (send (const nil {:Class :Module}) :new) ...)
|
31
|
+
PATTERN
|
32
|
+
|
29
33
|
def on_method_def(node, _method_name, _args, _body)
|
30
34
|
find_nested_defs(node) do |nested_def_node|
|
31
35
|
add_offense(nested_def_node, :expression)
|
@@ -36,7 +40,7 @@ module RuboCop
|
|
36
40
|
node.each_child_node do |child|
|
37
41
|
if child.def_type? || child.defs_type?
|
38
42
|
yield child
|
39
|
-
elsif !eval_call?(child)
|
43
|
+
elsif !(eval_call?(child) || class_or_module_new_call?(child))
|
40
44
|
find_nested_defs(child, &block)
|
41
45
|
end
|
42
46
|
end
|
@@ -128,7 +128,7 @@ module RuboCop
|
|
128
128
|
def cop_range(comment, cop)
|
129
129
|
matching_range(comment.loc.expression, cop) ||
|
130
130
|
matching_range(comment.loc.expression, cop.split('/').last) ||
|
131
|
-
|
131
|
+
raise("Couldn't find #{cop} in comment: #{comment.text}")
|
132
132
|
end
|
133
133
|
|
134
134
|
def matching_range(haystack, needle)
|
@@ -22,13 +22,20 @@ module RuboCop
|
|
22
22
|
SPACE * node.loc.column
|
23
23
|
end
|
24
24
|
|
25
|
+
def display_column(range)
|
26
|
+
line = processed_source.lines[range.line - 1]
|
27
|
+
line[0, range.column].display_width
|
28
|
+
end
|
29
|
+
|
25
30
|
def check_alignment(items, base_column = nil)
|
26
|
-
|
31
|
+
unless items.empty?
|
32
|
+
base_column ||= display_column(items.first.source_range)
|
33
|
+
end
|
27
34
|
prev_line = -1
|
28
35
|
items.each do |current|
|
29
36
|
if current.loc.line > prev_line &&
|
30
37
|
begins_its_line?(current.source_range)
|
31
|
-
@column_delta = base_column - current.
|
38
|
+
@column_delta = base_column - display_column(current.source_range)
|
32
39
|
if @column_delta != 0
|
33
40
|
expr = current.source_range
|
34
41
|
if offenses.any? { |o| within?(expr, o.location) }
|
@@ -13,8 +13,7 @@ module RuboCop
|
|
13
13
|
body_line_numbers = line_range(node).to_a[1...-1]
|
14
14
|
|
15
15
|
target_line_numbers = body_line_numbers -
|
16
|
-
|
17
|
-
line_numbers_of_inner_thing(node, :class)
|
16
|
+
line_numbers_of_inner_nodes(node, :module, :class)
|
18
17
|
|
19
18
|
target_line_numbers.reduce(0) do |length, line_number|
|
20
19
|
source_line = processed_source[line_number]
|
@@ -23,10 +22,10 @@ module RuboCop
|
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
26
|
-
def
|
25
|
+
def line_numbers_of_inner_nodes(node, *types)
|
27
26
|
line_numbers = Set.new
|
28
27
|
|
29
|
-
node.each_descendant(
|
28
|
+
node.each_descendant(*types) do |inner_node|
|
30
29
|
line_range = line_range(inner_node)
|
31
30
|
line_numbers.merge(line_range)
|
32
31
|
end
|
@@ -77,14 +77,18 @@ module RuboCop
|
|
77
77
|
alias unrecognized_style_detected no_acceptable_style!
|
78
78
|
|
79
79
|
def style
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
@enforced_style ||= begin
|
81
|
+
s = cop_config[parameter_name].to_sym
|
82
|
+
unless supported_styles.include?(s)
|
83
|
+
raise "Unknown style #{s} selected!"
|
84
|
+
end
|
85
|
+
s
|
86
|
+
end
|
83
87
|
end
|
84
88
|
|
85
89
|
def alternative_style
|
86
90
|
if supported_styles.size != 2
|
87
|
-
|
91
|
+
raise 'alternative_style can only be used when there are exactly ' \
|
88
92
|
'2 SupportedStyles'
|
89
93
|
end
|
90
94
|
(supported_styles - [style]).first
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
include ConfigurableEnforcedStyle
|
10
10
|
|
11
11
|
SNAKE_CASE = /^@{0,2}[\da-z_]+[!?=]?$/
|
12
|
-
CAMEL_CASE = /^@{0,2}[a-z][\da-zA-Z]+[!?=]?$/
|
12
|
+
CAMEL_CASE = /^@{0,2}_?[a-z][\da-zA-Z]+[!?=]?$/
|
13
13
|
|
14
14
|
def check_name(node, name, name_range)
|
15
15
|
return if operator?(name)
|
@@ -22,7 +22,8 @@ module RuboCop
|
|
22
22
|
return unless end_loc # Discard modifier forms of if/while/until.
|
23
23
|
|
24
24
|
matching = align_ranges.select do |_, range|
|
25
|
-
range.line == end_loc.line ||
|
25
|
+
range.line == end_loc.line ||
|
26
|
+
effective_column(range) == end_loc.column
|
26
27
|
end
|
27
28
|
|
28
29
|
if matching.key?(style)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
# Common functionality for dealing with frozen string literals.
|
7
|
+
module FrozenStringLiteral
|
8
|
+
module_function
|
9
|
+
|
10
|
+
FROZEN_STRING_LITERAL = '# frozen_string_literal:'.freeze
|
11
|
+
FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'.freeze
|
12
|
+
FROZEN_STRING_LITERAL_TYPES = [:str, :dstr].freeze
|
13
|
+
|
14
|
+
def frozen_string_literal_comment_exists?(processed_source,
|
15
|
+
comment = FROZEN_STRING_LITERAL)
|
16
|
+
first_three_lines =
|
17
|
+
[processed_source[0], processed_source[1], processed_source[2]]
|
18
|
+
first_three_lines.compact!
|
19
|
+
first_three_lines.any? do |line|
|
20
|
+
line.start_with?(comment)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def frozen_string_literals_enabled?(processed_source)
|
25
|
+
ruby_version = processed_source.ruby_version
|
26
|
+
return false unless ruby_version
|
27
|
+
return true if ruby_version >= 3.0
|
28
|
+
return false unless ruby_version >= 2.3
|
29
|
+
frozen_string_literal_comment_exists?(
|
30
|
+
processed_source, FROZEN_STRING_LITERAL_ENABLED
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RuboCop
|
5
|
+
module Cop
|
6
|
+
# Common functionality for checking that the closing brace of a literal is
|
7
|
+
# symmetrical with respect to the opening brace and contained elements.
|
8
|
+
module MultilineLiteralBraceLayout
|
9
|
+
def check_brace_layout(node)
|
10
|
+
return unless node.loc.begin # Ignore implicit literals.
|
11
|
+
return if children(node).empty? # Ignore empty literals.
|
12
|
+
|
13
|
+
if opening_brace_on_same_line?(node)
|
14
|
+
return if closing_brace_on_same_line?(node)
|
15
|
+
|
16
|
+
add_offense(node, :expression, self.class::SAME_LINE_MESSAGE)
|
17
|
+
else
|
18
|
+
return unless closing_brace_on_same_line?(node)
|
19
|
+
|
20
|
+
add_offense(node, :expression, self.class::NEW_LINE_MESSAGE)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def autocorrect(node)
|
25
|
+
if closing_brace_on_same_line?(node)
|
26
|
+
lambda do |corrector|
|
27
|
+
corrector.insert_before(node.loc.end, "\n".freeze)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
range = Parser::Source::Range.new(
|
31
|
+
node.source_range.source_buffer,
|
32
|
+
children(node).last.source_range.end_pos,
|
33
|
+
node.loc.end.begin_pos)
|
34
|
+
|
35
|
+
->(corrector) { corrector.remove(range) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def children(node)
|
42
|
+
node.children
|
43
|
+
end
|
44
|
+
|
45
|
+
# This method depends on the fact that we have guarded
|
46
|
+
# against implicit and empty literals.
|
47
|
+
def opening_brace_on_same_line?(node)
|
48
|
+
node.loc.begin.line == children(node).first.loc.first_line
|
49
|
+
end
|
50
|
+
|
51
|
+
# This method depends on the fact that we have guarded
|
52
|
+
# against implicit and empty literals.
|
53
|
+
def closing_brace_on_same_line?(node)
|
54
|
+
node.loc.end.line == children(node).last.loc.last_line
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -81,10 +81,11 @@ module RuboCop
|
|
81
81
|
node.children
|
82
82
|
end
|
83
83
|
|
84
|
-
#
|
84
|
+
# No need to process anything if the whole node is not multiline
|
85
|
+
# Without the 2nd check, Foo.new({}) is considered multiline, which
|
85
86
|
# it should not be. Essentially, if there are no elements, the
|
86
87
|
# expression can not be multiline.
|
87
|
-
return if elements.empty?
|
88
|
+
return if !node.multiline? || elements.empty?
|
88
89
|
|
89
90
|
items = elements.map(&:source_range)
|
90
91
|
if style == :consistent_comma
|
@@ -63,6 +63,11 @@ module RuboCop
|
|
63
63
|
PERCENT_I = '%i'.freeze
|
64
64
|
PERCENT_CAPITAL_I = '%I'.freeze
|
65
65
|
|
66
|
+
def initialize(*)
|
67
|
+
super
|
68
|
+
@reordered_splat_condition = false
|
69
|
+
end
|
70
|
+
|
66
71
|
def on_case(node)
|
67
72
|
_case_branch, *when_branches, _else_branch = *node
|
68
73
|
when_conditions =
|
@@ -85,6 +90,8 @@ module RuboCop
|
|
85
90
|
if variable.array_type?
|
86
91
|
correct_array_literal(condition, variable)
|
87
92
|
else
|
93
|
+
return if @reordered_splat_condition
|
94
|
+
@reordered_splat_condition = true
|
88
95
|
reorder_splat_condition(node)
|
89
96
|
end
|
90
97
|
end
|
@@ -9,43 +9,82 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# @bad
|
12
|
-
# '
|
12
|
+
# 'aBc'.downcase == 'abc'
|
13
13
|
# 'abc'.upcase.eql? 'ABC'
|
14
|
+
# 'abc' == 'ABC'.downcase
|
15
|
+
# 'ABC'.eql? 'abc'.upcase
|
16
|
+
# 'abc'.downcase == 'abc'.downcase
|
14
17
|
#
|
15
18
|
# @good
|
16
|
-
# '
|
19
|
+
# 'aBc'.casecmp('ABC').zero?
|
20
|
+
# 'abc'.casecmp('abc').zero?
|
21
|
+
# 'abc'.casecmp('ABC'.downcase).zero?
|
17
22
|
class Casecmp < Cop
|
23
|
+
include IgnoredNode
|
24
|
+
|
18
25
|
MSG = 'Use `casecmp` instead of `%s %s`.'.freeze
|
26
|
+
CASE_METHODS = [:downcase, :upcase].freeze
|
19
27
|
|
20
28
|
def_node_matcher :downcase_eq, <<-END
|
21
|
-
(send $(send _ ${:downcase :upcase}) ${:== :eql?} _)
|
29
|
+
(send $(send _ ${:downcase :upcase}) ${:== :eql? :!=} $_)
|
30
|
+
END
|
31
|
+
|
32
|
+
def_node_matcher :eq_downcase, <<-END
|
33
|
+
(send _ ${:== :eql? :!=} $(send _ ${:downcase :upcase}))
|
22
34
|
END
|
23
35
|
|
24
36
|
def on_send(node)
|
25
|
-
|
26
|
-
|
37
|
+
return if part_of_ignored_node?(node)
|
38
|
+
|
39
|
+
downcase_eq(node) do |send_downcase, case_method, eq_method, other|
|
40
|
+
*_, method = *other
|
41
|
+
if CASE_METHODS.include?(method)
|
42
|
+
range = node.loc.expression
|
43
|
+
ignore_node(node)
|
44
|
+
else
|
45
|
+
range = node.loc.selector.join(send_downcase.loc.selector)
|
46
|
+
end
|
47
|
+
|
27
48
|
add_offense(node, range, format(MSG, case_method, eq_method))
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
52
|
+
eq_downcase(node) do |eq_method, send_downcase, case_method|
|
53
|
+
range = node.loc.selector.join(send_downcase.loc.selector)
|
54
|
+
add_offense(node, range, format(MSG, eq_method, case_method))
|
28
55
|
end
|
29
56
|
end
|
30
57
|
|
31
58
|
def autocorrect(node)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
59
|
+
downcase_eq(node) do
|
60
|
+
receiver, method, arg = *node
|
61
|
+
variable, = *receiver
|
62
|
+
return correction(node, receiver, method, arg, variable)
|
63
|
+
end
|
64
|
+
|
65
|
+
eq_downcase(node) do
|
66
|
+
arg, method, receiver = *node
|
67
|
+
variable, = *receiver
|
68
|
+
return correction(node, receiver, method, arg, variable)
|
69
|
+
end
|
70
|
+
end
|
36
71
|
|
72
|
+
private
|
73
|
+
|
74
|
+
def correction(node, _receiver, method, arg, variable)
|
37
75
|
lambda do |corrector|
|
76
|
+
corrector.insert_before(node.loc.expression, '!') if method == :!=
|
77
|
+
|
38
78
|
# we want resulting call to be parenthesized
|
39
79
|
# if arg already includes one or more sets of parens, don't add more
|
40
80
|
# or if method call already used parens, again, don't add more
|
41
|
-
if arg.
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
81
|
+
replacement = if arg.send_type? || !parentheses?(arg)
|
82
|
+
"#{variable.source}.casecmp(#{arg.source}).zero?"
|
83
|
+
else
|
84
|
+
"#{variable.source}.casecmp#{arg.source}.zero?"
|
85
|
+
end
|
86
|
+
|
87
|
+
corrector.replace(node.loc.expression, replacement)
|
49
88
|
end
|
50
89
|
end
|
51
90
|
end
|