rubocop 1.42.0 → 1.45.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +73 -31
- data/lib/rubocop/cli.rb +54 -8
- data/lib/rubocop/config_loader.rb +12 -15
- data/lib/rubocop/config_loader_resolver.rb +3 -4
- data/lib/rubocop/cop/base.rb +27 -9
- data/lib/rubocop/cop/commissioner.rb +8 -2
- data/lib/rubocop/cop/cop.rb +23 -3
- data/lib/rubocop/cop/corrector.rb +10 -2
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -16
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +11 -13
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +4 -4
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +5 -4
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
- data/lib/rubocop/cop/lint/debugger.rb +8 -27
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
- data/lib/rubocop/cop/lint/else_layout.rb +2 -6
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +14 -7
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -5
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +7 -4
- data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
- data/lib/rubocop/cop/lint/useless_rescue.rb +85 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +9 -1
- data/lib/rubocop/cop/lint/void.rb +19 -10
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +2 -5
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +5 -3
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +57 -23
- data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -0
- data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -3
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -0
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
- data/lib/rubocop/cop/registry.rb +12 -7
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -11
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +3 -10
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/documentation_method.rb +6 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -0
- data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -14
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/min_max_comparison.rb +11 -1
- data/lib/rubocop/cop/style/missing_else.rb +13 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
- data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +18 -3
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
- data/lib/rubocop/cop/style/numbered_parameters_limit.rb +11 -3
- data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
- data/lib/rubocop/cop/style/operator_method_call.rb +16 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +16 -1
- data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -10
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +58 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/require_order.rb +2 -9
- data/lib/rubocop/cop/style/self_assignment.rb +2 -2
- data/lib/rubocop/cop/style/semicolon.rb +24 -2
- data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +12 -5
- data/lib/rubocop/cop/style/yoda_expression.rb +18 -2
- data/lib/rubocop/cop/team.rb +19 -14
- data/lib/rubocop/cop/variable_force/scope.rb +3 -3
- data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
- data/lib/rubocop/cop/variable_force.rb +1 -1
- data/lib/rubocop/formatter.rb +0 -1
- data/lib/rubocop/options.rb +22 -1
- data/lib/rubocop/path_util.rb +11 -6
- data/lib/rubocop/rspec/expect_offense.rb +6 -4
- data/lib/rubocop/runner.rb +40 -4
- data/lib/rubocop/server/cache.rb +10 -3
- data/lib/rubocop/server/cli.rb +37 -18
- data/lib/rubocop/server/client_command/exec.rb +1 -1
- data/lib/rubocop/server/client_command/start.rb +6 -1
- data/lib/rubocop/server/core.rb +23 -8
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +12 -27
@@ -218,11 +218,9 @@ module RuboCop
|
|
218
218
|
VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
|
219
219
|
ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
|
220
220
|
LINE_LENGTH = 'Layout/LineLength'
|
221
|
-
INDENTATION_WIDTH = 'Layout/IndentationWidth'
|
222
221
|
ENABLED = 'Enabled'
|
223
222
|
MAX = 'Max'
|
224
223
|
SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'
|
225
|
-
WIDTH = 'Width'
|
226
224
|
|
227
225
|
# The shovel operator `<<` does not have its own type. It is a `send`
|
228
226
|
# type.
|
@@ -428,10 +426,6 @@ module RuboCop
|
|
428
426
|
config.for_cop(LINE_LENGTH)[MAX]
|
429
427
|
end
|
430
428
|
|
431
|
-
def indentation_width
|
432
|
-
config.for_cop(INDENTATION_WIDTH)[WIDTH] || 2
|
433
|
-
end
|
434
|
-
|
435
429
|
def single_line_conditions_only?
|
436
430
|
cop_config[SINGLE_LINE_CONDITIONS_ONLY]
|
437
431
|
end
|
@@ -7,6 +7,10 @@ module RuboCop
|
|
7
7
|
# It can optionally be configured to also require documentation for
|
8
8
|
# non-public methods.
|
9
9
|
#
|
10
|
+
# NOTE: This cop allows `initialize` method because `initialize` is
|
11
|
+
# a special method called from `new`. In some programming languages
|
12
|
+
# they are called constructor to distinguish it from method.
|
13
|
+
#
|
10
14
|
# @example
|
11
15
|
#
|
12
16
|
# # bad
|
@@ -103,6 +107,8 @@ module RuboCop
|
|
103
107
|
PATTERN
|
104
108
|
|
105
109
|
def on_def(node)
|
110
|
+
return if node.method?(:initialize)
|
111
|
+
|
106
112
|
parent = node.parent
|
107
113
|
module_function_node?(parent) ? check(parent) : check(node)
|
108
114
|
end
|
@@ -118,11 +118,23 @@ module RuboCop
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def allowed_receiver?(receiver)
|
121
|
-
receiver_name = receiver
|
121
|
+
receiver_name = receiver_name(receiver)
|
122
122
|
|
123
123
|
allowed_receivers.include?(receiver_name)
|
124
124
|
end
|
125
125
|
|
126
|
+
def receiver_name(receiver)
|
127
|
+
if receiver.send_type?
|
128
|
+
if receiver.receiver
|
129
|
+
"#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
|
130
|
+
else
|
131
|
+
receiver.method_name.to_s
|
132
|
+
end
|
133
|
+
else
|
134
|
+
receiver.source
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
126
138
|
def allowed_receivers
|
127
139
|
cop_config.fetch('AllowedReceivers', [])
|
128
140
|
end
|
@@ -254,6 +254,7 @@ module RuboCop
|
|
254
254
|
op = pair_node.loc.operator
|
255
255
|
|
256
256
|
key_with_hash_rocket = ":#{pair_node.key.source}#{pair_node.inverse_delimiter(true)}"
|
257
|
+
key_with_hash_rocket += pair_node.key.source if pair_node.value_omission?
|
257
258
|
corrector.replace(pair_node.key, key_with_hash_rocket)
|
258
259
|
corrector.remove(range_with_surrounding_space(op))
|
259
260
|
end
|
@@ -21,6 +21,7 @@ module RuboCop
|
|
21
21
|
# work
|
22
22
|
# end
|
23
23
|
class InfiniteLoop < Base
|
24
|
+
include Alignment
|
24
25
|
extend AutoCorrector
|
25
26
|
|
26
27
|
LEADING_SPACE = /\A(\s*)/.freeze
|
@@ -106,7 +107,7 @@ module RuboCop
|
|
106
107
|
else
|
107
108
|
indentation = body.source_range.source_line[LEADING_SPACE]
|
108
109
|
|
109
|
-
['loop do', body.source.gsub(/^/,
|
110
|
+
['loop do', body.source.gsub(/^/, indentation(node)), 'end'].join("\n#{indentation}")
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
@@ -120,10 +121,6 @@ module RuboCop
|
|
120
121
|
|
121
122
|
start_range.join(end_range)
|
122
123
|
end
|
123
|
-
|
124
|
-
def configured_indent
|
125
|
-
' ' * config.for_cop('Layout/IndentationWidth')['Width']
|
126
|
-
end
|
127
124
|
end
|
128
125
|
end
|
129
126
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for usages of `unless` which can be replaced by `if` with inverted condition.
|
7
|
+
# Code without `unless` is easier to read, but that is subjective, so this cop
|
8
|
+
# is disabled by default.
|
9
|
+
#
|
10
|
+
# Methods that can be inverted should be defined in `InverseMethods`. Note that
|
11
|
+
# the relationship of inverse methods needs to be defined in both directions.
|
12
|
+
# For example,
|
13
|
+
# InverseMethods:
|
14
|
+
# :!=: :==
|
15
|
+
# :even?: :odd?
|
16
|
+
# :odd?: :even?
|
17
|
+
#
|
18
|
+
# will suggest both `even?` and `odd?` to be inverted, but only `!=` (and not `==`).
|
19
|
+
#
|
20
|
+
# @safety
|
21
|
+
# This cop is unsafe because it cannot be guaranteed that the method
|
22
|
+
# and its inverse method are both defined on receiver, and also are
|
23
|
+
# actually inverse of each other.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# # bad (simple condition)
|
27
|
+
# foo unless !bar
|
28
|
+
# foo unless x != y
|
29
|
+
# foo unless x >= 10
|
30
|
+
# foo unless x.even?
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# foo if bar
|
34
|
+
# foo if x == y
|
35
|
+
# foo if x < 10
|
36
|
+
# foo if x.odd?
|
37
|
+
#
|
38
|
+
# # bad (complex condition)
|
39
|
+
# foo unless x != y || x.even?
|
40
|
+
#
|
41
|
+
# # good
|
42
|
+
# foo if x == y && x.odd?
|
43
|
+
#
|
44
|
+
# # good (if)
|
45
|
+
# foo if !condition
|
46
|
+
#
|
47
|
+
class InvertibleUnlessCondition < Base
|
48
|
+
extend AutoCorrector
|
49
|
+
|
50
|
+
MSG = 'Favor `if` with inverted condition over `unless`.'
|
51
|
+
|
52
|
+
def on_if(node)
|
53
|
+
return unless node.unless?
|
54
|
+
|
55
|
+
condition = node.condition
|
56
|
+
return unless invertible?(condition)
|
57
|
+
|
58
|
+
add_offense(node) do |corrector|
|
59
|
+
corrector.replace(node.loc.keyword, node.inverse_keyword)
|
60
|
+
autocorrect(corrector, condition)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def invertible?(node)
|
67
|
+
case node.type
|
68
|
+
when :begin
|
69
|
+
invertible?(node.children.first)
|
70
|
+
when :send
|
71
|
+
return if inheritance_check?(node)
|
72
|
+
|
73
|
+
node.method?(:!) || inverse_methods.key?(node.method_name)
|
74
|
+
when :or, :and
|
75
|
+
invertible?(node.lhs) && invertible?(node.rhs)
|
76
|
+
else
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def inheritance_check?(node)
|
82
|
+
argument = node.first_argument
|
83
|
+
node.method?(:<) &&
|
84
|
+
(argument.const_type? && argument.short_name.to_s.upcase != argument.short_name.to_s)
|
85
|
+
end
|
86
|
+
|
87
|
+
def autocorrect(corrector, node)
|
88
|
+
case node.type
|
89
|
+
when :begin
|
90
|
+
autocorrect(corrector, node.children.first)
|
91
|
+
when :send
|
92
|
+
autocorrect_send_node(corrector, node)
|
93
|
+
when :or, :and
|
94
|
+
corrector.replace(node.loc.operator, node.inverse_operator)
|
95
|
+
autocorrect(corrector, node.lhs)
|
96
|
+
autocorrect(corrector, node.rhs)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def autocorrect_send_node(corrector, node)
|
101
|
+
if node.method?(:!)
|
102
|
+
corrector.remove(node.loc.selector)
|
103
|
+
else
|
104
|
+
corrector.replace(node.loc.selector, inverse_methods[node.method_name])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def inverse_methods
|
109
|
+
@inverse_methods ||= cop_config['InverseMethods']
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -13,8 +13,7 @@ module RuboCop
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
17
|
-
def omit_parentheses(node)
|
16
|
+
def omit_parentheses(node) # rubocop:disable Metrics/PerceivedComplexity
|
18
17
|
return unless node.parenthesized?
|
19
18
|
return if inside_endless_method_def?(node)
|
20
19
|
return if require_parentheses_for_hash_value_omission?(node)
|
@@ -28,7 +27,6 @@ module RuboCop
|
|
28
27
|
autocorrect(corrector, node)
|
29
28
|
end
|
30
29
|
end
|
31
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
32
30
|
|
33
31
|
def autocorrect(corrector, node)
|
34
32
|
if parentheses_at_the_end_of_multiline_call?(node)
|
@@ -90,7 +88,7 @@ module RuboCop
|
|
90
88
|
.end_with?('(')
|
91
89
|
end
|
92
90
|
|
93
|
-
def legitimate_call_with_parentheses?(node)
|
91
|
+
def legitimate_call_with_parentheses?(node) # rubocop:disable Metrics/PerceivedComplexity
|
94
92
|
call_in_literals?(node) ||
|
95
93
|
call_with_ambiguous_arguments?(node) ||
|
96
94
|
call_in_logical_operators?(node) ||
|
@@ -98,24 +96,28 @@ module RuboCop
|
|
98
96
|
call_in_single_line_inheritance?(node) ||
|
99
97
|
allowed_multiline_call_with_parentheses?(node) ||
|
100
98
|
allowed_chained_call_with_parentheses?(node) ||
|
101
|
-
assignment_in_condition?(node)
|
99
|
+
assignment_in_condition?(node) ||
|
100
|
+
forwards_anonymous_rest_arguments?(node)
|
102
101
|
end
|
103
102
|
|
104
103
|
def call_in_literals?(node)
|
105
|
-
node.parent
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
parent = node.parent&.block_type? ? node.parent.parent : node.parent
|
105
|
+
return unless parent
|
106
|
+
|
107
|
+
parent.pair_type? ||
|
108
|
+
parent.array_type? ||
|
109
|
+
parent.range_type? ||
|
110
|
+
splat?(parent) ||
|
111
|
+
ternary_if?(parent)
|
111
112
|
end
|
112
113
|
|
113
114
|
def call_in_logical_operators?(node)
|
114
115
|
parent = node.parent&.block_type? ? node.parent.parent : node.parent
|
115
|
-
parent
|
116
|
-
|
116
|
+
return unless parent
|
117
|
+
|
118
|
+
logical_operator?(parent) ||
|
117
119
|
(parent.send_type? &&
|
118
|
-
parent.arguments.any? { |argument| logical_operator?(argument) })
|
120
|
+
parent.arguments.any? { |argument| logical_operator?(argument) })
|
119
121
|
end
|
120
122
|
|
121
123
|
def call_in_optional_arguments?(node)
|
@@ -213,6 +215,13 @@ module RuboCop
|
|
213
215
|
|
214
216
|
parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
|
215
217
|
end
|
218
|
+
|
219
|
+
def forwards_anonymous_rest_arguments?(node)
|
220
|
+
return false unless (last_argument = node.last_argument)
|
221
|
+
return true if last_argument.forwarded_restarg_type?
|
222
|
+
|
223
|
+
last_argument.hash_type? && last_argument.children.first&.forwarded_kwrestarg_type?
|
224
|
+
end
|
216
225
|
end
|
217
226
|
# rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
|
218
227
|
end
|
@@ -36,6 +36,7 @@ module RuboCop
|
|
36
36
|
#
|
37
37
|
class MinMaxComparison < Base
|
38
38
|
extend AutoCorrector
|
39
|
+
include RangeHelp
|
39
40
|
|
40
41
|
MSG = 'Use `%<prefer>s` instead.'
|
41
42
|
GRATER_OPERATORS = %i[> >=].freeze
|
@@ -54,7 +55,7 @@ module RuboCop
|
|
54
55
|
replacement = "[#{lhs.source}, #{rhs.source}].#{preferred_method}"
|
55
56
|
|
56
57
|
add_offense(node, message: format(MSG, prefer: replacement)) do |corrector|
|
57
|
-
corrector
|
58
|
+
autocorrect(corrector, node, replacement)
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
@@ -67,6 +68,15 @@ module RuboCop
|
|
67
68
|
LESS_OPERATORS.include?(operator) ? 'max' : 'min'
|
68
69
|
end
|
69
70
|
end
|
71
|
+
|
72
|
+
def autocorrect(corrector, node, replacement)
|
73
|
+
if node.elsif?
|
74
|
+
corrector.remove(range_between(node.parent.loc.else.begin_pos, node.loc.else.begin_pos))
|
75
|
+
corrector.replace(node.else_branch, replacement)
|
76
|
+
else
|
77
|
+
corrector.replace(node, replacement)
|
78
|
+
end
|
79
|
+
end
|
70
80
|
end
|
71
81
|
end
|
72
82
|
end
|
@@ -99,6 +99,7 @@ module RuboCop
|
|
99
99
|
class MissingElse < Base
|
100
100
|
include OnNormalIfUnless
|
101
101
|
include ConfigurableEnforcedStyle
|
102
|
+
extend AutoCorrector
|
102
103
|
|
103
104
|
MSG = '`%<type>s` condition requires an `else`-clause.'
|
104
105
|
MSG_NIL = '`%<type>s` condition requires an `else`-clause with `nil` in it.'
|
@@ -126,7 +127,9 @@ module RuboCop
|
|
126
127
|
def check(node)
|
127
128
|
return if node.else?
|
128
129
|
|
129
|
-
add_offense(node, message: format(message_template, type: node.type))
|
130
|
+
add_offense(node, message: format(message_template, type: node.type)) do |corrector|
|
131
|
+
autocorrect(corrector, node)
|
132
|
+
end
|
130
133
|
end
|
131
134
|
|
132
135
|
def message_template
|
@@ -140,6 +143,15 @@ module RuboCop
|
|
140
143
|
end
|
141
144
|
end
|
142
145
|
|
146
|
+
def autocorrect(corrector, node)
|
147
|
+
case empty_else_style
|
148
|
+
when :empty
|
149
|
+
corrector.insert_before(node.loc.end, 'else; nil; ')
|
150
|
+
when :nil
|
151
|
+
corrector.insert_before(node.loc.end, 'else; ')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
143
155
|
def if_style?
|
144
156
|
style == :if
|
145
157
|
end
|
@@ -40,10 +40,6 @@ module RuboCop
|
|
40
40
|
[condition, indented_body, indented_end].join("\n")
|
41
41
|
end
|
42
42
|
|
43
|
-
def configured_indentation_width
|
44
|
-
super || 2
|
45
|
-
end
|
46
|
-
|
47
43
|
def indented_body(body, node)
|
48
44
|
body_source = "#{offset(node)}#{body.source}"
|
49
45
|
body_source.each_line.map do |line|
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
31
31
|
# baz
|
32
32
|
# )
|
33
33
|
class MultilineMemoization < Base
|
34
|
+
include Alignment
|
34
35
|
include ConfigurableEnforcedStyle
|
35
36
|
extend AutoCorrector
|
36
37
|
|
@@ -75,11 +76,10 @@ module RuboCop
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def keyword_begin_str(node, node_buf)
|
78
|
-
indent = config.for_cop('Layout/IndentationWidth')['Width'] || 2
|
79
79
|
if node_buf.source[node.loc.begin.end_pos] == "\n"
|
80
80
|
'begin'
|
81
81
|
else
|
82
|
-
"begin\n#{' ' * (node.loc.column +
|
82
|
+
"begin\n#{' ' * (node.loc.column + configured_indentation_width)}"
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
@@ -34,6 +34,7 @@ module RuboCop
|
|
34
34
|
# return cond ? b : c
|
35
35
|
#
|
36
36
|
class MultilineTernaryOperator < Base
|
37
|
+
include CommentsHelp
|
37
38
|
extend AutoCorrector
|
38
39
|
|
39
40
|
MSG_IF = 'Avoid multi-line ternary operators, use `if` or `unless` instead.'
|
@@ -46,9 +47,7 @@ module RuboCop
|
|
46
47
|
message = enforce_single_line_ternary_operator?(node) ? MSG_SINGLE_LINE : MSG_IF
|
47
48
|
|
48
49
|
add_offense(node, message: message) do |corrector|
|
49
|
-
|
50
|
-
|
51
|
-
corrector.replace(node, replacement(node))
|
50
|
+
autocorrect(corrector, node)
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
@@ -58,6 +57,16 @@ module RuboCop
|
|
58
57
|
node.ternary? && node.multiline?
|
59
58
|
end
|
60
59
|
|
60
|
+
def autocorrect(corrector, node)
|
61
|
+
return unless offense?(node)
|
62
|
+
|
63
|
+
corrector.replace(node, replacement(node))
|
64
|
+
return unless (parent = node.parent)
|
65
|
+
return unless (comments_in_condition = comments_in_condition(node))
|
66
|
+
|
67
|
+
corrector.insert_before(parent, comments_in_condition)
|
68
|
+
end
|
69
|
+
|
61
70
|
def replacement(node)
|
62
71
|
if enforce_single_line_ternary_operator?(node)
|
63
72
|
"#{node.condition.source} ? #{node.if_branch.source} : #{node.else_branch.source}"
|
@@ -72,6 +81,12 @@ module RuboCop
|
|
72
81
|
end
|
73
82
|
end
|
74
83
|
|
84
|
+
def comments_in_condition(node)
|
85
|
+
comments_in_range(node).map do |comment|
|
86
|
+
"#{comment.loc.expression.source}\n"
|
87
|
+
end.join
|
88
|
+
end
|
89
|
+
|
75
90
|
def enforce_single_line_ternary_operator?(node)
|
76
91
|
SINGLE_LINE_TYPES.include?(node.parent&.type) && !use_assignment_method?(node.parent)
|
77
92
|
end
|
@@ -103,11 +103,7 @@ module RuboCop
|
|
103
103
|
if node.if_branch.nil?
|
104
104
|
corrector.remove(range_by_whole_lines(node.loc.else, include_final_newline: true))
|
105
105
|
else
|
106
|
-
if_range
|
107
|
-
else_range = else_range(node)
|
108
|
-
|
109
|
-
corrector.replace(if_range, else_range.source)
|
110
|
-
corrector.replace(else_range, if_range.source)
|
106
|
+
corrector.swap(if_range(node), else_range(node))
|
111
107
|
end
|
112
108
|
end
|
113
109
|
|
@@ -12,10 +12,11 @@ module RuboCop
|
|
12
12
|
#
|
13
13
|
# @example Max: 1 (default)
|
14
14
|
# # bad
|
15
|
-
#
|
15
|
+
# use_multiple_numbered_parameters { _1.call(_2, _3, _4) }
|
16
16
|
#
|
17
17
|
# # good
|
18
|
-
#
|
18
|
+
# array.each { use_array_element_as_numbered_parameter(_1) }
|
19
|
+
# hash.each { use_only_hash_value_as_numbered_parameter(_2) }
|
19
20
|
class NumberedParametersLimit < Base
|
20
21
|
extend TargetRubyVersion
|
21
22
|
extend ExcludeLimit
|
@@ -26,9 +27,10 @@ module RuboCop
|
|
26
27
|
exclude_limit 'Max'
|
27
28
|
|
28
29
|
MSG = 'Avoid using more than %<max>i numbered %<parameter>s; %<count>i detected.'
|
30
|
+
NUMBERED_PARAMETER_PATTERN = /\A_[1-9]\z/.freeze
|
29
31
|
|
30
32
|
def on_numblock(node)
|
31
|
-
|
33
|
+
param_count = numbered_parameter_nodes(node).uniq.count
|
32
34
|
return if param_count <= max_count
|
33
35
|
|
34
36
|
parameter = max_count > 1 ? 'parameters' : 'parameter'
|
@@ -38,6 +40,12 @@ module RuboCop
|
|
38
40
|
|
39
41
|
private
|
40
42
|
|
43
|
+
def numbered_parameter_nodes(node)
|
44
|
+
node.each_descendant(:lvar).select do |lvar_node|
|
45
|
+
lvar_node.source.match?(NUMBERED_PARAMETER_PATTERN)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
41
49
|
def max_count
|
42
50
|
max = cop_config.fetch('Max', DEFAULT_MAX_VALUE)
|
43
51
|
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
31
31
|
# baz
|
32
32
|
# end
|
33
33
|
class OneLineConditional < Base
|
34
|
+
include Alignment
|
34
35
|
include ConfigurableEnforcedStyle
|
35
36
|
include OnNormalIfUnless
|
36
37
|
extend AutoCorrector
|
@@ -57,7 +58,7 @@ module RuboCop
|
|
57
58
|
|
58
59
|
def autocorrect(corrector, node)
|
59
60
|
if always_multiline? || cannot_replace_to_ternary?(node)
|
60
|
-
IfThenCorrector.new(node, indentation:
|
61
|
+
IfThenCorrector.new(node, indentation: configured_indentation_width).call(corrector)
|
61
62
|
else
|
62
63
|
corrector.replace(node, ternary_correction(node))
|
63
64
|
end
|
@@ -67,7 +68,7 @@ module RuboCop
|
|
67
68
|
replaced_node = ternary_replacement(node)
|
68
69
|
|
69
70
|
return replaced_node unless node.parent
|
70
|
-
return "(#{replaced_node})" if
|
71
|
+
return "(#{replaced_node})" if node.parent.operator_keyword?
|
71
72
|
return "(#{replaced_node})" if node.parent.send_type? && node.parent.operator_method?
|
72
73
|
|
73
74
|
replaced_node
|
@@ -116,10 +117,6 @@ module RuboCop
|
|
116
117
|
|
117
118
|
node.respond_to?(:arguments?) && node.arguments? && !node.parenthesized_call?
|
118
119
|
end
|
119
|
-
|
120
|
-
def indentation_width
|
121
|
-
@config.for_cop('Layout/IndentationWidth')['Width']
|
122
|
-
end
|
123
120
|
end
|
124
121
|
end
|
125
122
|
end
|
@@ -25,10 +25,10 @@ module RuboCop
|
|
25
25
|
|
26
26
|
def on_send(node)
|
27
27
|
return unless (dot = node.loc.dot)
|
28
|
-
return if node.receiver.const_type?
|
28
|
+
return if node.receiver.const_type? || !node.arguments.one?
|
29
29
|
|
30
30
|
_lhs, _op, rhs = *node
|
31
|
-
return if rhs
|
31
|
+
return if !rhs || method_call_with_parenthesized_arg?(rhs) || anonymous_forwarding?(rhs)
|
32
32
|
|
33
33
|
add_offense(dot) do |corrector|
|
34
34
|
wrap_in_parentheses_if_chained(corrector, node)
|
@@ -38,6 +38,20 @@ module RuboCop
|
|
38
38
|
|
39
39
|
private
|
40
40
|
|
41
|
+
# Checks for an acceptable case of `foo.+(bar).baz`.
|
42
|
+
def method_call_with_parenthesized_arg?(argument)
|
43
|
+
return false unless argument.parent.parent&.send_type?
|
44
|
+
|
45
|
+
argument.children.first && argument.parent.parenthesized?
|
46
|
+
end
|
47
|
+
|
48
|
+
def anonymous_forwarding?(argument)
|
49
|
+
return true if argument.forwarded_args_type? || argument.forwarded_restarg_type?
|
50
|
+
return true if argument.hash_type? && argument.children.first&.forwarded_kwrestarg_type?
|
51
|
+
|
52
|
+
argument.block_pass_type? && argument.source == '&'
|
53
|
+
end
|
54
|
+
|
41
55
|
def wrap_in_parentheses_if_chained(corrector, node)
|
42
56
|
return unless node.parent&.call_type?
|
43
57
|
|
@@ -172,7 +172,9 @@ module RuboCop
|
|
172
172
|
end
|
173
173
|
|
174
174
|
def modifier_statement?(node)
|
175
|
-
|
175
|
+
return false unless node
|
176
|
+
|
177
|
+
node.basic_conditional? && node.modifier_form?
|
176
178
|
end
|
177
179
|
|
178
180
|
# An internal class for correcting parallel assignment
|
@@ -36,6 +36,9 @@ module RuboCop
|
|
36
36
|
|
37
37
|
MSG = 'Use double pipes `||` instead.'
|
38
38
|
REDUNDANT_CONDITION = 'This condition is not needed.'
|
39
|
+
ARGUMENT_WITH_OPERATOR_TYPES = %i[
|
40
|
+
splat block_pass forwarded_restarg forwarded_kwrestarg forwarded_args
|
41
|
+
].freeze
|
39
42
|
|
40
43
|
def on_if(node)
|
41
44
|
return if node.elsif_conditional?
|
@@ -150,13 +153,25 @@ module RuboCop
|
|
150
153
|
end
|
151
154
|
|
152
155
|
def single_argument_method?(node)
|
153
|
-
node.send_type?
|
156
|
+
return false if !node.send_type? || node.method?(:[]) || !node.arguments.one?
|
157
|
+
|
158
|
+
!argument_with_operator?(node.first_argument)
|
154
159
|
end
|
155
160
|
|
156
161
|
def same_method?(if_branch, else_branch)
|
157
162
|
if_branch.method?(else_branch.method_name) && if_branch.receiver == else_branch.receiver
|
158
163
|
end
|
159
164
|
|
165
|
+
# If the argument is using an operator, it is an invalid syntax.
|
166
|
+
# e.g. `foo || *bar`, `foo || **bar`, and `foo || &bar`.
|
167
|
+
def argument_with_operator?(argument)
|
168
|
+
return true if ARGUMENT_WITH_OPERATOR_TYPES.include?(argument.type)
|
169
|
+
return false unless argument.hash_type?
|
170
|
+
return false unless (node = argument.children.first)
|
171
|
+
|
172
|
+
node.kwsplat_type? || node.forwarded_kwrestarg_type?
|
173
|
+
end
|
174
|
+
|
160
175
|
def if_source(if_branch, arithmetic_operation)
|
161
176
|
if branches_have_method?(if_branch.parent) && if_branch.parenthesized?
|
162
177
|
if_branch.source.delete_suffix(')')
|