rubocop 0.93.0 → 1.3.0
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 +36 -16
- data/config/default.yml +207 -77
- data/exe/rubocop +1 -1
- data/lib/rubocop.rb +16 -2
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
- data/lib/rubocop/cli/command/version.rb +1 -1
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_loader.rb +26 -8
- data/lib/rubocop/config_loader_resolver.rb +7 -5
- data/lib/rubocop/config_validator.rb +7 -6
- data/lib/rubocop/cop/badge.rb +9 -24
- data/lib/rubocop/cop/base.rb +16 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +26 -6
- data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
- data/lib/rubocop/cop/commissioner.rb +37 -23
- data/lib/rubocop/cop/corrector.rb +3 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/force.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +3 -3
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +4 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +3 -4
- data/lib/rubocop/cop/layout/class_structure.rb +7 -0
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +15 -2
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -3
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
- data/lib/rubocop/cop/layout/hash_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/line_length.rb +8 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +24 -18
- data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +35 -13
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -3
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +23 -2
- data/lib/rubocop/cop/lint/debugger.rb +17 -28
- data/lib/rubocop/cop/lint/duplicate_branch.rb +93 -0
- data/lib/rubocop/cop/lint/duplicate_case_condition.rb +2 -12
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
- data/lib/rubocop/cop/lint/else_layout.rb +29 -3
- data/lib/rubocop/cop/lint/empty_block.rb +82 -0
- data/lib/rubocop/cop/lint/empty_class.rb +93 -0
- data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +38 -6
- data/lib/rubocop/cop/lint/loop.rb +4 -4
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +14 -0
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +58 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +19 -16
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +44 -11
- data/lib/rubocop/cop/lint/shadowed_exception.rb +4 -5
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +95 -0
- data/lib/rubocop/cop/lint/to_json.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +185 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_method_definition.rb +2 -4
- data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -1
- data/lib/rubocop/cop/metrics/class_length.rb +9 -3
- data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
- data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -4
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +12 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +11 -5
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +67 -18
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
- data/lib/rubocop/cop/naming/variable_number.rb +98 -8
- data/lib/rubocop/cop/offense.rb +3 -3
- data/lib/rubocop/cop/security/open.rb +12 -10
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -3
- data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +0 -4
- data/lib/rubocop/cop/style/case_like_if.rb +0 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +19 -4
- data/lib/rubocop/cop/style/collection_compact.rb +91 -0
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +162 -0
- data/lib/rubocop/cop/style/double_negation.rb +6 -1
- data/lib/rubocop/cop/style/format_string_token.rb +47 -2
- data/lib/rubocop/cop/style/hash_syntax.rb +3 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +7 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +37 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +7 -3
- data/lib/rubocop/cop/style/infinite_loop.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +12 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -11
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
- data/lib/rubocop/cop/style/mixin_grouping.rb +0 -4
- data/lib/rubocop/cop/style/multiple_comparison.rb +55 -7
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +104 -0
- data/lib/rubocop/cop/style/nil_lambda.rb +52 -0
- data/lib/rubocop/cop/style/raise_args.rb +21 -6
- data/lib/rubocop/cop/style/redundant_begin.rb +14 -4
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +7 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +3 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
- data/lib/rubocop/cop/style/semicolon.rb +3 -0
- data/lib/rubocop/cop/style/static_class.rb +97 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +13 -1
- data/lib/rubocop/cop/style/swap_values.rb +108 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +9 -0
- data/lib/rubocop/cop/team.rb +6 -1
- data/lib/rubocop/cop/util.rb +5 -1
- data/lib/rubocop/ext/regexp_node.rb +17 -9
- data/lib/rubocop/ext/regexp_parser.rb +84 -0
- data/lib/rubocop/formatter/formatter_set.rb +2 -1
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +47 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/magic_comment.rb +2 -2
- data/lib/rubocop/options.rb +6 -1
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/target_ruby.rb +57 -1
- data/lib/rubocop/version.rb +56 -6
- metadata +21 -5
@@ -34,6 +34,7 @@ module RuboCop
|
|
34
34
|
# this is rarely a problem in practice.
|
35
35
|
class DoubleNegation < Base
|
36
36
|
include ConfigurableEnforcedStyle
|
37
|
+
extend AutoCorrector
|
37
38
|
|
38
39
|
MSG = 'Avoid the use of double negation (`!!`).'
|
39
40
|
RESTRICT_ON_SEND = %i[!].freeze
|
@@ -44,7 +45,11 @@ module RuboCop
|
|
44
45
|
return unless double_negative?(node) && node.prefix_bang?
|
45
46
|
return if style == :allowed_in_returns && allowed_in_returns?(node)
|
46
47
|
|
47
|
-
|
48
|
+
location = node.loc.selector
|
49
|
+
add_offense(location) do |corrector|
|
50
|
+
corrector.remove(location)
|
51
|
+
corrector.insert_after(node, '.nil?')
|
52
|
+
end
|
48
53
|
end
|
49
54
|
|
50
55
|
private
|
@@ -37,6 +37,27 @@ module RuboCop
|
|
37
37
|
#
|
38
38
|
# # good
|
39
39
|
# format('%s', 'Hello')
|
40
|
+
#
|
41
|
+
# It is allowed to contain unannotated token
|
42
|
+
# if the number of them is less than or equals to
|
43
|
+
# `MaxUnannotatedPlaceholdersAllowed`.
|
44
|
+
#
|
45
|
+
# @example MaxUnannotatedPlaceholdersAllowed: 0
|
46
|
+
#
|
47
|
+
# # bad
|
48
|
+
# format('%06d', 10)
|
49
|
+
# format('%s %s.', 'Hello', 'world')
|
50
|
+
#
|
51
|
+
# # good
|
52
|
+
# format('%<number>06d', number: 10)
|
53
|
+
#
|
54
|
+
# @example MaxUnannotatedPlaceholdersAllowed: 1 (default)
|
55
|
+
#
|
56
|
+
# # bad
|
57
|
+
# format('%s %s.', 'Hello', 'world')
|
58
|
+
#
|
59
|
+
# # good
|
60
|
+
# format('%06d', 10)
|
40
61
|
class FormatStringToken < Base
|
41
62
|
include ConfigurableEnforcedStyle
|
42
63
|
|
@@ -44,8 +65,12 @@ module RuboCop
|
|
44
65
|
return unless node.value.include?('%')
|
45
66
|
return if node.each_ancestor(:xstr, :regexp).any?
|
46
67
|
|
47
|
-
|
48
|
-
|
68
|
+
detections = collect_detections(node)
|
69
|
+
return if detections.empty?
|
70
|
+
return if allowed_unannotated?(detections)
|
71
|
+
|
72
|
+
detections.each do |detected_style, token_range|
|
73
|
+
if detected_style == style
|
49
74
|
correct_style_detected
|
50
75
|
else
|
51
76
|
style_detected(detected_style)
|
@@ -112,6 +137,26 @@ module RuboCop
|
|
112
137
|
yield(detected_style, token)
|
113
138
|
end
|
114
139
|
end
|
140
|
+
|
141
|
+
def collect_detections(node)
|
142
|
+
detections = []
|
143
|
+
tokens(node) do |detected_style, token_range|
|
144
|
+
unless unannotated_format?(node, detected_style)
|
145
|
+
detections << [detected_style, token_range]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
detections
|
149
|
+
end
|
150
|
+
|
151
|
+
def allowed_unannotated?(detections)
|
152
|
+
return false if detections.size > max_unannotated_placeholders_allowed
|
153
|
+
|
154
|
+
detections.all? { |detected_style,| detected_style == :unannotated }
|
155
|
+
end
|
156
|
+
|
157
|
+
def max_unannotated_placeholders_allowed
|
158
|
+
cop_config['MaxUnannotatedPlaceholdersAllowed']
|
159
|
+
end
|
115
160
|
end
|
116
161
|
end
|
117
162
|
end
|
@@ -97,10 +97,10 @@ module RuboCop
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def no_mixed_keys_check(pairs)
|
100
|
-
if
|
101
|
-
check(pairs, ':', MSG_NO_MIXED_KEYS)
|
102
|
-
else
|
100
|
+
if sym_indices?(pairs)
|
103
101
|
check(pairs, pairs.first.inverse_delimiter, MSG_NO_MIXED_KEYS)
|
102
|
+
else
|
103
|
+
check(pairs, ':', MSG_NO_MIXED_KEYS)
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
@@ -3,8 +3,13 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# This cop checks for identical
|
7
|
-
# each branch of a conditional
|
6
|
+
# This cop checks for identical expressions at the beginning or end of
|
7
|
+
# each branch of a conditional expression. Such expressions should normally
|
8
|
+
# be placed outside the conditional expression - before or after it.
|
9
|
+
#
|
10
|
+
# NOTE: The cop is poorly named and some people might think that it actually
|
11
|
+
# checks for duplicated conditional branches. The name will probably be changed
|
12
|
+
# in a future major RuboCop release.
|
8
13
|
#
|
9
14
|
# @example
|
10
15
|
# # bad
|
@@ -59,6 +59,9 @@ module RuboCop
|
|
59
59
|
# end
|
60
60
|
#
|
61
61
|
class IfInsideElse < Base
|
62
|
+
include RangeHelp
|
63
|
+
extend AutoCorrector
|
64
|
+
|
62
65
|
MSG = 'Convert `if` nested inside `else` to `elsif`.'
|
63
66
|
|
64
67
|
def on_if(node)
|
@@ -69,11 +72,44 @@ module RuboCop
|
|
69
72
|
return unless else_branch&.if_type? && else_branch&.if?
|
70
73
|
return if allow_if_modifier_in_else_branch?(else_branch)
|
71
74
|
|
72
|
-
add_offense(else_branch.loc.keyword)
|
75
|
+
add_offense(else_branch.loc.keyword) do |corrector|
|
76
|
+
autocorrect(corrector, else_branch)
|
77
|
+
end
|
73
78
|
end
|
74
79
|
|
75
80
|
private
|
76
81
|
|
82
|
+
def autocorrect(corrector, node)
|
83
|
+
if node.modifier_form?
|
84
|
+
correct_to_elsif_from_modifier_form(corrector, node)
|
85
|
+
end_range = node.parent.loc.end
|
86
|
+
else
|
87
|
+
correct_to_elsif_from_if_inside_else_form(corrector, node, node.condition)
|
88
|
+
end_range = node.loc.end
|
89
|
+
end
|
90
|
+
corrector.remove(range_by_whole_lines(end_range, include_final_newline: true))
|
91
|
+
corrector.remove(
|
92
|
+
range_by_whole_lines(node.if_branch.source_range, include_final_newline: true)
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def correct_to_elsif_from_modifier_form(corrector, node)
|
97
|
+
corrector.replace(node.parent.loc.else, <<~RUBY.chop)
|
98
|
+
elsif #{node.condition.source}
|
99
|
+
#{indent(node.if_branch)}#{node.if_branch.source}
|
100
|
+
end
|
101
|
+
RUBY
|
102
|
+
end
|
103
|
+
|
104
|
+
def correct_to_elsif_from_if_inside_else_form(corrector, node, condition)
|
105
|
+
corrector.replace(node.parent.loc.else, "elsif #{condition.source}")
|
106
|
+
if_condition_range = range_between(
|
107
|
+
node.loc.keyword.begin_pos, condition.source_range.end_pos
|
108
|
+
)
|
109
|
+
corrector.replace(if_condition_range, node.if_branch.source)
|
110
|
+
corrector.remove(condition)
|
111
|
+
end
|
112
|
+
|
77
113
|
def allow_if_modifier_in_else_branch?(else_branch)
|
78
114
|
allow_if_modifier? && else_branch&.modifier_form?
|
79
115
|
end
|
@@ -21,14 +21,18 @@ module RuboCop
|
|
21
21
|
# Foo.do_something
|
22
22
|
# end
|
23
23
|
#
|
24
|
-
#
|
24
|
+
# do_something_with_a_long_name(arg) if long_condition_that_prevents_code_fit_on_single_line
|
25
25
|
#
|
26
26
|
# # good
|
27
27
|
# do_stuff(bar) if condition
|
28
28
|
# Foo.do_something unless qux.empty?
|
29
29
|
#
|
30
|
-
# if
|
31
|
-
#
|
30
|
+
# if long_condition_that_prevents_code_fit_on_single_line
|
31
|
+
# do_something_with_a_long_name(arg)
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# if short_condition # a long comment that makes it too long if it were just a single line
|
35
|
+
# do_something
|
32
36
|
# end
|
33
37
|
class IfUnlessModifier < Base
|
34
38
|
include StatementModifier
|
@@ -5,6 +5,10 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# Use `Kernel#loop` for infinite loops.
|
7
7
|
#
|
8
|
+
# This cop is marked as unsafe as the rule does not necessarily
|
9
|
+
# apply if the body might raise a `StopIteration` exception; contrary to
|
10
|
+
# other infinite loops, `Kernel#loop` silently rescues that and returns `nil`.
|
11
|
+
#
|
8
12
|
# @example
|
9
13
|
# # bad
|
10
14
|
# while true
|
@@ -34,6 +34,10 @@ module RuboCop
|
|
34
34
|
add_offense(node) do |corrector|
|
35
35
|
if node.parent.find(&:kwoptarg_type?) == node
|
36
36
|
corrector.insert_before(node, "#{kwarg_nodes.map(&:source).join(', ')}, ")
|
37
|
+
|
38
|
+
arguments = node.each_ancestor(:def, :defs).first.arguments
|
39
|
+
append_newline_to_last_kwoptarg(arguments, corrector) unless parentheses?(arguments)
|
40
|
+
|
37
41
|
remove_kwargs(kwarg_nodes, corrector)
|
38
42
|
end
|
39
43
|
end
|
@@ -41,6 +45,14 @@ module RuboCop
|
|
41
45
|
|
42
46
|
private
|
43
47
|
|
48
|
+
def append_newline_to_last_kwoptarg(arguments, corrector)
|
49
|
+
last_argument = arguments.last
|
50
|
+
return if last_argument.kwrestarg_type? || last_argument.blockarg_type?
|
51
|
+
|
52
|
+
last_kwoptarg = arguments.reverse.find(&:kwoptarg_type?)
|
53
|
+
corrector.insert_after(last_kwoptarg, "\n")
|
54
|
+
end
|
55
|
+
|
44
56
|
def remove_kwargs(kwarg_nodes, corrector)
|
45
57
|
kwarg_nodes.each do |kwarg|
|
46
58
|
with_space = range_with_surrounding_space(range: kwarg.source_range)
|
@@ -144,25 +144,22 @@ module RuboCop
|
|
144
144
|
# # good
|
145
145
|
# Array 1
|
146
146
|
class MethodCallWithArgsParentheses < Base
|
147
|
+
require_relative 'method_call_with_args_parentheses/omit_parentheses'
|
148
|
+
require_relative 'method_call_with_args_parentheses/require_parentheses'
|
149
|
+
|
147
150
|
include ConfigurableEnforcedStyle
|
148
151
|
include IgnoredMethods
|
149
152
|
include IgnoredPattern
|
153
|
+
include RequireParentheses
|
154
|
+
include OmitParentheses
|
150
155
|
extend AutoCorrector
|
151
156
|
|
152
|
-
def
|
153
|
-
|
154
|
-
return unless style_configured?
|
155
|
-
|
156
|
-
case style
|
157
|
-
when :require_parentheses
|
158
|
-
extend RequireParentheses
|
159
|
-
when :omit_parentheses
|
160
|
-
extend OmitParentheses
|
161
|
-
end
|
157
|
+
def on_send(node)
|
158
|
+
send(style, node) # call require_parentheses or omit_parentheses
|
162
159
|
end
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
alias on_csend on_send
|
161
|
+
alias on_super on_send
|
162
|
+
alias on_yield on_send
|
166
163
|
|
167
164
|
private
|
168
165
|
|
@@ -7,15 +7,19 @@ module RuboCop
|
|
7
7
|
# Style omit_parentheses
|
8
8
|
module OmitParentheses
|
9
9
|
TRAILING_WHITESPACE_REGEX = /\s+\Z/.freeze
|
10
|
+
OMIT_MSG = 'Omit parentheses for method calls with arguments.'
|
11
|
+
private_constant :OMIT_MSG
|
10
12
|
|
11
|
-
|
13
|
+
private
|
14
|
+
|
15
|
+
def omit_parentheses(node)
|
12
16
|
return unless node.parenthesized?
|
13
17
|
return if node.implicit_call?
|
14
18
|
return if super_call_without_arguments?(node)
|
15
19
|
return if allowed_camel_case_method_call?(node)
|
16
20
|
return if legitimate_call_with_parentheses?(node)
|
17
21
|
|
18
|
-
add_offense(offense_range(node)) do |corrector|
|
22
|
+
add_offense(offense_range(node), message: OMIT_MSG) do |corrector|
|
19
23
|
if parentheses_at_the_end_of_multiline_call?(node)
|
20
24
|
corrector.replace(args_begin(node), ' \\')
|
21
25
|
else
|
@@ -24,20 +28,11 @@ module RuboCop
|
|
24
28
|
corrector.remove(node.loc.end)
|
25
29
|
end
|
26
30
|
end
|
27
|
-
alias on_csend on_send
|
28
|
-
alias on_super on_send
|
29
|
-
alias on_yield on_send
|
30
|
-
|
31
|
-
private
|
32
31
|
|
33
32
|
def offense_range(node)
|
34
33
|
node.loc.begin.join(node.loc.end)
|
35
34
|
end
|
36
35
|
|
37
|
-
def message(_range = nil)
|
38
|
-
'Omit parentheses for method calls with arguments.'
|
39
|
-
end
|
40
|
-
|
41
36
|
def super_call_without_arguments?(node)
|
42
37
|
node.super_type? && node.arguments.none?
|
43
38
|
end
|
@@ -6,27 +6,23 @@ module RuboCop
|
|
6
6
|
class MethodCallWithArgsParentheses
|
7
7
|
# Style require_parentheses
|
8
8
|
module RequireParentheses
|
9
|
-
|
9
|
+
REQUIRE_MSG = 'Use parentheses for method calls with arguments.'
|
10
|
+
private_constant :REQUIRE_MSG
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def require_parentheses(node)
|
10
15
|
return if ignored_method?(node.method_name)
|
11
16
|
return if matches_ignored_pattern?(node.method_name)
|
12
17
|
return if eligible_for_parentheses_omission?(node)
|
13
18
|
return unless node.arguments? && !node.parenthesized?
|
14
19
|
|
15
|
-
add_offense(node) do |corrector|
|
20
|
+
add_offense(node, message: REQUIRE_MSG) do |corrector|
|
16
21
|
corrector.replace(args_begin(node), '(')
|
17
22
|
|
18
23
|
corrector.insert_after(args_end(node), ')') unless args_parenthesized?(node)
|
19
24
|
end
|
20
25
|
end
|
21
|
-
alias on_csend on_send
|
22
|
-
alias on_super on_send
|
23
|
-
alias on_yield on_send
|
24
|
-
|
25
|
-
def message(_node = nil)
|
26
|
-
'Use parentheses for method calls with arguments.'
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
26
|
|
31
27
|
def eligible_for_parentheses_omission?(node)
|
32
28
|
node.operator_method? || node.setter_method? || ignored_macro?(node)
|
@@ -4,7 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# This cop checks against comparing a variable with multiple items, where
|
7
|
-
# `Array#include?` could be used instead
|
7
|
+
# `Array#include?`, `Set#include?` or a `case` could be used instead
|
8
|
+
# to avoid code repetition.
|
9
|
+
# It accepts comparisons of multiple method calls to avoid unnecessary method calls
|
10
|
+
# by default. It can be configured by `AllowMethodComparison` option.
|
8
11
|
#
|
9
12
|
# @example
|
10
13
|
# # bad
|
@@ -14,25 +17,63 @@ module RuboCop
|
|
14
17
|
# # good
|
15
18
|
# a = 'a'
|
16
19
|
# foo if ['a', 'b', 'c'].include?(a)
|
20
|
+
#
|
21
|
+
# VALUES = Set['a', 'b', 'c'].freeze
|
22
|
+
# # elsewhere...
|
23
|
+
# foo if VALUES.include?(a)
|
24
|
+
#
|
25
|
+
# case foo
|
26
|
+
# when 'a', 'b', 'c' then foo
|
27
|
+
# # ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # accepted (but consider `case` as above)
|
31
|
+
# foo if a == b.lightweight || a == b.heavyweight
|
32
|
+
#
|
33
|
+
# @example AllowMethodComparison: true (default)
|
34
|
+
# # good
|
35
|
+
# foo if a == b.lightweight || a == b.heavyweight
|
36
|
+
#
|
37
|
+
# @example AllowMethodComparison: false
|
38
|
+
# # bad
|
39
|
+
# foo if a == b.lightweight || a == b.heavyweight
|
40
|
+
#
|
41
|
+
# # good
|
42
|
+
# foo if [b.lightweight, b.heavyweight].include?(a)
|
17
43
|
class MultipleComparison < Base
|
44
|
+
extend AutoCorrector
|
45
|
+
|
18
46
|
MSG = 'Avoid comparing a variable with multiple items ' \
|
19
47
|
'in a conditional, use `Array#include?` instead.'
|
20
48
|
|
49
|
+
def on_new_investigation
|
50
|
+
@compared_elements = []
|
51
|
+
@allowed_method_comparison = false
|
52
|
+
end
|
53
|
+
|
21
54
|
def on_or(node)
|
22
55
|
root_of_or_node = root_of_or_node(node)
|
23
56
|
|
24
57
|
return unless node == root_of_or_node
|
25
58
|
return unless nested_variable_comparison?(root_of_or_node)
|
59
|
+
return if @allowed_method_comparison
|
26
60
|
|
27
|
-
add_offense(node)
|
61
|
+
add_offense(node) do |corrector|
|
62
|
+
elements = @compared_elements.join(', ')
|
63
|
+
prefer_method = "[#{elements}].include?(#{variables_in_node(node).first})"
|
64
|
+
|
65
|
+
corrector.replace(node, prefer_method)
|
66
|
+
end
|
28
67
|
end
|
29
68
|
|
30
69
|
private
|
31
70
|
|
32
71
|
def_node_matcher :simple_double_comparison?, '(send $lvar :== $lvar)'
|
33
|
-
def_node_matcher :
|
34
|
-
|
35
|
-
|
72
|
+
def_node_matcher :simple_comparison_lhs?, <<~PATTERN
|
73
|
+
(send $lvar :== $_)
|
74
|
+
PATTERN
|
75
|
+
def_node_matcher :simple_comparison_rhs?, <<~PATTERN
|
76
|
+
(send $_ :== $lvar)
|
36
77
|
PATTERN
|
37
78
|
|
38
79
|
def nested_variable_comparison?(node)
|
@@ -55,9 +96,12 @@ module RuboCop
|
|
55
96
|
simple_double_comparison?(node) do |var1, var2|
|
56
97
|
return [variable_name(var1), variable_name(var2)]
|
57
98
|
end
|
58
|
-
|
99
|
+
if (var, obj = simple_comparison_lhs?(node)) || (obj, var = simple_comparison_rhs?(node))
|
100
|
+
@allowed_method_comparison = true if allow_method_comparison? && obj.send_type?
|
101
|
+
@compared_elements << obj.source
|
59
102
|
return [variable_name(var)]
|
60
103
|
end
|
104
|
+
|
61
105
|
[]
|
62
106
|
end
|
63
107
|
|
@@ -74,7 +118,7 @@ module RuboCop
|
|
74
118
|
end
|
75
119
|
|
76
120
|
def comparison?(node)
|
77
|
-
|
121
|
+
simple_comparison_lhs?(node) || simple_comparison_rhs?(node) || nested_comparison?(node)
|
78
122
|
end
|
79
123
|
|
80
124
|
def root_of_or_node(or_node)
|
@@ -86,6 +130,10 @@ module RuboCop
|
|
86
130
|
or_node
|
87
131
|
end
|
88
132
|
end
|
133
|
+
|
134
|
+
def allow_method_comparison?
|
135
|
+
cop_config.fetch('AllowMethodComparison', true)
|
136
|
+
end
|
89
137
|
end
|
90
138
|
end
|
91
139
|
end
|