Sheetshow.Memory (Sheetshow v0.1.0)

Copy Markdown View Source

A spreadsheet in a map: the backend that needs no network.

It carries out the same ops the Google backend does, so a plan can be run and read back in a test, and it refuses what Google refuses (writing to a sheet that is not there, adding one that is), so a plan that forgets its Sheetshow.Op.AddSheet fails here too.

iex> alias Sheetshow.{Memory, Op}
iex> plan = [
...>   Op.AddSheet.new("Costs"),
...>   Op.PutCells.new(Sheetshow.row(["Rent", 1000], sheet: "Costs"))
...> ]
iex> {:ok, memory} = Memory.run(plan, Memory.new())
iex> Memory.read!("Costs", memory) |> Sheetshow.to_rows()
[["Rent", 1000]]

A memory holds content, not a grid: it has no row or column count, so the space below the last cell is simply empty and a write can go anywhere. Each sheet is a plain map, %{cells: %{{row, col} => cell}, col_widths: %{}, row_heights: %{}}, and the cells in it carry their sheet, so what read/2 returns is what the layout functions in Sheetshow take.

The functions here are the interpreter itself. Sheetshow.Workbook.memory/1 puts a memory behind the same Sheetshow.run/2 and reads the other backends answer to, which is the way to use one in a test.

Summary

Functions

The column widths and row heights of a sheet, by index.

An empty spreadsheet, or one with the sheets named already there.

The cells inside a range, in reading order. Empty cells are not cells, so they are not there.

Same as read/2, raising on failure.

Carries out an op or a plan, in order, and gives back the spreadsheet it leaves behind. Mirrors Sheetshow.run/2, so a plan runs here or at Google with the same call shape.

Same as run/2, raising on failure.

The sheet titles, sorted. A memory keeps no sheet order of its own.

Types

sheet()

@type sheet() :: %{
  cells: %{
    required({non_neg_integer(), non_neg_integer()}) => Sheetshow.Cell.t()
  },
  col_widths: %{required(non_neg_integer()) => pos_integer()},
  row_heights: %{required(non_neg_integer()) => pos_integer()}
}

t()

@type t() :: %Sheetshow.Memory{sheets: %{required(String.t()) => sheet()}}

Functions

dimensions!(title, memory)

@spec dimensions!(String.t(), t()) :: %{col_widths: map(), row_heights: map()}

The column widths and row heights of a sheet, by index.

iex> alias Sheetshow.{Memory, Op}
iex> memory = Memory.run!(Op.SetDimensions.new("Costs", :cols, 0..1, 180), Memory.new(["Costs"]))
iex> Sheetshow.Memory.dimensions!("Costs", memory)
%{col_widths: %{0 => 180, 1 => 180}, row_heights: %{}}

new(titles \\ [])

@spec new([String.t()]) :: t()

An empty spreadsheet, or one with the sheets named already there.

iex> Sheetshow.Memory.new(["Costs", "log"]) |> Sheetshow.Memory.titles()
["Costs", "log"]

read(range, memory)

@spec read(Sheetshow.Range.t() | String.t(), t()) ::
  {:ok, [Sheetshow.Cell.t()]} | {:error, Sheetshow.Error.t()}

The cells inside a range, in reading order. Empty cells are not cells, so they are not there.

iex> alias Sheetshow.{Memory, Op}
iex> memory = Memory.run!(Op.PutCells.new(Sheetshow.row([1, 2]), "Costs"), Memory.new(["Costs"]))
iex> {:ok, cells} = Memory.read("Costs!A1:A1", memory)
iex> Enum.map(cells, & &1.value)
[1]

read!(range, memory)

@spec read!(Sheetshow.Range.t() | String.t(), t()) :: [Sheetshow.Cell.t()]

Same as read/2, raising on failure.

run(ops, memory)

@spec run(Sheetshow.Op.t() | [Sheetshow.Op.t()], t()) ::
  {:ok, t()} | {:error, Sheetshow.Error.t()}

Carries out an op or a plan, in order, and gives back the spreadsheet it leaves behind. Mirrors Sheetshow.run/2, so a plan runs here or at Google with the same call shape.

Nothing is half-done: the first op that fails ends the run and the memory you passed in is the one you still have.

iex> alias Sheetshow.{Memory, Op}
iex> {:error, error} = Memory.run(Op.PutCells.new(Sheetshow.row([1], sheet: "Costs")), Memory.new())
iex> error.reason
:unknown_sheet

run!(ops, memory)

@spec run!(Sheetshow.Op.t() | [Sheetshow.Op.t()], t()) :: t()

Same as run/2, raising on failure.

titles(memory)

@spec titles(t()) :: [String.t()]

The sheet titles, sorted. A memory keeps no sheet order of its own.

iex> Sheetshow.Memory.new() |> Sheetshow.Memory.titles()
[]