rubocop-vibe 0.2.0 → 0.4.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/config/default.yml +51 -4
- data/lib/rubocop/cop/vibe/blank_line_after_assignment.rb +217 -0
- data/lib/rubocop/cop/vibe/blank_line_before_expectation.rb +6 -1
- data/lib/rubocop/cop/vibe/class_organization.rb +20 -1
- data/lib/rubocop/cop/vibe/consecutive_assignment_alignment.rb +5 -102
- data/lib/rubocop/cop/vibe/consecutive_constant_alignment.rb +5 -113
- data/lib/rubocop/cop/vibe/consecutive_indexed_assignment_alignment.rb +145 -0
- data/lib/rubocop/cop/vibe/consecutive_instance_variable_assignment_alignment.rb +123 -0
- data/lib/rubocop/cop/vibe/consecutive_let_alignment.rb +5 -94
- data/lib/rubocop/cop/vibe/describe_block_order.rb +6 -2
- data/lib/rubocop/cop/vibe/explicit_return_conditional.rb +192 -0
- data/lib/rubocop/cop/vibe/is_expected_one_liner.rb +3 -0
- data/lib/rubocop/cop/vibe/let_order.rb +147 -0
- data/lib/rubocop/cop/vibe/mixin/alignment_helpers.rb +92 -0
- data/lib/rubocop/cop/vibe/multiline_hash_argument_style.rb +171 -0
- data/lib/rubocop/cop/vibe/no_compound_conditions.rb +138 -0
- data/lib/rubocop/cop/vibe/no_rubocop_disable.rb +3 -0
- data/lib/rubocop/cop/vibe/no_skipped_tests.rb +1 -0
- data/lib/rubocop/cop/vibe/no_unless_guard_clause.rb +4 -0
- data/lib/rubocop/cop/vibe/prefer_one_liner_expectation.rb +4 -0
- data/lib/rubocop/cop/vibe/raise_unless_block.rb +1 -0
- data/lib/rubocop/cop/vibe/rspec_before_block_style.rb +114 -0
- data/lib/rubocop/cop/vibe/rspec_stub_chain_style.rb +4 -0
- data/lib/rubocop/cop/vibe_cops.rb +9 -0
- data/lib/rubocop/vibe/plugin.rb +4 -4
- data/lib/rubocop/vibe/version.rb +1 -1
- metadata +11 -2
|
@@ -27,6 +27,7 @@ module RuboCop
|
|
|
27
27
|
# DEFAULT_VALUE = 0 # Separate group, not aligned
|
|
28
28
|
class ConsecutiveConstantAlignment < Base
|
|
29
29
|
extend AutoCorrector
|
|
30
|
+
include AlignmentHelpers
|
|
30
31
|
|
|
31
32
|
MSG = "Align consecutive constant assignments at the `=` operator."
|
|
32
33
|
|
|
@@ -58,109 +59,12 @@ module RuboCop
|
|
|
58
59
|
# @return [void]
|
|
59
60
|
def check_constants_in_body(body)
|
|
60
61
|
statements = extract_statements(body)
|
|
61
|
-
return if statements.size < 2
|
|
62
|
-
|
|
63
|
-
groups = group_consecutive_constants(statements)
|
|
64
|
-
groups.each { |group| check_group_alignment(group) }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Extract statements from a body node.
|
|
68
|
-
#
|
|
69
|
-
# @param [RuboCop::AST::Node] body The body node.
|
|
70
|
-
# @return [Array<RuboCop::AST::Node>]
|
|
71
|
-
def extract_statements(body)
|
|
72
|
-
if body.begin_type?
|
|
73
|
-
body.children
|
|
74
|
-
else
|
|
75
|
-
[body]
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Group consecutive constant assignments together.
|
|
80
|
-
#
|
|
81
|
-
# @param [Array<RuboCop::AST::Node>] statements The statements.
|
|
82
|
-
# @return [Array<Array<RuboCop::AST::Node>>] Groups of consecutive constants.
|
|
83
|
-
def group_consecutive_constants(statements)
|
|
84
|
-
groups = []
|
|
85
|
-
current_group = []
|
|
86
|
-
previous_line = nil
|
|
87
|
-
|
|
88
|
-
statements.each do |statement|
|
|
89
|
-
current_group, previous_line = process_statement(statement, current_group, previous_line, groups)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
finalize_groups(groups, current_group)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Process a single statement for grouping.
|
|
96
|
-
#
|
|
97
|
-
# @param [RuboCop::AST::Node] statement The statement.
|
|
98
|
-
# @param [Array<RuboCop::AST::Node>] current_group The current group.
|
|
99
|
-
# @param [Integer, nil] previous_line The previous line number.
|
|
100
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
101
|
-
# @return [Array] The updated current_group and previous_line.
|
|
102
|
-
def process_statement(statement, current_group, previous_line, groups)
|
|
103
|
-
if constant_assignment?(statement)
|
|
104
|
-
current_group = handle_constant(statement, current_group, previous_line, groups)
|
|
105
|
-
else
|
|
106
|
-
save_group_if_valid(groups, current_group)
|
|
107
|
-
current_group = []
|
|
108
|
-
end
|
|
109
|
-
[current_group, statement.loc.last_line]
|
|
110
|
-
end
|
|
111
62
|
|
|
112
|
-
|
|
113
|
-
#
|
|
114
|
-
# Only single-line constants are considered for alignment to avoid
|
|
115
|
-
# conflicts with multi-line hash/array constants and Layout/ExtraSpacing.
|
|
116
|
-
#
|
|
117
|
-
# @param [RuboCop::AST::Node] node The node.
|
|
118
|
-
# @return [Boolean]
|
|
119
|
-
def constant_assignment?(node)
|
|
120
|
-
node.casgn_type? && single_line?(node)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
# Check if node is on a single line.
|
|
124
|
-
#
|
|
125
|
-
# @param [RuboCop::AST::Node] node The node.
|
|
126
|
-
# @return [Boolean]
|
|
127
|
-
def single_line?(node)
|
|
128
|
-
node.single_line?
|
|
129
|
-
end
|
|
63
|
+
return if statements.size < 2
|
|
130
64
|
|
|
131
|
-
|
|
132
|
-
#
|
|
133
|
-
# @param [RuboCop::AST::Node] statement The constant assignment.
|
|
134
|
-
# @param [Array<RuboCop::AST::Node>] current_group The current group.
|
|
135
|
-
# @param [Integer, nil] previous_line The previous line number.
|
|
136
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
137
|
-
# @return [Array<RuboCop::AST::Node>] The updated current group.
|
|
138
|
-
def handle_constant(statement, current_group, previous_line, groups)
|
|
139
|
-
if previous_line && statement.loc.line - previous_line > 1
|
|
140
|
-
save_group_if_valid(groups, current_group)
|
|
141
|
-
current_group = []
|
|
142
|
-
end
|
|
143
|
-
current_group << statement
|
|
144
|
-
current_group
|
|
145
|
-
end
|
|
65
|
+
groups = group_consecutive_statements(statements) { |s| s.casgn_type? && s.single_line? }
|
|
146
66
|
|
|
147
|
-
|
|
148
|
-
#
|
|
149
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
150
|
-
# @param [Array<RuboCop::AST::Node>] group The group to potentially save.
|
|
151
|
-
# @return [void]
|
|
152
|
-
def save_group_if_valid(groups, group)
|
|
153
|
-
groups << group if group.size > 1
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# Finalize groups by adding any remaining valid group.
|
|
157
|
-
#
|
|
158
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
159
|
-
# @param [Array<RuboCop::AST::Node>] current_group The current group.
|
|
160
|
-
# @return [Array<Array<RuboCop::AST::Node>>] The finalized groups.
|
|
161
|
-
def finalize_groups(groups, current_group)
|
|
162
|
-
save_group_if_valid(groups, current_group)
|
|
163
|
-
groups
|
|
67
|
+
groups.each { |group| check_group_alignment(group) }
|
|
164
68
|
end
|
|
165
69
|
|
|
166
70
|
# Check alignment for a group of constant assignments.
|
|
@@ -173,6 +77,7 @@ module RuboCop
|
|
|
173
77
|
|
|
174
78
|
group.each do |const|
|
|
175
79
|
current_column = const.loc.operator.column
|
|
80
|
+
|
|
176
81
|
next if current_column == target_column
|
|
177
82
|
|
|
178
83
|
add_offense(const.loc.name) do |corrector|
|
|
@@ -210,19 +115,6 @@ module RuboCop
|
|
|
210
115
|
|
|
211
116
|
[1, current_spaces + spaces_needed].max
|
|
212
117
|
end
|
|
213
|
-
|
|
214
|
-
# Create a source range between two positions.
|
|
215
|
-
#
|
|
216
|
-
# @param [Integer] start_pos The start position.
|
|
217
|
-
# @param [Integer] end_pos The end position.
|
|
218
|
-
# @return [Parser::Source::Range]
|
|
219
|
-
def range_between(start_pos, end_pos)
|
|
220
|
-
Parser::Source::Range.new(
|
|
221
|
-
processed_source.buffer,
|
|
222
|
-
start_pos,
|
|
223
|
-
end_pos
|
|
224
|
-
)
|
|
225
|
-
end
|
|
226
118
|
end
|
|
227
119
|
end
|
|
228
120
|
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Vibe
|
|
6
|
+
# Enforces alignment of consecutive indexed assignments at the `=` operator.
|
|
7
|
+
#
|
|
8
|
+
# Consecutive indexed assignments (with no blank lines between) should align
|
|
9
|
+
# their `=` operators for better readability. Groups are broken by blank lines.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# # bad
|
|
13
|
+
# response.headers["Cache-Control"] = "public, max-age=3600"
|
|
14
|
+
# response.headers["Content-Type"] = "application/javascript"
|
|
15
|
+
#
|
|
16
|
+
# # good
|
|
17
|
+
# response.headers["Cache-Control"] = "public, max-age=3600"
|
|
18
|
+
# response.headers["Content-Type"] = "application/javascript"
|
|
19
|
+
#
|
|
20
|
+
# # good - blank line breaks the group
|
|
21
|
+
# response.headers["Cache-Control"] = "public, max-age=3600"
|
|
22
|
+
#
|
|
23
|
+
# hash["key"] = "value" # Separate group, not aligned
|
|
24
|
+
class ConsecutiveIndexedAssignmentAlignment < Base
|
|
25
|
+
extend AutoCorrector
|
|
26
|
+
include AlignmentHelpers
|
|
27
|
+
|
|
28
|
+
MSG = "Align consecutive indexed assignments at the = operator."
|
|
29
|
+
|
|
30
|
+
# Check block nodes for indexed assignment alignment.
|
|
31
|
+
#
|
|
32
|
+
# @param [RuboCop::AST::Node] node The block node.
|
|
33
|
+
# @return [void]
|
|
34
|
+
def on_block(node)
|
|
35
|
+
if node.body
|
|
36
|
+
check_indexed_assignments_in_body(node.body)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
alias on_numblock on_block
|
|
40
|
+
|
|
41
|
+
# Check method definitions for indexed assignment alignment.
|
|
42
|
+
#
|
|
43
|
+
# @param [RuboCop::AST::Node] node The def node.
|
|
44
|
+
# @return [void]
|
|
45
|
+
def on_def(node)
|
|
46
|
+
if node.body
|
|
47
|
+
check_indexed_assignments_in_body(node.body)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
alias on_defs on_def
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# Check indexed assignments in a body node.
|
|
55
|
+
#
|
|
56
|
+
# @param [RuboCop::AST::Node] body The body node.
|
|
57
|
+
# @return [void]
|
|
58
|
+
def check_indexed_assignments_in_body(body)
|
|
59
|
+
statements = extract_statements(body)
|
|
60
|
+
|
|
61
|
+
return if statements.size < 2
|
|
62
|
+
|
|
63
|
+
groups = group_consecutive_statements(statements) { |s| indexed_assignment?(s) }
|
|
64
|
+
|
|
65
|
+
groups.each { |group| check_group_alignment(group) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Check if a node is an indexed assignment.
|
|
69
|
+
#
|
|
70
|
+
# @param [RuboCop::AST::Node] node The node to check.
|
|
71
|
+
# @return [Boolean]
|
|
72
|
+
def indexed_assignment?(node)
|
|
73
|
+
node.send_type? && node.method?(:[]=)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Check alignment for a group of indexed assignments.
|
|
77
|
+
#
|
|
78
|
+
# @param [Array<RuboCop::AST::Node>] group The assignment group.
|
|
79
|
+
# @return [void]
|
|
80
|
+
def check_group_alignment(group)
|
|
81
|
+
columns = group.map { |asgn| asgn.loc.operator.column }
|
|
82
|
+
target_column = columns.max
|
|
83
|
+
|
|
84
|
+
group.each do |asgn|
|
|
85
|
+
current_column = asgn.loc.operator.column
|
|
86
|
+
|
|
87
|
+
next if current_column == target_column
|
|
88
|
+
|
|
89
|
+
add_offense(offense_location(asgn)) do |corrector|
|
|
90
|
+
autocorrect_alignment(corrector, asgn, target_column)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Get the location to highlight for the offense.
|
|
96
|
+
#
|
|
97
|
+
# @param [RuboCop::AST::Node] asgn The indexed assignment node.
|
|
98
|
+
# @return [Parser::Source::Range]
|
|
99
|
+
def offense_location(asgn)
|
|
100
|
+
asgn.loc.selector
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Auto-correct the alignment of an indexed assignment.
|
|
104
|
+
#
|
|
105
|
+
# @param [RuboCop::AST::Corrector] corrector The corrector.
|
|
106
|
+
# @param [RuboCop::AST::Node] asgn The indexed assignment node.
|
|
107
|
+
# @param [Integer] target_column The target column for alignment.
|
|
108
|
+
# @return [void]
|
|
109
|
+
def autocorrect_alignment(corrector, asgn, target_column)
|
|
110
|
+
bracket_end = closing_bracket_end_pos(asgn)
|
|
111
|
+
operator_start = asgn.loc.operator.begin_pos
|
|
112
|
+
total_spaces = calculate_total_spaces(asgn, target_column, bracket_end, operator_start)
|
|
113
|
+
|
|
114
|
+
corrector.replace(
|
|
115
|
+
range_between(bracket_end, operator_start),
|
|
116
|
+
" " * total_spaces
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Get the position after the closing bracket.
|
|
121
|
+
#
|
|
122
|
+
# @param [RuboCop::AST::Node] asgn The indexed assignment node.
|
|
123
|
+
# @return [Integer]
|
|
124
|
+
def closing_bracket_end_pos(asgn)
|
|
125
|
+
asgn.first_argument.source_range.end_pos + 1
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Calculate total spaces needed for alignment.
|
|
129
|
+
#
|
|
130
|
+
# @param [RuboCop::AST::Node] asgn The indexed assignment node.
|
|
131
|
+
# @param [Integer] target_column The target column for alignment.
|
|
132
|
+
# @param [Integer] bracket_end Position after the closing bracket.
|
|
133
|
+
# @param [Integer] operator_start Position of the operator.
|
|
134
|
+
# @return [Integer] The number of spaces (minimum 1).
|
|
135
|
+
def calculate_total_spaces(asgn, target_column, bracket_end, operator_start)
|
|
136
|
+
current_column = asgn.loc.operator.column
|
|
137
|
+
current_spaces = operator_start - bracket_end
|
|
138
|
+
spaces_needed = target_column - current_column
|
|
139
|
+
|
|
140
|
+
[1, current_spaces + spaces_needed].max
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Vibe
|
|
6
|
+
# Enforces alignment of consecutive instance variable assignments at the `=` operator.
|
|
7
|
+
#
|
|
8
|
+
# Consecutive assignments (with no blank lines between) should align their
|
|
9
|
+
# `=` operators for better readability. Groups are broken by blank lines.
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# # bad
|
|
13
|
+
# @user = create(:user)
|
|
14
|
+
# @character = create(:character)
|
|
15
|
+
# @input = "test"
|
|
16
|
+
#
|
|
17
|
+
# # good
|
|
18
|
+
# @user = create(:user)
|
|
19
|
+
# @character = create(:character)
|
|
20
|
+
# @input = "test"
|
|
21
|
+
#
|
|
22
|
+
# # good - blank line breaks the group
|
|
23
|
+
# @user = create(:user)
|
|
24
|
+
# @character = create(:character)
|
|
25
|
+
#
|
|
26
|
+
# @service = Users::Activate.new
|
|
27
|
+
# @activation = service.call
|
|
28
|
+
class ConsecutiveInstanceVariableAssignmentAlignment < Base
|
|
29
|
+
extend AutoCorrector
|
|
30
|
+
include AlignmentHelpers
|
|
31
|
+
|
|
32
|
+
MSG = "Align consecutive instance variable assignments at the = operator."
|
|
33
|
+
|
|
34
|
+
# Check block nodes for assignment alignment.
|
|
35
|
+
#
|
|
36
|
+
# @param [RuboCop::AST::Node] node The block node.
|
|
37
|
+
# @return [void]
|
|
38
|
+
def on_block(node)
|
|
39
|
+
if node.body
|
|
40
|
+
check_assignments_in_body(node.body)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
alias on_numblock on_block
|
|
44
|
+
|
|
45
|
+
# Check method definitions for assignment alignment.
|
|
46
|
+
#
|
|
47
|
+
# @param [RuboCop::AST::Node] node The def node.
|
|
48
|
+
# @return [void]
|
|
49
|
+
def on_def(node)
|
|
50
|
+
if node.body
|
|
51
|
+
check_assignments_in_body(node.body)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
alias on_defs on_def
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
# Check assignments in a body node.
|
|
59
|
+
#
|
|
60
|
+
# @param [RuboCop::AST::Node] body The body node.
|
|
61
|
+
# @return [void]
|
|
62
|
+
def check_assignments_in_body(body)
|
|
63
|
+
statements = extract_statements(body)
|
|
64
|
+
|
|
65
|
+
return if statements.size < 2
|
|
66
|
+
|
|
67
|
+
groups = group_consecutive_statements(statements, &:ivasgn_type?)
|
|
68
|
+
|
|
69
|
+
groups.each { |group| check_group_alignment(group) }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Check alignment for a group of assignments.
|
|
73
|
+
#
|
|
74
|
+
# @param [Array<RuboCop::AST::Node>] group The assignment group.
|
|
75
|
+
# @return [void]
|
|
76
|
+
def check_group_alignment(group)
|
|
77
|
+
columns = group.map { |asgn| asgn.loc.operator.column }
|
|
78
|
+
target_column = columns.max
|
|
79
|
+
|
|
80
|
+
group.each do |asgn|
|
|
81
|
+
current_column = asgn.loc.operator.column
|
|
82
|
+
|
|
83
|
+
next if current_column == target_column
|
|
84
|
+
|
|
85
|
+
add_offense(asgn.loc.name) do |corrector|
|
|
86
|
+
autocorrect_alignment(corrector, asgn, target_column)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Auto-correct the alignment of an assignment.
|
|
92
|
+
#
|
|
93
|
+
# @param [RuboCop::AST::Corrector] corrector The corrector.
|
|
94
|
+
# @param [RuboCop::AST::Node] asgn The assignment node.
|
|
95
|
+
# @param [Integer] target_column The target column for alignment.
|
|
96
|
+
# @return [void]
|
|
97
|
+
def autocorrect_alignment(corrector, asgn, target_column)
|
|
98
|
+
variable_name_end = asgn.loc.name.end_pos
|
|
99
|
+
operator_start = asgn.loc.operator.begin_pos
|
|
100
|
+
total_spaces = calculate_total_spaces(asgn, target_column)
|
|
101
|
+
|
|
102
|
+
corrector.replace(
|
|
103
|
+
range_between(variable_name_end, operator_start),
|
|
104
|
+
" " * total_spaces
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Calculate total spaces needed for alignment.
|
|
109
|
+
#
|
|
110
|
+
# @param [RuboCop::AST::Node] asgn The assignment node.
|
|
111
|
+
# @param [Integer] target_column The target column for alignment.
|
|
112
|
+
# @return [Integer] The number of spaces (minimum 1).
|
|
113
|
+
def calculate_total_spaces(asgn, target_column)
|
|
114
|
+
current_column = asgn.loc.operator.column
|
|
115
|
+
current_spaces = asgn.loc.operator.begin_pos - asgn.loc.name.end_pos
|
|
116
|
+
spaces_needed = target_column - current_column
|
|
117
|
+
|
|
118
|
+
[1, current_spaces + spaces_needed].max
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -28,6 +28,7 @@ module RuboCop
|
|
|
28
28
|
class ConsecutiveLetAlignment < Base
|
|
29
29
|
extend AutoCorrector
|
|
30
30
|
include SpecFileHelper
|
|
31
|
+
include AlignmentHelpers
|
|
31
32
|
|
|
32
33
|
MSG = "Align consecutive `let` declarations at the `{` brace."
|
|
33
34
|
|
|
@@ -66,90 +67,12 @@ module RuboCop
|
|
|
66
67
|
# @return [void]
|
|
67
68
|
def check_lets_in_body(body)
|
|
68
69
|
statements = extract_statements(body)
|
|
69
|
-
return if statements.size < 2
|
|
70
|
-
|
|
71
|
-
groups = group_consecutive_lets(statements)
|
|
72
|
-
groups.each { |group| check_group_alignment(group) }
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Extract statements from a body node.
|
|
76
|
-
#
|
|
77
|
-
# @param [RuboCop::AST::Node] body The body node.
|
|
78
|
-
# @return [Array<RuboCop::AST::Node>]
|
|
79
|
-
def extract_statements(body)
|
|
80
|
-
if body.begin_type?
|
|
81
|
-
body.children
|
|
82
|
-
else
|
|
83
|
-
[body]
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Group consecutive let declarations together.
|
|
88
|
-
#
|
|
89
|
-
# @param [Array<RuboCop::AST::Node>] statements The statements.
|
|
90
|
-
# @return [Array<Array<RuboCop::AST::Node>>] Groups of consecutive lets.
|
|
91
|
-
def group_consecutive_lets(statements)
|
|
92
|
-
groups = []
|
|
93
|
-
current_group = []
|
|
94
|
-
previous_line = nil
|
|
95
|
-
|
|
96
|
-
statements.each do |statement|
|
|
97
|
-
current_group, previous_line = process_statement(statement, current_group, previous_line, groups)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
finalize_groups(groups, current_group)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
# Process a single statement for grouping.
|
|
104
|
-
#
|
|
105
|
-
# @param [RuboCop::AST::Node] statement The statement.
|
|
106
|
-
# @param [Array<RuboCop::AST::Node>] current_group The current group.
|
|
107
|
-
# @param [Integer, nil] previous_line The previous line number.
|
|
108
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
109
|
-
# @return [Array] The updated current_group and previous_line.
|
|
110
|
-
def process_statement(statement, current_group, previous_line, groups)
|
|
111
|
-
if let_declaration?(statement)
|
|
112
|
-
current_group = handle_let(statement, current_group, previous_line, groups)
|
|
113
|
-
else
|
|
114
|
-
save_group_if_valid(groups, current_group)
|
|
115
|
-
current_group = []
|
|
116
|
-
end
|
|
117
|
-
[current_group, statement.loc.last_line]
|
|
118
|
-
end
|
|
119
70
|
|
|
120
|
-
|
|
121
|
-
#
|
|
122
|
-
# @param [RuboCop::AST::Node] statement The let declaration.
|
|
123
|
-
# @param [Array<RuboCop::AST::Node>] current_group The current group.
|
|
124
|
-
# @param [Integer, nil] previous_line The previous line number.
|
|
125
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
126
|
-
# @return [Array<RuboCop::AST::Node>] The updated current group.
|
|
127
|
-
def handle_let(statement, current_group, previous_line, groups)
|
|
128
|
-
if previous_line && statement.loc.line - previous_line > 1
|
|
129
|
-
save_group_if_valid(groups, current_group)
|
|
130
|
-
current_group = []
|
|
131
|
-
end
|
|
132
|
-
current_group << statement
|
|
133
|
-
current_group
|
|
134
|
-
end
|
|
71
|
+
return if statements.size < 2
|
|
135
72
|
|
|
136
|
-
|
|
137
|
-
#
|
|
138
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
139
|
-
# @param [Array<RuboCop::AST::Node>] group The group to potentially save.
|
|
140
|
-
# @return [void]
|
|
141
|
-
def save_group_if_valid(groups, group)
|
|
142
|
-
groups << group if group.size > 1
|
|
143
|
-
end
|
|
73
|
+
groups = group_consecutive_statements(statements) { |s| let_declaration?(s) }
|
|
144
74
|
|
|
145
|
-
|
|
146
|
-
#
|
|
147
|
-
# @param [Array<Array<RuboCop::AST::Node>>] groups The groups.
|
|
148
|
-
# @param [Array<RuboCop::AST::Node>] current_group The current group.
|
|
149
|
-
# @return [Array<Array<RuboCop::AST::Node>>] The finalized groups.
|
|
150
|
-
def finalize_groups(groups, current_group)
|
|
151
|
-
save_group_if_valid(groups, current_group)
|
|
152
|
-
groups
|
|
75
|
+
groups.each { |group| check_group_alignment(group) }
|
|
153
76
|
end
|
|
154
77
|
|
|
155
78
|
# Check alignment for a group of let declarations.
|
|
@@ -162,6 +85,7 @@ module RuboCop
|
|
|
162
85
|
|
|
163
86
|
group.each do |let|
|
|
164
87
|
current_column = let.loc.begin.column
|
|
88
|
+
|
|
165
89
|
next if current_column == target_column
|
|
166
90
|
|
|
167
91
|
add_offense(let.send_node) do |corrector|
|
|
@@ -200,19 +124,6 @@ module RuboCop
|
|
|
200
124
|
|
|
201
125
|
[1, current_spaces + spaces_needed].max
|
|
202
126
|
end
|
|
203
|
-
|
|
204
|
-
# Create a source range between two positions.
|
|
205
|
-
#
|
|
206
|
-
# @param [Integer] start_pos The start position.
|
|
207
|
-
# @param [Integer] end_pos The end position.
|
|
208
|
-
# @return [Parser::Source::Range]
|
|
209
|
-
def range_between(start_pos, end_pos)
|
|
210
|
-
Parser::Source::Range.new(
|
|
211
|
-
processed_source.buffer,
|
|
212
|
-
start_pos,
|
|
213
|
-
end_pos
|
|
214
|
-
)
|
|
215
|
-
end
|
|
216
127
|
end
|
|
217
128
|
end
|
|
218
129
|
end
|
|
@@ -83,9 +83,11 @@ module RuboCop
|
|
|
83
83
|
return unless top_level_describe?(node)
|
|
84
84
|
|
|
85
85
|
describe_blocks = extract_describe_blocks(node)
|
|
86
|
+
|
|
86
87
|
return if describe_blocks.size < 2
|
|
87
88
|
|
|
88
89
|
violations = find_ordering_violations(describe_blocks)
|
|
90
|
+
|
|
89
91
|
violations.each do |block_info|
|
|
90
92
|
add_offense(block_info[:node]) do |corrector|
|
|
91
93
|
autocorrect(corrector, describe_blocks)
|
|
@@ -153,15 +155,15 @@ module RuboCop
|
|
|
153
155
|
# @return [nil] When description is not a string/symbol literal.
|
|
154
156
|
def extract_description(node)
|
|
155
157
|
first_arg = node.send_node.first_argument
|
|
158
|
+
|
|
156
159
|
return unless first_arg
|
|
157
160
|
|
|
158
161
|
if first_arg.str_type?
|
|
159
162
|
first_arg.value
|
|
160
163
|
elsif first_arg.sym_type?
|
|
161
164
|
first_arg.value.to_s
|
|
162
|
-
# Intentionally returns nil for constants/variables.
|
|
163
|
-
# These will get DEFAULT_PRIORITY.
|
|
164
165
|
end
|
|
166
|
+
# Returns nil for constants/variables - they get DEFAULT_PRIORITY.
|
|
165
167
|
end
|
|
166
168
|
|
|
167
169
|
# Categorize description and assign priority.
|
|
@@ -202,6 +204,7 @@ module RuboCop
|
|
|
202
204
|
def controller_action_priority(description)
|
|
203
205
|
# Strip the # prefix for controller actions.
|
|
204
206
|
action_name = description.start_with?("#") ? description[1..] : description
|
|
207
|
+
|
|
205
208
|
if controller_action?(action_name)
|
|
206
209
|
30 + CONTROLLER_ACTIONS.index(action_name)
|
|
207
210
|
end
|
|
@@ -251,6 +254,7 @@ module RuboCop
|
|
|
251
254
|
|
|
252
255
|
blocks.each_with_index do |block, index|
|
|
253
256
|
sorted_block = sorted_blocks[index]
|
|
257
|
+
|
|
254
258
|
next if block == sorted_block
|
|
255
259
|
|
|
256
260
|
corrector.replace(block[:node], sorted_block[:node].source)
|