Current section

Files

Jump to
io_ansi_table lib io ansi table.ex
Raw

lib/io/ansi/table.ex

# ┌───────────────────────────────────────────────────────────┐
# │ Inspired by the book "Programming Elixir" by Dave Thomas. │
# └───────────────────────────────────────────────────────────┘
defmodule IO.ANSI.Table do
@moduledoc """
Prints data to STDOUT in a table with borders and colors.
Can choose a table style to change the look of the table.
"""
use PersistConfig
alias IO.ANSI.Table.{Server, Style}
@async Application.get_env(@app, :async)
@doc """
Prints data from `maps` to STDOUT in a table tailored by `options`.
All options can be configured and/or passed as a keyword argument.
Each option of the keyword will override its configured counterpart.
You should however configure all options except possibly
`bell`, `count` and `style`.
The columns are identified by the `:headers` option (`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 _n_
`maps` in the list, once sorted. If negative, the last _n_ ones.
See `IO.ANSI.Table.Options` for examples of all options.
## Parameters
- `maps` - list of maps/keywords/structs (list)
- `options` - up to 10 options all configurable (keyword)
## Options
- `:align_specs` - to align column elements (list)
- `:bell` - ring the bell? (boolean)
- `:count` - number of `maps` to format (integer)
- `:headers` - to identify each column (list)
- `: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)
- `:style` - table style (atom)
## Table styles
#{Style.texts(" - `&style`&filler - &note\n")}
## Examples
alias IO.ANSI.Table
alias IO.ANSI.Table.Server
header_fixes = %{~r[dob]i => "Date of Birth"}
Application.put_env(:io_ansi_table, :headers, [:name, :dob, :likes])
Application.put_env(:io_ansi_table, :header_fixes, header_fixes)
Application.put_env(:io_ansi_table, :sort_specs, [asc: :dob])
Application.put_env(:io_ansi_table, :align_specs, [center: :dob])
Application.put_env(:io_ansi_table, :margins, [top: 2, bottom: 2])
people = [
%{name: "Mike", likes: "ski, arts", dob: "1992-04-15"},
%{name: "Mary", likes: "reading" , dob: "1985-07-11"},
%{name: "Ray" , likes: "cycling" , dob: "1977-08-28"}
]
GenServer.stop(Server, :shutdown)
Table.format(people, style: :light)
Table.format(people, style: :medium)
Table.format(people, style: :dark)
## ![print_table_people](images/print_table_people.png)
"""
@spec format([Access.container()], Keyword.t()) :: :ok
if @async do
def format(maps, options \\ []) when is_list(options) do
GenServer.cast(Server, {maps, options})
end
else
def format(maps, options \\ []) when is_list(options) do
GenServer.call(Server, {maps, options})
end
end
end