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.
618 619 620 621 622 623 624 625 626 627 628 629 630 |
# File 'lib/liquid_xlsx/renderer.rb', line 618 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.
616 617 618 |
# File 'lib/liquid_xlsx/renderer.rb', line 616 def formula_translator @formula_translator end |
Instance Method Details
#build_merge_ranges ⇒ Object
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 736 737 738 739 740 |
# File 'lib/liquid_xlsx/renderer.rb', line 707 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.
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
# File 'lib/liquid_xlsx/renderer.rb', line 689 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.
683 684 685 |
# File 'lib/liquid_xlsx/renderer.rb', line 683 def current_path @loop_stack.filter_map { |f| f[:current_iteration]&.dig(:index) } end |
#end_iteration ⇒ Object
662 663 664 665 |
# File 'lib/liquid_xlsx/renderer.rb', line 662 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.
669 670 671 672 673 674 675 676 677 678 679 |
# File 'lib/liquid_xlsx/renderer.rb', line 669 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
646 647 648 |
# File 'lib/liquid_xlsx/renderer.rb', line 646 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
650 651 652 |
# File 'lib/liquid_xlsx/renderer.rb', line 650 def leave_block # Block already recorded in enter_block end |
#record_row(template_row_num, new_row_num) ⇒ Object
632 633 634 635 636 637 638 639 640 641 642 643 644 |
# File 'lib/liquid_xlsx/renderer.rb', line 632 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
658 659 660 |
# File 'lib/liquid_xlsx/renderer.rb', line 658 def start_iteration(index) @loop_stack.last[:current_iteration] = { row_map: {}, index: index } end |
#start_loop ⇒ Object
654 655 656 |
# File 'lib/liquid_xlsx/renderer.rb', line 654 def start_loop @loop_stack.push(iterations: [], current_iteration: nil) end |