Packages
io_ansi_table
0.1.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/formatter.ex
# Based on the book "Programming Elixir" by Dave Thomas.
defmodule IO.ANSI.Table.Formatter do
@moduledoc """
Prints a table applying a table style. Each row is
a list of values identified by successive headers.
"""
alias IO.ANSI.Table.Config
alias IO.ANSI.Table.Formatter.Helper
alias IO.ANSI.Table.Style
@doc """
Takes a list of key-value `collections`, the (maximum) number of
`collections` to format, whether to ring the `bell`, a table `style` and,
as `options`, a list of `headers` (keys) and a list of `key headers` to
sort the `collections` on.
Prints a table to STDOUT of the values in each selected `collection`.
The columns are identified by successive `headers` in order.
We calculate the width of each column to fit the longest element
in that column, also considering the `header` itself.
If the number of `collections` given is positive, we format
the `n` first `collections` in the list. If negative, the last `n` ones.
## Parameters
- `collections` - list of collections (maps or keywords)
- `count` - number of collections to format (integer)
- `bell` - ring the bell? (boolean)
- `style` - table style (atom)
- `options` - headers and key headers (keyword)
## Table styles
#{Style.texts " - `&style`&filler - ¬e\n"}
## Options
- `:headers` - defaults to config value `:headers`
- `:key_headers` - defaults to config value `:key_headers`
## Examples
alias IO.ANSI.Table.Formatter
people = [
%{name: "Mike", likes: "ski, arts", date_of_birth: "1992-04-15"},
%{name: "Mary", likes: "reading" , date_of_birth: "1985-07-11"},
%{name: "Ray" , likes: "cycling" , date_of_birth: "1977-08-28"}
]
Formatter.print_table(
people, 3, true, :dark,
headers: [:name, :date_of_birth, :likes],
key_headers: [:date_of_birth]
)
## 
iex> alias IO.ANSI.Table.Formatter
iex> alias ExUnit.CaptureIO
iex> people = [
...> %{name: "Mike", likes: "ski, arts", date_of_birth: "1992-04-15"},
...> %{name: "Mary", likes: "reading" , date_of_birth: "1985-07-11"},
...> %{name: "Ray" , likes: "cycling" , date_of_birth: "1977-08-28"}
...> ]
iex> CaptureIO.capture_io fn ->
...> Formatter.print_table(
...> people, 3, false, :dashed,
...> headers: [:name, :date_of_birth, :likes],
...> key_headers: [:date_of_birth]
...> )
...> end
"\\n" <> \"""
+------+---------------+-----------+
| Name | Date Of Birth | Likes |
+------+---------------+-----------+
| Ray | 1977-08-28 | cycling |
| Mary | 1985-07-11 | reading |
| Mike | 1992-04-15 | ski, arts |
+------+---------------+-----------+
\""" <> "\\n"
"""
@spec print_table([map | Keyword.t], integer, boolean, atom, Keyword.t)
:: :ok
def print_table(collections, count, bell, style, options \\ []) do
headers = Keyword.get(options, :headers, Config.headers)
key_headers = Keyword.get(options, :key_headers, Config.key_headers)
collections =
collections
|> Stream.map(&Map.take &1, headers) # optional
|> Enum.sort_by(&key_for &1, key_headers)
|> Enum.take(count)
widths =
[Map.new(headers, &{&1, titlecase &1}) | collections]
|> columns(headers)
|> widths # => max widths of column values or headers
rows = rows(collections, headers)
Helper.print_table(rows, headers, key_headers, widths, style, bell)
end
@doc """
Takes a key-value `collection` and a list of `keys`.
Returns a sort key for the `collection`.
## Examples
iex> alias IO.ANSI.Table.Formatter
iex> collection = [one: '1', two: "2", three: 3.0, four: 4]
iex> keys = [:three, :one, :four]
iex> Formatter.key_for(collection, keys)
"3.014"
"""
@spec key_for([map | Keyword.t], [any]) :: String.t
def key_for(collection, keys) do
Enum.map_join keys, &collection[&1]
end
@doc """
Takes a list of key-value `collections` and a list of `keys`.
Returns a list of columns, each column being a list of string values
selected from each `collection` on a given `key` and repeatedly on
successive `keys` in order.
## Examples
iex> alias IO.ANSI.Table.Formatter
iex> list = [
...> %{"a" => "1", "b" => "2", "c" => "3"},
...> %{"a" => "4", "b" => "5", "c" => "6"}
...> ]
iex> Formatter.columns(list, ["c", "a"])
[["3", "6"], ["1", "4"]]
iex> alias IO.ANSI.Table.Formatter
iex> list = [
...> %{:one => "1", '2' => 2.0, 3 => :three},
...> %{:one => '4', '2' => "5", 3 => 000006}
...> ]
iex> Formatter.columns(list, [3, :one, '2'])
[["three", "6"], ["1", "4"], ["2.0", "5"]]
"""
@spec columns([map | Keyword.t], [any]) :: [[String.t]]
def columns(collections, keys) do
for key <- keys do
for collection <- collections, do: to_string collection[key]
end
end
@doc """
Takes a list of key-value `collections` and a list of `keys`.
Returns a list of rows, each row being a list of string values
orderly selected on successive `keys` from a given `collection` and
repeatedly for each `collection` in turn.
## Examples
iex> alias IO.ANSI.Table.Formatter
iex> list = [
...> %{"a" => "1", "b" => "2", "c" => "3"},
...> %{"a" => "4", "b" => "5", "c" => "6"}
...> ]
iex> Formatter.rows(list, ["c", "a"])
[["3", "1"], ["6", "4"]]
iex> alias IO.ANSI.Table.Formatter
iex> list = [
...> %{:one => "1", '2' => 2.0, 3 => :three},
...> %{:one => '4', '2' => "5", 3 => 000006}
...> ]
iex> Formatter.rows(list, [3, :one, '2'])
[["three", "1", "2.0"], ["6", "4", "5"]]
"""
@spec rows([map | Keyword.t], [any]) :: [[String.t]]
def rows(collections, keys) do
for collection <- collections do
for key <- keys, do: to_string collection[key]
end
end
@doc """
Given a list of `columns` (string sublists), returns a list containing
the maximum width of each `column`.
## Examples
iex> alias IO.ANSI.Table.Formatter
iex> data = [["cat", "wombat", "elk"], ["mongoose", "ant", "gnu"]]
iex> Formatter.widths(data)
[6, 8]
iex> alias IO.ANSI.Table.Formatter
iex> data = [[":cat", "{1, 2}", "007"], ["mongoose", ":ant", "3.1416"]]
iex> Formatter.widths(data)
[6, 8]
"""
@spec widths([[String.t]]) :: [non_neg_integer]
def widths(columns) do
for column <- columns, do: column |> Enum.map(&String.length/1) |> Enum.max
end
@doc """
Capitalizes every word of a `title` (converted to string if applicable).
Any underscore is considered a space and consecutive
whitespace characters are treated as a single occurrence.
Leading and trailing whitespace characters are removed.
## Examples
iex> alias IO.ANSI.Table.Formatter
iex> Formatter.titlecase(" son of a gun ")
"Son Of A Gun"
iex> alias IO.ANSI.Table.Formatter
iex> Formatter.titlecase("_date___of_birth_")
"Date Of Birth"
iex> alias IO.ANSI.Table.Formatter
iex> Formatter.titlecase(:" _aN_ _oDD cASe_ ")
"An Odd Case"
"""
@spec titlecase(any) :: String.t
def titlecase(title) do
title
|> to_string
|> String.split(~r/(_|\s)+/, trim: true)
|> Enum.map(&String.capitalize/1)
|> Enum.join("\s")
end
end