From d2d00beaea3aab3859d854d0e4d2ed37fd8e89c0 Mon Sep 17 00:00:00 2001 From: Aaron Seigo Date: Mon, 7 Jun 2021 16:23:33 +0200 Subject: [PATCH] update the vendorized TableRex and namespace it with Licensir besides updating the TableRex code, this allows Licensir to be used with other libraries that use TableRex as a dependency --- lib/mix/tasks/licenses.ex | 2 +- lib/table_rex.ex | 6 ++-- lib/table_rex/cell.ex | 48 +++++++++++++++++++++---- lib/table_rex/column.ex | 2 +- lib/table_rex/renderer.ex | 4 +-- lib/table_rex/renderer/text.ex | 56 +++++++++++++++++------------ lib/table_rex/renderer/text/meta.ex | 10 +++--- lib/table_rex/table.ex | 22 ++++++------ 8 files changed, 97 insertions(+), 53 deletions(-) diff --git a/lib/mix/tasks/licenses.ex b/lib/mix/tasks/licenses.ex index 2ff4ae4..f35befc 100644 --- a/lib/mix/tasks/licenses.ex +++ b/lib/mix/tasks/licenses.ex @@ -40,7 +40,7 @@ defmodule Mix.Tasks.Licenses do _ = Mix.Shell.IO.info([:yellow, "Notice: This is not a legal advice. Use the information below at your own risk."]) rows - |> TableRex.quick_render!(["Package", "Version", "License"]) + |> Licensir.TableRex.quick_render!(["Package", "Version", "License"]) |> IO.puts() end diff --git a/lib/table_rex.ex b/lib/table_rex.ex index 9b98178..8675d0c 100755 --- a/lib/table_rex.ex +++ b/lib/table_rex.ex @@ -1,9 +1,9 @@ -defmodule TableRex do +defmodule Licensir.TableRex do @moduledoc """ TableRex generates configurable, text-based tables for display """ - alias TableRex.Renderer - alias TableRex.Table + alias Licensir.TableRex.Renderer + alias Licensir.TableRex.Table @doc """ A shortcut function to render with a one-liner. diff --git a/lib/table_rex/cell.ex b/lib/table_rex/cell.ex index 59f2d7f..a028b6b 100755 --- a/lib/table_rex/cell.ex +++ b/lib/table_rex/cell.ex @@ -1,4 +1,4 @@ -defmodule TableRex.Cell do +defmodule Licensir.TableRex.Cell do @moduledoc """ Defines a struct that represents a single table cell, and helper functions. @@ -14,6 +14,9 @@ defmodule TableRex.Cell do * `rendered_value`: The stringified value for rendering + * `wrapped_lines`: A list of 1 or more string values representing + the line(s) within the cell to be rendered + * `align`: * `:left`: left align text in the cell. * `:center`: center text in the cell. @@ -26,9 +29,9 @@ defmodule TableRex.Cell do enable that Cell to work well with the rest of TableRex. It should be set to a piece of data that can be rendered to string. """ - alias TableRex.Cell + alias Licensir.TableRex.Cell - defstruct raw_value: nil, rendered_value: "", align: nil, color: nil + defstruct raw_value: nil, rendered_value: "", align: nil, color: nil, wrapped_lines: [""] @type t :: %__MODULE__{} @@ -51,17 +54,48 @@ defmodule TableRex.Cell do hindered. """ @spec to_cell(Cell.t()) :: Cell.t() - def to_cell(%Cell{rendered_value: rendered_value} = cell) when rendered_value != "", do: cell + def to_cell(%Cell{rendered_value: rendered_value} = cell) + when is_binary(rendered_value) and rendered_value != "" do + %Cell{cell | wrapped_lines: wrapped_lines(rendered_value)} + end def to_cell(%Cell{raw_value: raw_value} = cell) do - %Cell{cell | rendered_value: to_string(raw_value)} + rendered_value = to_string(raw_value) + %Cell{cell | rendered_value: rendered_value, wrapped_lines: wrapped_lines(rendered_value)} end @spec to_cell(any, list) :: Cell.t() - def to_cell(value, opts \\ []) do + def to_cell(value, opts \\ []) + + def to_cell(list, opts) when is_list(list) do + if List.improper?(list) do + list + |> to_string() + |> to_cell(opts) + else + list + |> Enum.join("\n") + |> to_cell(opts) + end + end + + def to_cell(value, opts) do opts = Enum.into(opts, %{}) - %Cell{rendered_value: to_string(value), raw_value: value} + rendered_value = to_string(value) + + %Cell{ + raw_value: value, + rendered_value: rendered_value, + wrapped_lines: wrapped_lines(rendered_value) + } |> Map.merge(opts) end + + @spec height(Cell.t()) :: integer + def height(%Cell{wrapped_lines: lines}), do: length(lines) + + defp wrapped_lines(value) when is_binary(value) do + String.split(value, "\n") + end end diff --git a/lib/table_rex/column.ex b/lib/table_rex/column.ex index e97284c..fcb6885 100755 --- a/lib/table_rex/column.ex +++ b/lib/table_rex/column.ex @@ -1,4 +1,4 @@ -defmodule TableRex.Column do +defmodule Licensir.TableRex.Column do @moduledoc """ Defines a struct that represents a column's metadata diff --git a/lib/table_rex/renderer.ex b/lib/table_rex/renderer.ex index 38fcb82..8dfedd8 100755 --- a/lib/table_rex/renderer.ex +++ b/lib/table_rex/renderer.ex @@ -1,4 +1,4 @@ -defmodule TableRex.Renderer do +defmodule Licensir.TableRex.Renderer do @moduledoc """ An Elixir behaviour that defines the API Renderers should conform to, allowing for display output in a variety of formats. @@ -11,5 +11,5 @@ defmodule TableRex.Renderer do @callback default_options() :: map @doc "Renders a passed %TableRex.Table{} struct into a string." - @callback render(table :: %TableRex.Table{}, opts :: list) :: render_return + @callback render(table :: %Licensir.TableRex.Table{}, opts :: list) :: render_return end diff --git a/lib/table_rex/renderer/text.ex b/lib/table_rex/renderer/text.ex index f8427b6..bec8f87 100755 --- a/lib/table_rex/renderer/text.ex +++ b/lib/table_rex/renderer/text.ex @@ -1,12 +1,12 @@ -defmodule TableRex.Renderer.Text do +defmodule Licensir.TableRex.Renderer.Text do @moduledoc """ Renderer module which handles outputting ASCII-style tables for display. """ - alias TableRex.Cell - alias TableRex.Table - alias TableRex.Renderer.Text.Meta + alias Licensir.TableRex.Cell + alias Licensir.TableRex.Table + alias Licensir.TableRex.Renderer.Text.Meta - @behaviour TableRex.Renderer + @behaviour Licensir.TableRex.Renderer # horizontal_styles: [:all, :header, :frame:, :off] # vertical_styles: [:all, :frame, :off] @@ -174,14 +174,7 @@ defmodule TableRex.Renderer.Text do defp render_header({%Table{header_row: header_row} = table, meta, opts, rendered}) do separator = if meta.render_column_separators?, do: opts[:vertical_symbol], else: " " - line = render_cell_row(table, meta, header_row, separator) - - line = - if meta.render_vertical_frame? do - line |> frame_with(opts[:vertical_symbol]) - else - line - end + line = render_cell_row(table, meta, header_row, separator, opts[:vertical_symbol]) {table, meta, opts, [line | rendered]} end @@ -219,15 +212,10 @@ defmodule TableRex.Renderer.Text do end defp render_rows({%Table{rows: rows} = table, meta, opts, rendered}) do - separator = if meta.render_column_separators?, do: opts[:vertical_symbol], else: " " - lines = Enum.map(rows, &render_cell_row(table, meta, &1, separator)) + cell_separator = if meta.render_column_separators?, do: opts[:vertical_symbol], else: " " lines = - if meta.render_vertical_frame? do - Enum.map(lines, &frame_with(&1, opts[:vertical_symbol])) - else - lines - end + Enum.map(rows, &render_cell_row(table, meta, &1, cell_separator, opts[:vertical_symbol])) lines = if meta.render_row_separators? do @@ -248,6 +236,12 @@ defmodule TableRex.Renderer.Text do {table, meta, opts, rendered} end + defp vertically_framed(lines, %{render_vertical_frame?: true}, symbol) do + Enum.map(lines, &frame_with(&1, symbol)) + end + + defp vertically_framed(lines, _, _), do: lines + defp render_bottom_frame({table, %Meta{render_horizontal_frame?: false} = meta, opts, rendered}) do {table, meta, opts, rendered} end @@ -271,8 +265,24 @@ defmodule TableRex.Renderer.Text do |> Enum.join() end - defp render_cell_row(%Table{} = table, %Meta{} = meta, row, separator) do + defp render_cell_row(%Table{} = table, %Meta{} = meta, row, cell_separator, frame_symbol) do + row_height = + row + |> Enum.map(&Cell.height/1) + |> Enum.max() + + 1..row_height + |> Enum.map(&render_cell_row_line(table, meta, row, cell_separator, &1)) + |> vertically_framed(meta, frame_symbol) + |> Enum.join("\n") + end + + defp render_cell_row_line(%Table{} = table, %Meta{} = meta, row, separator, line_index) do row + |> Enum.map(fn %Cell{wrapped_lines: lines} = cell -> + line_value = Enum.at(lines, line_index - 1) || "" + %Cell{cell | rendered_value: line_value} + end) |> Enum.with_index() |> Enum.map(&render_cell(table, meta, &1)) |> Enum.intersperse(separator) @@ -341,7 +351,7 @@ defmodule TableRex.Renderer.Text do |> Enum.with_index() |> Enum.reduce({%{}, %{}}, &reduce_row_maximums(table, &1, &2)) - num_columns = Map.size(col_widths) + num_columns = map_size(col_widths) # Infer padding on left and right of title title_padding = @@ -392,7 +402,7 @@ defmodule TableRex.Renderer.Text do |> String.split("\n") height = Enum.count(lines) - width = Enum.max(lines) |> String.length() + width = lines |> Enum.map(&String.length/1) |> Enum.max() {width + padding * 2, height} end diff --git a/lib/table_rex/renderer/text/meta.ex b/lib/table_rex/renderer/text/meta.ex index 4fe9299..8c23a31 100755 --- a/lib/table_rex/renderer/text/meta.ex +++ b/lib/table_rex/renderer/text/meta.ex @@ -1,9 +1,9 @@ -defmodule TableRex.Renderer.Text.Meta do +defmodule Licensir.TableRex.Renderer.Text.Meta do @moduledoc """ The data structure for the `TableRex.Renderer.Text` rendering module, it holds results of style & dimension calculations to be passed down the render pipeline. """ - alias TableRex.Renderer.Text.Meta + alias Licensir.TableRex.Renderer.Text.Meta defstruct col_widths: %{}, row_heights: %{}, @@ -15,7 +15,7 @@ defmodule TableRex.Renderer.Text.Meta do render_row_separators?: false @doc """ - Retreives the "inner width" of the table, which is the full width minus any frame. + Retrieves the "inner width" of the table, which is the full width minus any frame. """ def inner_width(%Meta{table_width: table_width, render_vertical_frame?: true}) do table_width - 2 @@ -26,14 +26,14 @@ defmodule TableRex.Renderer.Text.Meta do end @doc """ - Retreives the column width at the given column index. + Retrieves the column width at the given column index. """ def col_width(meta, col_index) do Map.get(meta.col_widths, col_index) end @doc """ - Retreives the row width at the given row index. + Retrieves the row width at the given row index. """ def row_height(meta, row_index) do Map.get(meta.row_heights, row_index) diff --git a/lib/table_rex/table.ex b/lib/table_rex/table.ex index bbf61f9..9d641c9 100755 --- a/lib/table_rex/table.ex +++ b/lib/table_rex/table.ex @@ -1,4 +1,4 @@ -defmodule TableRex.Table do +defmodule Licensir.TableRex.Table do @moduledoc """ A set of functions for working with tables. @@ -6,10 +6,10 @@ defmodule TableRex.Table do fields are private and must not be accessed directly. Instead, use the functions in this module. """ - alias TableRex.Cell - alias TableRex.Column - alias TableRex.Renderer - alias TableRex.Table + alias Licensir.TableRex.Cell + alias Licensir.TableRex.Column + alias Licensir.TableRex.Renderer + alias Licensir.TableRex.Table defstruct title: nil, header_row: [], rows: [], columns: %{}, default_column: %Column{} @@ -25,7 +25,7 @@ defmodule TableRex.Table do ## Examples iex> Table.new - %TableRex.Table{} + %Licensir.TableRex.Table{} """ @spec new() :: Table.t() @@ -34,7 +34,7 @@ defmodule TableRex.Table do @doc """ Creates a new table with an initial set of rows and an optional header and title. """ - @spec new(list, list, String.t()) :: Table.t() + @spec new(list, list, String.t() | nil) :: Table.t() def new(rows, header_row \\ [], title \\ nil) when is_list(rows) and is_list(header_row) do new() |> put_title(title) @@ -197,7 +197,7 @@ defmodule TableRex.Table do def sort(%Table{rows: [first_row | _]}, column_index, _order) when length(first_row) <= column_index do - raise TableRex.Error, + raise Licensir.TableRex.Error, message: "You cannot sort by column #{column_index}, as the table only has #{length(first_row)} column(s)" end @@ -220,7 +220,7 @@ defmodule TableRex.Table do end defp build_sort_function(_column_index, order) do - raise TableRex.Error, + raise Licensir.TableRex.Error, message: "Invalid sort order parameter: #{order}. Must be an atom, either :desc or :asc." end @@ -233,7 +233,7 @@ defmodule TableRex.Table do end @doc """ - Retreives the value of a column meta option at the specified col_index. + Retrieves the value of a column meta option at the specified col_index. If no value has been set, default values are returned. """ @spec get_column_meta(Table.t(), integer, atom) :: any @@ -291,7 +291,7 @@ defmodule TableRex.Table do def render!(%Table{} = table, opts \\ []) when is_list(opts) do case render(table, opts) do {:ok, rendered_string} -> rendered_string - {:error, reason} -> raise TableRex.Error, message: reason + {:error, reason} -> raise Licensir.TableRex.Error, message: reason end end end