Class: LiquidXlsx::FormulaTranslator
- Inherits:
-
Object
- Object
- LiquidXlsx::FormulaTranslator
- Defined in:
- lib/liquid_xlsx/formula_translator.rb
Overview
Translates Excel formulas when rows are copied or shifted, and widens ranges that reference loop bodies after loops have expanded.
Loop expansions are registered in RENDER coordinates: for each template row of a loop body we know the list of rendered row numbers it produced. A range like SUM(E3:E3) whose rows point into a loop body is rewritten to span from the first to the last rendered body row; all other relative references are shifted by the formula's own row delta.
Constant Summary collapse
- CELL_REF =
Pattern for cell references including sheet-qualified ones. Guards: a reference must not be preceded or followed by an identifier character, so tails of function names (LOG10, ATAN2) and defined names are not mistaken for cell references.
/ (?<![A-Za-z0-9_$]) (?<sheet>(?:'[^']*'|[A-Za-z0-9_.]+)!)? # optional sheet name (?<col_abs>\$)?(?<col>[A-Z]{1,3}) (?<row_abs>\$)?(?<row>\d+) (?![A-Za-z0-9_(]) /x
Instance Method Summary collapse
-
#copied_row?(template_row) ⇒ Boolean
Whether a template row lies inside a registered loop block (i.e. the row was copied per iteration rather than moved).
-
#initialize ⇒ FormulaTranslator
constructor
A new instance of FormulaTranslator.
-
#register_expansion(rows:, block_first:, block_last:, path: []) ⇒ Object
Register a loop expansion.
-
#translate(formula, row_delta, col_delta = 0, template_row: nil, copied: true, formula_path: []) ⇒ String
Translate a formula.
Constructor Details
#initialize ⇒ FormulaTranslator
Returns a new instance of FormulaTranslator.
26 27 28 29 |
# File 'lib/liquid_xlsx/formula_translator.rb', line 26 def initialize # Each: { rows: {template_row => [rendered_row, ...]}, block_first:, block_last:, path: } @expansions = [] end |
Instance Method Details
#copied_row?(template_row) ⇒ Boolean
Whether a template row lies inside a registered loop block (i.e. the row was copied per iteration rather than moved).
43 44 45 46 47 |
# File 'lib/liquid_xlsx/formula_translator.rb', line 43 def copied_row?(template_row) return false unless template_row @expansions.any? { |e| template_row.between?(e[:block_first], e[:block_last]) } end |
#register_expansion(rows:, block_first:, block_last:, path: []) ⇒ Object
Register a loop expansion.
36 37 38 39 |
# File 'lib/liquid_xlsx/formula_translator.rb', line 36 def register_expansion(rows:, block_first:, block_last:, path: []) @expansions << { rows: rows, block_first: block_first, block_last: block_last, path: path.dup.freeze } end |
#translate(formula, row_delta, col_delta = 0, template_row: nil, copied: true, formula_path: []) ⇒ String
Translate a formula.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/liquid_xlsx/formula_translator.rb', line 59 def translate(formula, row_delta, col_delta = 0, template_row: nil, copied: true, formula_path: []) refs = scan_refs(formula) return formula if refs.empty? (formula, refs, template_row, formula_path) out = +"" last_pos = 0 refs.each do |ref| out << formula[last_pos...ref[:pos]] out << rebuild_ref(ref, row_delta, col_delta, copied) last_pos = ref[:end_pos] end out << formula[last_pos..] out end |