rubocop-vibe 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
- # Check if node is a single-line constant assignment.
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
- # Handle a constant assignment.
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
- # Save group if it has multiple constant assignments.
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
@@ -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
- # Handle a let declaration.
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
- # Save group if it has multiple let declarations.
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
- # Finalize groups by adding any remaining valid group.
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)
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Vibe
6
+ # Enforces using explicit `if`/`else`/`end` blocks instead of ternary operators
7
+ # or trailing conditionals when they are the return value of a method.
8
+ #
9
+ # Ternary operators and trailing conditionals can be harder to read when used
10
+ # as method return values. This cop enforces converting them to explicit
11
+ # `if`/`else`/`end` blocks for better readability.
12
+ #
13
+ # @example
14
+ # # bad - ternary as return value
15
+ # def allow_origin
16
+ # origin = request.headers["Origin"]
17
+ # origin_allowed?(origin) ? origin : "*"
18
+ # end
19
+ #
20
+ # # good - explicit if/else
21
+ # def allow_origin
22
+ # origin = request.headers["Origin"]
23
+ # if origin_allowed?(origin)
24
+ # origin
25
+ # else
26
+ # "*"
27
+ # end
28
+ # end
29
+ #
30
+ # # bad - trailing conditional as return value
31
+ # def vary
32
+ # "Origin" if website.present?
33
+ # end
34
+ #
35
+ # # good - explicit if block
36
+ # def vary
37
+ # if website.present?
38
+ # "Origin"
39
+ # end
40
+ # end
41
+ #
42
+ # # good - ternary used in assignment (not as return value)
43
+ # def example
44
+ # result = condition ? "yes" : "no"
45
+ # process(result)
46
+ # end
47
+ class ExplicitReturnConditional < Base
48
+ extend AutoCorrector
49
+
50
+ MSG_TERNARY = "Use explicit `if`/`else`/`end` block instead of ternary operator for return value."
51
+ MSG_MODIFIER = "Use explicit `if`/`end` block instead of trailing conditional for return value."
52
+
53
+ # Check method definitions for conditional return values.
54
+ #
55
+ # @param [RuboCop::AST::Node] node The def node.
56
+ # @return [void]
57
+ def on_def(node)
58
+ if node.body
59
+ check_return_value(node.body)
60
+ end
61
+ end
62
+ alias on_defs on_def
63
+
64
+ private
65
+
66
+ # Check if the return value is a conditional that should be explicit.
67
+ #
68
+ # @param [RuboCop::AST::Node] body The method body node.
69
+ # @return [void]
70
+ def check_return_value(body)
71
+ return_node = find_return_node(body)
72
+
73
+ return unless return_node.if_type?
74
+
75
+ if return_node.ternary?
76
+ register_ternary_offense(return_node)
77
+ elsif return_node.modifier_form?
78
+ register_modifier_offense(return_node)
79
+ end
80
+ end
81
+
82
+ # Find the node that represents the return value.
83
+ #
84
+ # @param [RuboCop::AST::Node] body The method body node.
85
+ # @return [RuboCop::AST::Node, nil]
86
+ def find_return_node(body)
87
+ if body.begin_type?
88
+ body.children.last
89
+ else
90
+ body
91
+ end
92
+ end
93
+
94
+ # Register offense for ternary operator.
95
+ #
96
+ # @param [RuboCop::AST::Node] node The ternary node.
97
+ # @return [void]
98
+ def register_ternary_offense(node)
99
+ add_offense(node, message: MSG_TERNARY) do |corrector|
100
+ autocorrect_ternary(corrector, node)
101
+ end
102
+ end
103
+
104
+ # Register offense for modifier conditional.
105
+ #
106
+ # @param [RuboCop::AST::Node] node The modifier if node.
107
+ # @return [void]
108
+ def register_modifier_offense(node)
109
+ add_offense(node, message: MSG_MODIFIER) do |corrector|
110
+ autocorrect_modifier(corrector, node)
111
+ end
112
+ end
113
+
114
+ # Autocorrect ternary operator to if/else/end block.
115
+ #
116
+ # @param [RuboCop::Cop::Corrector] corrector The corrector.
117
+ # @param [RuboCop::AST::Node] node The ternary node.
118
+ # @return [void]
119
+ def autocorrect_ternary(corrector, node)
120
+ corrector.replace(node, build_if_else_block(node))
121
+ end
122
+
123
+ # Autocorrect modifier conditional to if/end block.
124
+ #
125
+ # @param [RuboCop::Cop::Corrector] corrector The corrector.
126
+ # @param [RuboCop::AST::Node] node The modifier if node.
127
+ # @return [void]
128
+ def autocorrect_modifier(corrector, node)
129
+ corrector.replace(node, build_if_block(node))
130
+ end
131
+
132
+ # Build if/else/end block replacement for ternary.
133
+ #
134
+ # @param [RuboCop::AST::Node] node The ternary node.
135
+ # @return [String]
136
+ def build_if_else_block(node)
137
+ base_indent = " " * node.loc.column
138
+ inner_indent = "#{base_indent} "
139
+
140
+ [
141
+ "if #{node.condition.source}",
142
+ "#{inner_indent}#{node.if_branch.source}",
143
+ "#{base_indent}else",
144
+ "#{inner_indent}#{node.else_branch.source}",
145
+ "#{base_indent}end"
146
+ ].join("\n")
147
+ end
148
+
149
+ # Build if/end block replacement for modifier conditional.
150
+ #
151
+ # @param [RuboCop::AST::Node] node The modifier if node.
152
+ # @return [String]
153
+ def build_if_block(node)
154
+ condition = build_condition(node)
155
+ base_indent = " " * node.loc.column
156
+ inner_indent = "#{base_indent} "
157
+
158
+ [
159
+ "if #{condition}",
160
+ "#{inner_indent}#{node.if_branch.source}",
161
+ "#{base_indent}end"
162
+ ].join("\n")
163
+ end
164
+
165
+ # Build the condition for the if block.
166
+ # For unless, negate the condition. For if, keep it as is.
167
+ #
168
+ # @param [RuboCop::AST::Node] node The if node.
169
+ # @return [String] The condition source.
170
+ def build_condition(node)
171
+ if node.unless?
172
+ negate_condition(node.condition)
173
+ else
174
+ node.condition.source
175
+ end
176
+ end
177
+
178
+ # Negate a condition, handling simple cases cleanly.
179
+ #
180
+ # @param [RuboCop::AST::Node] condition The condition node.
181
+ # @return [String] The negated condition.
182
+ def negate_condition(condition)
183
+ if condition.send_type? && condition.method?(:!)
184
+ condition.receiver.source
185
+ else
186
+ "!#{condition.source}"
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -45,6 +45,7 @@ module RuboCop
45
45
  return unless is_expected_call?(node)
46
46
 
47
47
  example_block = find_example_block(node)
48
+
48
49
  return unless example_block
49
50
  return unless example_block_with_description?(example_block)
50
51
  return if complex_expectation?(example_block)
@@ -65,6 +66,7 @@ module RuboCop
65
66
  def find_example_block(node)
66
67
  node.each_ancestor(:block).find do |ancestor|
67
68
  send_node = ancestor.send_node
69
+
68
70
  send_node.method?(:it) || send_node.method?(:specify)
69
71
  end
70
72
  end
@@ -100,6 +102,7 @@ module RuboCop
100
102
  # @return [void]
101
103
  def autocorrect(corrector, node)
102
104
  expectation_source = node.body.source
105
+
103
106
  corrector.replace(node, "it { #{expectation_source} }")
104
107
  end
105
108
  end