defmodule IO.ANSI.Table.Spec.Rows do
@moduledoc """
Derives the rows of a table.
Also transposes rows into columns.
"""
alias IO.ANSI.Table.{Column, Header, Row, Spec}
# Reset log files at compile time to log debug messages.
# May need `mix compile --force` and `mix test --force`.
{:ok, _apps} = Application.ensure_all_started(:log_reset)
@doc """
Derives the rows of a table given `spec` and `maps`.
## Examples
iex> alias IO.ANSI.Table.Spec.Rows
iex> alias IO.ANSI.Table.Spec
iex> spec = Spec.new([:c4, :c1, :c2])
iex> maps = [%{c1: 11, c2: 12, c4: 14}, %{c1: 21, c2: 22, c4: 24}]
iex> %Spec{rows: rows} = Rows.derive_and_put(spec, maps)
iex> rows
[["14", "11", "12"], ["24", "21", "22"]]
"""
@spec derive_and_put(Spec.t(), [Access.container()]) :: Spec.t()
def derive_and_put(
%Spec{
count: count,
headers: headers,
sort_specs: specs
} = spec,
maps
) do
require MapSorter
rows = MapSorter.sort(maps, specs) |> Enum.take(count) |> select(headers)
put_in(spec.rows, rows)
end
@doc """
Transposes `rows` into columns.
## Examples
iex> alias IO.ANSI.Table.Spec.Rows
iex> rows = [
...> ["1", "2", "3"],
...> ["4", "5", "6"]
...> ]
iex> Rows.transpose(rows)
[["1", "4"], ["2", "5"], ["3", "6"]]
"""
@spec transpose([Row.t()]) :: [Column.t()]
def transpose(rows), do: Enum.zip(rows) |> Enum.map(&Tuple.to_list/1)
## Private functions
# @doc """
# Gets the values for `headers` in `maps` and returns a list of rows.
# ## Examples
# iex> alias IO.ANSI.Table.Spec.Rows
# iex> maps = [
# ...> %{a: 1, b: 2, c: 3},
# ...> %{a: 4, b: 5, c: 6}
# ...> ]
# iex> Rows.select(maps, [:c, :a])
# [["3", "1"], ["6", "4"]]
# iex> alias IO.ANSI.Table.Spec.Rows
# iex> maps = [
# ...> %{:one => "1", '2' => 2.0, "3" => :three},
# ...> %{:one => '4', '2' => "5", "3" => 000006}
# ...> ]
# iex> Rows.select(maps, ["3", :one, '2'])
# [["three", "1", "2.0"], ["6", "4", "5"]]
# """
@spec select([Access.container()], [Header.t()]) :: [Row.t()]
defp select(maps, headers) do
for map <- maps do
for header <- headers, do: map[header] |> to_string()
end
end
end