rubocop 1.42.0 → 1.45.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/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(')')
|