66require "rubocop"
77
88module RuboCop
9- module Cop
9+ module Socketry
1010 module Layout
11- # This cop requires that blank lines have the correct indentation based on AST structure.
11+ # A RuboCop cop that enforces consistent blank line indentation based on AST structure.
12+ # This cop ensures that blank lines are indented correctly according to their context in the code,
13+ # using a two-pass algorithm that analyzes the AST to determine proper indentation levels.
1214 class ConsistentBlankLineIndentation < RuboCop ::Cop ::Base
13- extend RuboCop :: Cop ::AutoCorrector
14- include Alignment
15- include RangeHelp
15+ extend Cop ::AutoCorrector
16+ include Cop :: Alignment
17+ include Cop :: RangeHelp
1618
19+ # @attribute [String] The message displayed when a blank line has incorrect indentation.
1720 MESSAGE = "Blank lines must have the correct indentation."
1821
22+ # Get the configured indentation width from cop configuration or fallback to default.
23+ # @returns [Integer] The number of spaces or tabs to use for each indentation level.
1924 def configured_indentation_width
2025 cop_config [ "IndentationWidth" ] || config . for_cop ( "Layout/IndentationWidth" ) [ "Width" ] || 1
2126 end
2227
28+ # Get the configured indentation style from cop configuration or fallback to default.
29+ # @returns [String] The indentation style, either "tab" or "space".
2330 def configured_indentation_style
2431 cop_config [ "IndentationStyle" ] || config . for_cop ( "Layout/IndentationStyle" ) [ "Style" ] || "tab"
2532 end
2633
34+ # Generate indentation string based on the current level and configured style.
35+ # @parameter width [Integer] The number of indentation levels to apply.
36+ # @returns [String] The indentation string (tabs or spaces).
2737 def indentation ( width )
2838 case configured_indentation_style
2939 when "tab"
@@ -33,14 +43,17 @@ def indentation(width)
3343 end
3444 end
3545
46+ # Main investigation method that processes the source code and checks blank line indentation.
47+ # This method implements a two-pass algorithm: first building indentation deltas from the AST,
48+ # then processing each line to check blank lines against expected indentation.
3649 def on_new_investigation
3750 indentation_deltas = build_indentation_deltas
3851 current_level = 0
3952
4053 processed_source . lines . each_with_index do |line , index |
4154 line_number = index + 1
4255
43- # Blank line :
56+ # Check blank lines for correct indentation :
4457 if line . strip . empty?
4558 expected_indentation = indentation ( current_level )
4659 if line != expected_indentation
@@ -56,20 +69,27 @@ def on_new_investigation
5669 end
5770 end
5871
72+ # Apply indentation delta for this line:
5973 delta = indentation_deltas [ line_number ] || 0
6074 current_level += delta
6175 end
6276 end
6377
6478 private
6579
66- # Build a hash of line_number => delta (+1 for indent, -1 for dedent)
80+ # Build a hash mapping line numbers to indentation deltas (+1 for indent, -1 for dedent).
81+ # This method walks the AST to identify where indentation should increase or decrease.
82+ # @returns [Hash(Integer, Integer)] A hash where keys are line numbers and values are deltas.
6783 def build_indentation_deltas
6884 deltas = Hash . new ( 0 )
6985 walk_ast_for_indentation ( processed_source . ast , deltas )
7086 deltas
7187 end
7288
89+ # Recursively walk the AST to build indentation deltas for block structures.
90+ # This method identifies nodes that should affect indentation and records the deltas.
91+ # @parameter node [Parser::AST::Node] The current AST node to process.
92+ # @parameter deltas [Hash(Integer, Integer)] The deltas hash to populate.
7393 def walk_ast_for_indentation ( node , deltas )
7494 return unless node . is_a? ( Parser ::AST ::Node )
7595
@@ -86,6 +106,12 @@ def walk_ast_for_indentation(node, deltas)
86106 end
87107 end
88108
109+ # Create a source range for a specific line and column position.
110+ # @parameter buffer [Parser::Source::Buffer] The source buffer.
111+ # @parameter line [Integer] The line number (1-indexed).
112+ # @parameter column [Integer] The column position.
113+ # @parameter length [Integer] The length of the range.
114+ # @returns [Parser::Source::Range] The source range object.
89115 def source_range ( buffer , line , column , length )
90116 Parser ::Source ::Range . new ( buffer , buffer . line_range ( line ) . begin_pos + column , buffer . line_range ( line ) . begin_pos + column + length )
91117 end
0 commit comments