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}
@spec derive(Spec.t(), [Access.container()]) :: Spec.t()
def derive(%Spec{sort_specs: sort_specs, headers: headers} = spec, maps) do
import MapSorter, only: [sort: 2]
rows = sort(maps, sort_specs) |> Enum.take(spec.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