ETS-backed editable representation of a worksheet. The parsed SimpleForm tree is converted on first access and materialised back to a tree at serialise time.
The cell grid lives in an ETS :set table for O(1) lookup and insert.
Surrounding <worksheet> content (<sheetViews>, <cols>,
<mergeCells>, <pageMargins>, …) passes through pre_sheet_data /
post_sheet_data unchanged so fidelity is preserved.
Sharing semantics
ETS tables are mutable. Two %ExVEx.Workbook{} references that share
the same cached sheet via Workbook.put_sheet_tree/3 also share the
same underlying ETS table; a mutation on one is visible from the other.
In practice this shows up between a workbook and its put_cell
descendants after the sheet has been parsed at least once. A pristine
workbook from ExVEx.open/1 that has not yet touched a sheet is
insulated because it will lazily create a fresh table on first access.
If you need an independent snapshot, ExVEx.save/2 it and open/1
that, or call ExVEx.close/1 and re-open.
Memory lifecycle
ETS tables persist until the owning process exits. In short-lived
processes (scripts, one-shot jobs, tests) this is fine. In long-running
servers that open many workbooks, call ExVEx.close/1 when done with a
workbook to reclaim the tables eagerly.
Summary
Functions
Returns the resolved %ExVEx.OOXML.Worksheet.Cell{} record for the given
coordinate, or :error if the cell is absent.
Types
Functions
@spec cell_record_at(t(), ExVEx.Utils.Coordinate.t()) :: {:ok, ExVEx.OOXML.Worksheet.Cell.t()} | :error
Returns the resolved %ExVEx.OOXML.Worksheet.Cell{} record for the given
coordinate, or :error if the cell is absent.
@spec cells_map(t()) :: %{ required(ExVEx.Utils.Coordinate.t()) => ExVEx.OOXML.Worksheet.Cell.t() }
@spec get_cell(t(), ExVEx.Utils.Coordinate.t()) :: {:ok, cell_element()} | :error
@spec merge(t(), ExVEx.Utils.Range.t(), boolean()) :: t()
@spec merged_ranges(t()) :: [ExVEx.Utils.Range.t()]
@spec put_cell(t(), ExVEx.Utils.Coordinate.t(), ExVEx.cell_value()) :: t()
@spec unmerge(t(), ExVEx.Utils.Range.t()) :: t()