Sheetshow.Range (Sheetshow v0.1.0)

Copy Markdown View Source

A rectangle of cells on one sheet: Costs!A2:C10, a whole column, a whole sheet.

Bounds are 0-indexed and inclusive. An end_row or end_col of nil is unbounded, which is how Sheets spells "to the end": A:A is %Range{start_col: 0, end_col: 0, end_row: nil} and A2:F is rows from 1 with columns 0 to 5. The struct literal is the constructor for those; new/3 takes Elixir ranges for the bounded case.

iex> Sheetshow.Range.new("Costs", 1..9, 0..2) |> Sheetshow.Range.to_a1()
"Costs!A2:C10"
iex> Sheetshow.Range.to_a1(%Sheetshow.Range{sheet: "log", start_row: 10, end_col: 5})
"log!A11:F"

Unquoted names that look like references (Tab1) are read as references, exactly as Sheets does; quote them ('Tab1') to mean the sheet.

Summary

Functions

Whether both ends are known.

The smallest range holding every coordinate or cell given. They must share a sheet; the list must not be empty.

Whether the coordinate lies inside the range. The sheets must match, and a nil sheet matches only nil.

Parses an A1 range. A bare quoted or non-reference-like name is the whole sheet; reversed corners are normalised.

Same as from_a1/1, raising on failure.

A bounded range from Elixir ranges of rows and columns.

Prints as A1. A single cell prints as one reference; a whole sheet as its name, which it must have.

Types

bound()

@type bound() :: non_neg_integer() | nil

t()

@type t() :: %Sheetshow.Range{
  end_col: bound(),
  end_row: bound(),
  sheet: String.t() | nil,
  start_col: non_neg_integer(),
  start_row: non_neg_integer()
}

Functions

bounded?(range)

@spec bounded?(t()) :: boolean()

Whether both ends are known.

iex> Sheetshow.Range.bounded?(Sheetshow.Range.from_a1!("A1:B2"))
true
iex> Sheetshow.Range.bounded?(Sheetshow.Range.from_a1!("A:B"))
false

bounding(items)

@spec bounding([Sheetshow.Coord.t() | %{coord: Sheetshow.Coord.t()}]) :: t()

The smallest range holding every coordinate or cell given. They must share a sheet; the list must not be empty.

iex> coords = [Sheetshow.Coord.new(4, 1, "Costs"), Sheetshow.Coord.new(0, 3, "Costs")]
iex> Sheetshow.Range.bounding(coords) |> Sheetshow.Range.to_a1()
"Costs!B1:D5"

contains?(range, coord)

@spec contains?(t(), Sheetshow.Coord.t()) :: boolean()

Whether the coordinate lies inside the range. The sheets must match, and a nil sheet matches only nil.

iex> range = Sheetshow.Range.from_a1!("Costs!A2:C")
iex> Sheetshow.Range.contains?(range, Sheetshow.Coord.new(100, 2, "Costs"))
true
iex> Sheetshow.Range.contains?(range, Sheetshow.Coord.new(0, 0, "Costs"))
false

from_a1(a1)

@spec from_a1(String.t()) :: {:ok, t()} | {:error, Sheetshow.Error.t()}

Parses an A1 range. A bare quoted or non-reference-like name is the whole sheet; reversed corners are normalised.

iex> Sheetshow.Range.from_a1("Costs!C3:A1")
{:ok, %Sheetshow.Range{sheet: "Costs", start_row: 0, start_col: 0, end_row: 2, end_col: 2}}
iex> Sheetshow.Range.from_a1("B:B")
{:ok, %Sheetshow.Range{sheet: nil, start_row: 0, start_col: 1, end_row: nil, end_col: 1}}
iex> Sheetshow.Range.from_a1("2:3")
{:ok, %Sheetshow.Range{sheet: nil, start_row: 1, start_col: 0, end_row: 2, end_col: nil}}
iex> Sheetshow.Range.from_a1("Costs")
{:ok, %Sheetshow.Range{sheet: "Costs", start_row: 0, start_col: 0, end_row: nil, end_col: nil}}
iex> {:error, %Sheetshow.Error{reason: :invalid_a1}} = Sheetshow.Range.from_a1("A0")

from_a1!(a1)

@spec from_a1!(String.t()) :: t()

Same as from_a1/1, raising on failure.

new(sheet, arg1, arg2)

@spec new(String.t() | nil, Range.t(), Range.t()) :: t()

A bounded range from Elixir ranges of rows and columns.

iex> Sheetshow.Range.new(nil, 0..0, 0..3)
%Sheetshow.Range{sheet: nil, start_row: 0, start_col: 0, end_row: 0, end_col: 3}

to_a1(range)

@spec to_a1(t()) :: String.t()

Prints as A1. A single cell prints as one reference; a whole sheet as its name, which it must have.

iex> Sheetshow.Range.to_a1(%Sheetshow.Range{start_row: 3, start_col: 1, end_row: 3, end_col: 1})
"B4"
iex> Sheetshow.Range.to_a1(%Sheetshow.Range{sheet: "Costs", end_col: 2})
"Costs!A:C"
iex> Sheetshow.Range.to_a1(%Sheetshow.Range{sheet: "Q1 costs"})
"'Q1 costs'"