Class: LiquidXlsx::RenderState
- Inherits:
-
Object
- Object
- LiquidXlsx::RenderState
- Defined in:
- lib/liquid_xlsx/renderer.rb
Overview
Tracks merge cells, formula expansions, and block boundaries.
Instance Attribute Summary collapse
-
#formula_translator ⇒ Object
readonly
Returns the value of attribute formula_translator.
Instance Method Summary collapse
- #build_merge_ranges ⇒ Object
-
#check_block_boundaries(sheet_name) ⇒ Object
Check if any merge cell crosses a structural block boundary.
-
#current_path ⇒ Object
Current iteration path: indices of all active loop iterations.
- #end_iteration ⇒ Object
-
#end_loop ⇒ Object
Aggregate per-iteration row maps of the current loop execution into a single => [rendered_row, ...] hash and pop the frame.
- #enter_block(type, for_row, endfor_row) ⇒ Object
-
#initialize(merge_transformer, original_merges, formula_translator) ⇒ RenderState
constructor
A new instance of RenderState.
- #leave_block ⇒ Object
- #record_row(template_row_num, new_row_num) ⇒ Object
- #start_iteration(index) ⇒ Object
- #start_loop ⇒ Object
Constructor Details
#initialize(merge_transformer, original_merges, formula_translator) ⇒ RenderState
Returns a new instance of RenderState.
613 614 615 616 617 618 619 620 621 622 623 624 625 |
# File 'lib/liquid_xlsx/renderer.rb', line 613 def initialize(merge_transformer, original_merges, formula_translator) @merge_transformer = merge_transformer @original_merges = original_merges @formula_translator = formula_translator # Map: template_row_num => [new_row_num, ...] (multiple for loop iterations) @row_map = {} # Structural block boundaries (template row numbers) for merge crossing detection @blocks = [] # Current loop state # Each frame: { iterations: [...], current_iteration: {row_map: {}, index:} or nil } @loop_stack = [] end |
Instance Attribute Details
#formula_translator ⇒ Object (readonly)
Returns the value of attribute formula_translator.
611 612 613 |
# File 'lib/liquid_xlsx/renderer.rb', line 611 def formula_translator @formula_translator end |
Instance Method Details
#build_merge_ranges ⇒ Object
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
# File 'lib/liquid_xlsx/renderer.rb', line 702 def build_merge_ranges result = [] @original_merges.each do |merge_info| ref = merge_info[:ref] start_template_row = merge_info[:start_row] end_template_row = merge_info[:end_row] # Skip merges on structural rows (consumed by parser) unless @row_map.key?(start_template_row) || @row_map.key?(end_template_row) next end if @row_map.key?(start_template_row) && @row_map.key?(end_template_row) start_rows = @row_map[start_template_row] end_rows = @row_map[end_template_row] start_rows.each_with_index do |sr, i| er = end_rows[i] || sr cloned = clone_merge(ref, sr - start_template_row, er - end_template_row) result << cloned if cloned end elsif @row_map.key?(start_template_row) @row_map[start_template_row].each do |nr| cloned = clone_merge_row(ref, nr - start_template_row) result << cloned if cloned end else result << ref end end result end |
#check_block_boundaries(sheet_name) ⇒ Object
Check if any merge cell crosses a structural block boundary. Both block bounds and merge bounds use template row numbers.
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 |
# File 'lib/liquid_xlsx/renderer.rb', line 684 def check_block_boundaries(sheet_name) @original_merges.each do |merge_info| merge_start = merge_info[:start_row] merge_end = merge_info[:end_row] @blocks.each do |block| next unless crosses_boundary?(merge_start, merge_end, block[:start], block[:end]) raise UnsupportedTemplateError.new( "Merged cell '#{merge_info[:ref]}' crosses a #{block[:type]} block boundary " \ "(template rows #{block[:start]}-#{block[:end]})", sheet: sheet_name, block_rows: "rows #{block[:start]}-#{block[:end]}" ) end end end |
#current_path ⇒ Object
Current iteration path: indices of all active loop iterations. Used for formula-path and expansion-path visibility filtering.
678 679 680 |
# File 'lib/liquid_xlsx/renderer.rb', line 678 def current_path @loop_stack.filter_map { |f| f[:current_iteration]&.dig(:index) } end |
#end_iteration ⇒ Object
657 658 659 660 |
# File 'lib/liquid_xlsx/renderer.rb', line 657 def end_iteration @loop_stack.last[:iterations] << @loop_stack.last[:current_iteration] @loop_stack.last[:current_iteration] = nil end |
#end_loop ⇒ Object
Aggregate per-iteration row maps of the current loop execution into a single => [rendered_row, ...] hash and pop the frame.
664 665 666 667 668 669 670 671 672 673 674 |
# File 'lib/liquid_xlsx/renderer.rb', line 664 def end_loop frame = @loop_stack.pop aggregate = {} frame[:iterations].each do |iter| iter[:row_map].each do |t_row, r_rows| aggregate[t_row] ||= [] aggregate[t_row].concat(r_rows) end end aggregate end |
#enter_block(type, for_row, endfor_row) ⇒ Object
641 642 643 |
# File 'lib/liquid_xlsx/renderer.rb', line 641 def enter_block(type, for_row, endfor_row) @blocks << { type: type, start: for_row, end: endfor_row } if for_row && endfor_row end |
#leave_block ⇒ Object
645 646 647 |
# File 'lib/liquid_xlsx/renderer.rb', line 645 def leave_block # Block already recorded in enter_block end |
#record_row(template_row_num, new_row_num) ⇒ Object
627 628 629 630 631 632 633 634 635 636 637 638 639 |
# File 'lib/liquid_xlsx/renderer.rb', line 627 def record_row(template_row_num, new_row_num) @row_map[template_row_num] ||= [] @row_map[template_row_num] << new_row_num # Also write to all active per-iteration row maps for later aggregation @loop_stack.each do |frame| iter = frame[:current_iteration] next unless iter iter[:row_map][template_row_num] ||= [] iter[:row_map][template_row_num] << new_row_num end end |
#start_iteration(index) ⇒ Object
653 654 655 |
# File 'lib/liquid_xlsx/renderer.rb', line 653 def start_iteration(index) @loop_stack.last[:current_iteration] = { row_map: {}, index: index } end |
#start_loop ⇒ Object
649 650 651 |
# File 'lib/liquid_xlsx/renderer.rb', line 649 def start_loop @loop_stack.push(iterations: [], current_iteration: nil) end |