Packages
io_ansi_table
1.0.4
1.0.40
1.0.39
1.0.38
1.0.37
1.0.36
1.0.34
1.0.33
1.0.32
1.0.31
1.0.30
1.0.29
1.0.28
1.0.27
1.0.26
1.0.25
1.0.24
1.0.23
1.0.22
1.0.21
1.0.20
1.0.19
1.0.18
1.0.17
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.4.32
0.4.31
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Writes data to "stdio" in a table with borders and colors. Can choose a table style to change the look of the table.
Current section
Files
Jump to
Current section
Files
lib/io/ansi/table.ex
# ┌───────────────────────────────────────────────────────────┐
# │ Inspired by the book "Programming Elixir" by Dave Thomas. │
# └───────────────────────────────────────────────────────────┘
defmodule IO.ANSI.Table do
@moduledoc """
Writes data to stdout in a table with borders and colors.
Can choose a table style to change the look of the table.
##### Inspired by the book [Programming Elixir](https://pragprog.com/book/elixir16/programming-elixir-1-6) by Dave Thomas.
"""
use PersistConfig
alias __MODULE__.{DynSpecSup, Header, Spec, SpecServer}
@doc """
Starts a new table spec server process and supervises it.
Upon request (see `format/2`), the server will write data from
`maps` to stdout in a table formatted per `headers` and `options`.
The table columns are identified by `headers` (`map` keys).
We calculate the width of each column to fit the longest element
in that column, also considering the column heading.
However, the `:max_width` option prevails.
If the `:count` option is positive, we format the first _count_
`maps` in the list, once sorted. If negative, the last _count_ ones.
See `IO.ANSI.Table.Options` for a list of all options in this API.
## Parameters
- `headers` - keys identifying each column (list)
- `options` - up to `10` options (keyword)
## Options
- `:align_specs` - to align column elements (list)
- `:bell` - whether to ring the bell (boolean)
- `:count` - number of `maps` to format (integer)
- `:header_fixes` - to alter the `headers` (map)
- `:margins` - to position the table (keyword)
- `:max_width` - to cap column widths (non neg integer)
- `:sort_specs` - to sort the `maps` (list)
- `:sort_symbols` - to denote sort direction (keyword)
- `:spec_name` - to identify the table spec server (string)
- `:style` - table style (atom)
## Examples
iex> alias IO.ANSI.Table
iex> alias IO.ANSI.Table.SpecServer
iex> {:ok, pid} = Table.start([:name, :dob, :likes])
iex> pid == SpecServer.via("io_ansi_table") |> GenServer.whereis()
true
"""
@spec start([Header.t(), ...], Keyword.t()) :: Supervisor.on_start_child()
def start([_ | _] = headers, options \\ []) when is_list(options) do
spec = Spec.new(headers, options)
DynamicSupervisor.start_child(DynSpecSup, {SpecServer, spec})
end
@doc """
Stops a table spec server process normally. It won't be restarted.
The table spec server to stop is identified by `option` `:spec_name`.
See `IO.ANSI.Table.Options` for a list of all options in this API.
## Parameters
- `options` - up to `1` option (keyword)
## Options
- `:spec_name` - to identify the table spec server (string)
## Examples
iex> alias IO.ANSI.Table
iex> Table.start([:name, :dob, :likes])
iex> Table.stop
:ok
"""
@spec stop(Keyword.t()) :: :ok
def stop(options \\ []) when is_list(options) do
spec_name = Spec.spec_name(options)
SpecServer.via(spec_name) |> GenServer.stop(:shutdown)
end
@doc """
Sends a request to the table spec server identified by `option` `:spec_name`.
The server will write data from `maps` to stdout in a table formatted per its
spec and `options`.
Also supports:
- keywords
- structs implementing the `Access` behaviour
Does not support:
- _nested_ maps, keywords or structs
See `IO.ANSI.Table.Options` for a list of all options in this API.
## Parameters
- `maps` - _flat_ maps/keywords/structs (list)
- `options` - up to `6` options (keyword)
## Options
- `:async` - whether to write the table asynchronously (boolean)
- `:bell` - whether to ring the bell (boolean)
- `:count` - number of `maps` to format (integer)
- `:max_width` - to cap column widths (non neg integer)
- `:spec_name` - to identify the table spec server (string)
- `:style` - table style (atom)
## Examples
alias IO.ANSI.Table
people = [
%{name: "Mike", likes: "ski, arts", dob: "1992-04-15", bmi: 23.9},
%{name: "Mary", likes: "travels" , dob: "1992-04-15", bmi: 26.8},
%{name: "Ann" , likes: "reading" , dob: "1992-04-15", bmi: 24.7},
%{name: "Ray" , likes: "cycling" , dob: "1977-08-28", bmi: 19.1},
%{name: "Bill", likes: "karate" , dob: "1977-08-28", bmi: 18.1},
%{name: "Joe" , likes: "boxing" , dob: "1977-08-28", bmi: 20.8},
%{name: "Jill", likes: "cooking" , dob: "1976-09-28", bmi: 25.8}
]
Table.start([:name, :dob, :likes],
header_fixes: %{~r[dob]i => "Date of Birth"},
sort_specs: [asc: :dob],
align_specs: [center: :dob],
margins: [top: 2, bottom: 2, left: 2]
)
Table.format(people, style: :light)
Table.format(people, style: :light_alt)
Table.format(people, style: :light_mult)
Table.format(people, style: :cyan_alt)
Table.format(people, style: :cyan_mult)
## 
## 
## 
## 
## 
"""
@spec format([Access.container()], Keyword.t()) :: :ok
def format(maps, options \\ []) when is_list(maps) and is_list(options) do
spec_name = Spec.spec_name(options)
if options[:async],
do: GenServer.cast(SpecServer.via(spec_name), {:format, maps, options}),
else: GenServer.call(SpecServer.via(spec_name), {:format, maps, options})
end
@doc """
Sends a request to the table spec server identified by `option` `:spec_name`.
Returns the server's table spec.
See `IO.ANSI.Table.Options` for a list of all options in this API.
## Parameters
- `options` - up to `1` option (keyword)
## Options
- `:spec_name` - to identify the table spec server (string)
"""
def get(options \\ []) when is_list(options) do
spec_name = Spec.spec_name(options)
GenServer.call(SpecServer.via(spec_name), :get)
end
@doc """
Writes data from `maps` to stdout in a table formatted per `spec` and
`options`.
Also supports:
- keywords
- structs implementing the `Access` behaviour
Does not support:
- _nested_ maps, keywords or structs
See `IO.ANSI.Table.Options` for a list of all options in this API.
## Parameters
- `spec` - table spec (struct)
- `maps` - _flat_ maps/keywords/structs (list)
- `options` - up to `4` options (keyword)
## Options
- `:bell` - whether to ring the bell (boolean)
- `:count` - number of `maps` to format (integer)
- `:max_width` - to cap column widths (non neg integer)
- `:style` - table style (atom)
## Examples
alias IO.ANSI.Table
alias IO.ANSI.Table.Spec
people = [
%{name: "Mike", likes: "ski, arts", dob: "1992-04-15", bmi: 23.9},
%{name: "Mary", likes: "travels" , dob: "1992-04-15", bmi: 26.8},
%{name: "Ann" , likes: "reading" , dob: "1992-04-15", bmi: 24.7},
%{name: "Ray" , likes: "cycling" , dob: "1977-08-28", bmi: 19.1},
%{name: "Bill", likes: "karate" , dob: "1977-08-28", bmi: 18.1},
%{name: "Joe" , likes: "boxing" , dob: "1977-08-28", bmi: 20.8},
%{name: "Jill", likes: "cooking" , dob: "1976-09-28", bmi: 25.8}
]
spec =
Spec.new([:name, :dob, :likes],
header_fixes: %{~r[dob]i => "Date of Birth"},
sort_specs: [asc: :dob],
align_specs: [center: :dob],
margins: [top: 2, bottom: 2, left: 2]
)
|> Spec.extend()
Table.write(spec, people, style: :light)
Table.write(spec, people, style: :light_alt)
Table.write(spec, people, style: :light_mult)
Table.write(spec, people, style: :cyan_alt)
Table.write(spec, people, style: :cyan_mult)
"""
@spec write(Spec.t(), [Access.container()], Keyword.t()) :: :ok
defdelegate write(spec, maps, options \\ []), to: Spec, as: :write_table
end