rubocop 1.43.0 → 1.44.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 +50 -0
- data/lib/rubocop/config_loader.rb +12 -15
- 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/block_end_newline.rb +7 -1
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +0 -2
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
- 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 +11 -7
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
- data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
- data/lib/rubocop/cop/lint/useless_rescue.rb +15 -1
- 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_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- 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/hash_shorthand_syntax.rb +40 -18
- data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -0
- data/lib/rubocop/cop/registry.rb +12 -7
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +18 -10
- data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +2 -9
- 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/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 +11 -5
- 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/multiline_if_modifier.rb +0 -4
- data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
- data/lib/rubocop/cop/style/operator_method_call.rb +1 -1
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -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/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/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/rspec/expect_offense.rb +6 -4
- data/lib/rubocop/server/cache.rb +3 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +6 -3
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Enforces the use of `Comparable#clamp` instead of comparison by minimum and maximum.
|
7
|
+
#
|
8
|
+
# This cop supports autocorrection for `if/elsif/else` bad style only.
|
9
|
+
# Because `ArgumentError` occurs if the minimum and maximum of `clamp` arguments are reversed.
|
10
|
+
# When these are variables, it is not possible to determine which is the minimum and maximum:
|
11
|
+
#
|
12
|
+
# [source,ruby]
|
13
|
+
# ----
|
14
|
+
# [1, [2, 3].max].min # => 1
|
15
|
+
# 1.clamp(3, 1) # => min argument must be smaller than max argument (ArgumentError)
|
16
|
+
# ----
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# [[x, low].max, high].min
|
22
|
+
#
|
23
|
+
# # bad
|
24
|
+
# if x < low
|
25
|
+
# low
|
26
|
+
# elsif high < x
|
27
|
+
# high
|
28
|
+
# else
|
29
|
+
# x
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# x.clamp(low, high)
|
34
|
+
#
|
35
|
+
class ComparableClamp < Base
|
36
|
+
include Alignment
|
37
|
+
extend AutoCorrector
|
38
|
+
extend TargetRubyVersion
|
39
|
+
|
40
|
+
minimum_target_ruby_version 2.4
|
41
|
+
|
42
|
+
MSG = 'Use `%<prefer>s` instead of `if/elsif/else`.'
|
43
|
+
MSG_MIN_MAX = 'Use `Comparable#clamp` instead.'
|
44
|
+
RESTRICT_ON_SEND = %i[min max].freeze
|
45
|
+
|
46
|
+
# @!method if_elsif_else_condition?(node)
|
47
|
+
def_node_matcher :if_elsif_else_condition?, <<~PATTERN
|
48
|
+
{
|
49
|
+
(if (send _x :< _min) _min (if (send _max :< _x) _max _x))
|
50
|
+
(if (send _min :> _x) _min (if (send _max :< _x) _max _x))
|
51
|
+
(if (send _x :< _min) _min (if (send _x :> _max) _max _x))
|
52
|
+
(if (send _min :> _x) _min (if (send _x :> _max) _max _x))
|
53
|
+
(if (send _max :< _x) _max (if (send _x :< _min) _min _x))
|
54
|
+
(if (send _x :> _max) _max (if (send _x :< _min) _min _x))
|
55
|
+
(if (send _max :< _x) _max (if (send _min :> _x) _min _x))
|
56
|
+
(if (send _x :> _max) _max (if (send _min :> _x) _min _x))
|
57
|
+
}
|
58
|
+
PATTERN
|
59
|
+
|
60
|
+
# @!method array_min_max?(node)
|
61
|
+
def_node_matcher :array_min_max?, <<~PATTERN
|
62
|
+
{
|
63
|
+
(send
|
64
|
+
(array
|
65
|
+
(send (array _ _) :max) _) :min)
|
66
|
+
(send
|
67
|
+
(array
|
68
|
+
_ (send (array _ _) :max)) :min)
|
69
|
+
(send
|
70
|
+
(array
|
71
|
+
(send (array _ _) :min) _) :max)
|
72
|
+
(send
|
73
|
+
(array
|
74
|
+
_ (send (array _ _) :min)) :max)
|
75
|
+
}
|
76
|
+
PATTERN
|
77
|
+
|
78
|
+
def on_if(node)
|
79
|
+
return unless if_elsif_else_condition?(node)
|
80
|
+
|
81
|
+
if_body, elsif_body, else_body = *node.branches
|
82
|
+
|
83
|
+
else_body_source = else_body.source
|
84
|
+
|
85
|
+
if min_condition?(node.condition, else_body_source)
|
86
|
+
min = if_body.source
|
87
|
+
max = elsif_body.source
|
88
|
+
else
|
89
|
+
min = elsif_body.source
|
90
|
+
max = if_body.source
|
91
|
+
end
|
92
|
+
|
93
|
+
prefer = "#{else_body_source}.clamp(#{min}, #{max})"
|
94
|
+
|
95
|
+
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
96
|
+
autocorrect(corrector, node, prefer)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def on_send(node)
|
101
|
+
return unless array_min_max?(node)
|
102
|
+
|
103
|
+
add_offense(node, message: MSG_MIN_MAX)
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def autocorrect(corrector, node, prefer)
|
109
|
+
if node.elsif?
|
110
|
+
corrector.insert_before(node, "else\n")
|
111
|
+
corrector.replace(node, "#{indentation(node)}#{prefer}")
|
112
|
+
else
|
113
|
+
corrector.replace(node, prefer)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def min_condition?(if_condition, else_body)
|
118
|
+
lhs, op, rhs = *if_condition
|
119
|
+
|
120
|
+
(lhs.source == else_body && op == :<) || (rhs.source == else_body && op == :>)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -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
|
@@ -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,7 +96,8 @@ 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)
|
@@ -216,6 +215,13 @@ module RuboCop
|
|
216
215
|
|
217
216
|
parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
|
218
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
|
219
225
|
end
|
220
226
|
# rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
|
221
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
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
@@ -47,7 +47,7 @@ module RuboCop
|
|
47
47
|
|
48
48
|
def anonymous_forwarding?(argument)
|
49
49
|
return true if argument.forwarded_args_type? || argument.forwarded_restarg_type?
|
50
|
-
return true if argument.children.first&.forwarded_kwrestarg_type?
|
50
|
+
return true if argument.hash_type? && argument.children.first&.forwarded_kwrestarg_type?
|
51
51
|
|
52
52
|
argument.block_pass_type? && argument.source == '&'
|
53
53
|
end
|
@@ -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
|
@@ -18,21 +18,27 @@ module RuboCop
|
|
18
18
|
|
19
19
|
MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.'
|
20
20
|
|
21
|
-
# @!method double_splat_hash_braces?(node)
|
22
|
-
def_node_matcher :double_splat_hash_braces?, <<~PATTERN
|
23
|
-
(hash (kwsplat (hash ...)))
|
24
|
-
PATTERN
|
25
|
-
|
26
21
|
def on_hash(node)
|
27
22
|
return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?)
|
23
|
+
return unless (parent = node.parent)
|
24
|
+
return unless parent.kwsplat_type?
|
28
25
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
corrector.replace(grandparent, node.children.map(&:source).join(', '))
|
26
|
+
add_offense(parent) do |corrector|
|
27
|
+
corrector.remove(parent.loc.operator)
|
28
|
+
corrector.remove(opening_brace(node))
|
29
|
+
corrector.remove(closing_brace(node))
|
34
30
|
end
|
35
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def opening_brace(node)
|
36
|
+
node.loc.begin.join(node.children.first.loc.expression.begin)
|
37
|
+
end
|
38
|
+
|
39
|
+
def closing_brace(node)
|
40
|
+
node.children.last.loc.expression.end.join(node.loc.end)
|
41
|
+
end
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
@@ -88,10 +88,9 @@ module RuboCop
|
|
88
88
|
return unless previous_older_sibling
|
89
89
|
|
90
90
|
add_offense(node, message: format(MSG, name: node.method_name)) do |corrector|
|
91
|
-
swap(
|
91
|
+
corrector.swap(
|
92
92
|
range_with_comments_and_lines(previous_older_sibling),
|
93
|
-
range_with_comments_and_lines(node.parent.if_type? ? node.parent : node)
|
94
|
-
corrector: corrector
|
93
|
+
range_with_comments_and_lines(node.parent.if_type? ? node.parent : node)
|
95
94
|
)
|
96
95
|
end
|
97
96
|
end
|
@@ -130,12 +129,6 @@ module RuboCop
|
|
130
129
|
end_pos: node2.location.expression.end_pos
|
131
130
|
).source.include?("\n\n")
|
132
131
|
end
|
133
|
-
|
134
|
-
def swap(range1, range2, corrector:)
|
135
|
-
inserted = range2.source
|
136
|
-
corrector.insert_before(range1, inserted)
|
137
|
-
corrector.remove(range2)
|
138
|
-
end
|
139
132
|
end
|
140
133
|
end
|
141
134
|
end
|
@@ -42,7 +42,7 @@ module RuboCop
|
|
42
42
|
|
43
43
|
if rhs.send_type?
|
44
44
|
check_send_node(node, rhs, var_name, var_type)
|
45
|
-
elsif
|
45
|
+
elsif rhs.operator_keyword?
|
46
46
|
check_boolean_node(node, rhs, var_name, var_type)
|
47
47
|
end
|
48
48
|
end
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
|
77
77
|
if rhs.send_type?
|
78
78
|
autocorrect_send_node(corrector, node, rhs)
|
79
|
-
elsif
|
79
|
+
elsif rhs.operator_keyword?
|
80
80
|
autocorrect_boolean_node(corrector, node, rhs)
|
81
81
|
end
|
82
82
|
end
|
@@ -72,8 +72,10 @@ module RuboCop
|
|
72
72
|
|
73
73
|
def each_semicolon
|
74
74
|
tokens_for_lines.each do |line, tokens|
|
75
|
-
|
76
|
-
|
75
|
+
semicolon_pos = semicolon_position(tokens)
|
76
|
+
after_expr_pos = semicolon_pos == -1 ? -2 : semicolon_pos
|
77
|
+
|
78
|
+
yield line, tokens[semicolon_pos].column, tokens[after_expr_pos] if semicolon_pos
|
77
79
|
end
|
78
80
|
end
|
79
81
|
|
@@ -81,6 +83,26 @@ module RuboCop
|
|
81
83
|
processed_source.tokens.group_by(&:line)
|
82
84
|
end
|
83
85
|
|
86
|
+
def semicolon_position(tokens)
|
87
|
+
if tokens.last.semicolon?
|
88
|
+
-1
|
89
|
+
elsif tokens.first.semicolon?
|
90
|
+
0
|
91
|
+
elsif exist_semicolon_before_right_curly_brace?(tokens)
|
92
|
+
-3
|
93
|
+
elsif exist_semicolon_after_left_curly_brace?(tokens)
|
94
|
+
2
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def exist_semicolon_before_right_curly_brace?(tokens)
|
99
|
+
tokens[-2]&.right_curly_brace? && tokens[-3]&.semicolon?
|
100
|
+
end
|
101
|
+
|
102
|
+
def exist_semicolon_after_left_curly_brace?(tokens)
|
103
|
+
tokens[1]&.left_curly_brace? && tokens[2]&.semicolon?
|
104
|
+
end
|
105
|
+
|
84
106
|
def register_semicolon(line, column, after_expression, token_before_semicolon = nil)
|
85
107
|
range = source_range(processed_source.buffer, line, column)
|
86
108
|
|
@@ -97,8 +97,10 @@ module RuboCop
|
|
97
97
|
scope_stack.reverse_each do |scope|
|
98
98
|
variable = scope.variables[name]
|
99
99
|
return variable if variable
|
100
|
+
|
100
101
|
# Only block scope allows referencing outer scope variables.
|
101
|
-
|
102
|
+
node = scope.node
|
103
|
+
return nil unless node.block_type? || node.numblock_type?
|
102
104
|
end
|
103
105
|
|
104
106
|
nil
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
|
51
51
|
ZERO_ARITY_SUPER_TYPE = :zsuper
|
52
52
|
|
53
|
-
TWISTED_SCOPE_TYPES = %i[block class sclass defs module].freeze
|
53
|
+
TWISTED_SCOPE_TYPES = %i[block numblock class sclass defs module].freeze
|
54
54
|
SCOPE_TYPES = (TWISTED_SCOPE_TYPES + [:def]).freeze
|
55
55
|
|
56
56
|
SEND_TYPE = :send
|