Class: RuboCop::Cop::Sane::EmptyLinesAroundMultilineBlock
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::Sane::EmptyLinesAroundMultilineBlock
- Extended by:
- AutoCorrector
- Defined in:
- lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb
Overview
This cop enforces empty lines before and after multiline blocks such as ‘if/else` and `case/when`.
Constant Summary collapse
- MSG_BEFORE =
"Add empty line before multiline `%<keyword>s` block."- MSG_AFTER =
"Add empty line after multiline `%<keyword>s` block."
Instance Method Summary collapse
- #assignment_node?(node) ⇒ Boolean
- #chained_block?(node) ⇒ Boolean
- #followed_by_rescue?(node) ⇒ Boolean
- #lambda_block?(node) ⇒ Boolean
- #on_block(node) ⇒ Object (also: #on_numblock)
- #on_case(node) ⇒ Object (also: #on_case_match)
- #on_if(node) ⇒ Object
- #paired_methods?(prev_method, current_method) ⇒ Boolean
- #part_of_assignment?(node) ⇒ Boolean
- #part_of_expression?(node) ⇒ Boolean
- #preceded_by_paired_method?(node, prev_sibling) ⇒ Boolean
Instance Method Details
#assignment_node?(node) ⇒ Boolean
148 149 150 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 148 def assignment_node?(node) [:lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn, :masgn, :op_asgn, :or_asgn, :and_asgn].include?(node.type) end |
#chained_block?(node) ⇒ Boolean
115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 115 def chained_block?(node) # Skip blocks that are part of a method chain # e.g., expect { ... }.to raise_error # e.g., foo.map { ... }&.join (csend is safe navigation &.) parent = node.parent return true if (parent&.send_type? || parent&.csend_type?) && parent.receiver == node # Skip blocks that are part of an assignment expression # e.g., self.foo = items.map do ... end return true if part_of_assignment?(node) false end |
#followed_by_rescue?(node) ⇒ Boolean
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 170 def followed_by_rescue?(node) # Don't require blank line before rescue clause parent = node.parent return false unless parent # Check if parent is a rescue node and next sibling is a resbody if parent.rescue_type? siblings = parent.children index = siblings.index(node) return false unless index next_sib = siblings[index + 1] return next_sib&.resbody_type? end false end |
#lambda_block?(node) ⇒ Boolean
111 112 113 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 111 def lambda_block?(node) node.send_node&.lambda_literal? end |
#on_block(node) ⇒ Object Also known as: on_numblock
100 101 102 103 104 105 106 107 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 100 def on_block(node) return unless multiline?(node) return if chained_block?(node) # e.g., expect { ... }.to raise_error return if lambda_block?(node) # e.g., -> { ... } or -> do ... end check_empty_line_before(node) check_empty_line_after(node) end |
#on_case(node) ⇒ Object Also known as: on_case_match
91 92 93 94 95 96 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 91 def on_case(node) return unless multiline?(node) check_empty_line_before(node) check_empty_line_after(node) end |
#on_if(node) ⇒ Object
58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 58 def on_if(node) return if node.ternary? return if node.modifier_form? return if node.elsif? # elsif is part of parent if, not a separate block return unless multiline?(node) return if part_of_expression?(node) check_empty_line_before(node) check_empty_line_after(node) end |
#paired_methods?(prev_method, current_method) ⇒ Boolean
165 166 167 168 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 165 def paired_methods?(prev_method, current_method) # desc + task is idiomatic in rake files prev_method == :desc && current_method == :task end |
#part_of_assignment?(node) ⇒ Boolean
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 129 def part_of_assignment?(node) parent = node.parent return false unless parent # Direct assignment: foo = bar.map do...end return true if assignment_node?(parent) # Assignment via setter: self.foo = bar.map do...end return true if parent.send_type? && parent.method_name.to_s.end_with?("=") # Hash value: { key: items.map do...end } return true if parent.pair_type? # Array element: [items.map do...end] return true if parent.array_type? false end |
#part_of_expression?(node) ⇒ Boolean
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 69 def part_of_expression?(node) parent = node.parent return false unless parent # Part of assignment: foo = if ... end return true if assignment_node?(parent) # Part of setter call: obj.foo = if ... end return true if parent.send_type? && parent.method_name.to_s.end_with?("=") # Part of method arguments: foo(if ... end) return true if parent.send_type? && parent.arguments.include?(node) # Part of array: [if ... end] return true if parent.array_type? # Part of hash value: { key: if ... end } return true if parent.pair_type? false end |
#preceded_by_paired_method?(node, prev_sibling) ⇒ Boolean
152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/rubocop/cop/sane/empty_lines_around_multiline_block.rb', line 152 def preceded_by_paired_method?(node, prev_sibling) # Skip blank line requirement for idiomatic pairings like desc + task # Only applies to block nodes return false unless node.block_type? || node.numblock_type? return false unless prev_sibling&.send_type? return false unless node.send_node prev_method = prev_sibling.method_name current_method = node.send_node.method_name paired_methods?(prev_method, current_method) end |