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
@type bound() :: non_neg_integer() | nil
@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
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
@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"
@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
@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")
Same as from_a1/1, raising on failure.
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}
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'"