NAME

Text::Table::Boxed - Automate separators and rules for Text::Table

SYNOPSIS

use Text::Table::Boxed;

my $tb = Text::Table::Boxed->new({
  columns => [ "Planet", "Radius\nkm", "Density\ng/cm^3" ],
  style   => "boxrule",
});

$tb->load(
    [ "Mercury", 2360, 3.7 ],
    [ "Venus", 6110, 5.1 ],
    [ "Earth", 6378, 5.52 ],
    [ "Jupiter", 71030, 1.3 ],
);

print $tb;  # Render table including separators and rules

# Custom rules and separators
my $tb = Text::Table::Boxed->new({
  columns => [ "Planet", "Radius\nkm", "Density\ng/cm^3" ],
  picture => <<'EOF',
┌───╥───┬───┐
│ c ║ c │ c │
╞═══╬═══╪═══╡
│ c ║ c │ c │
├───╫───┼───┤
│ c ║ c │ c │
╘═══╩═══╧═══╛
EOF
});

my @lines = $tb->rendered_title();  # including rules
my @lines = $tb->rendered_table();  # including rules

# Retrieve rows, each of which is an array of possibly-multiple lines,
# the last of which is a rule line if appropriate.
my $lineset  = $tb->rendered_title();
my @linesets = $tb->rendered_body_rows($body_row_index, $num_rows);

DESCRIPTION

This wrapper for Text::Table automates column separators and horizontal rules. Embedded newlines are allowed in cell data.

Support for ASCII or Unicode box-drawing characters is built in, or you can give an "ascii art" picture showing what you want.

Text:Table::Boxed is a derived class of Text::Table and supports all of it's methods. new supports a different API where a single hashref argument supplies column descriptors in a 'columns' element, along with possibly other options.

ROWS

The concept of "row" is introduced, which represents a possibly-multiline table row. Rules are inserted only at row boundaries, not between lines within a row. Multi-line rows exist where cell values contain embedded newlines.

Methods with "row" in their name return lines segregated into rows, each row represented by an array of the constituent lines. In contrast, similar methods without "row" in their name return a flat list of lines (or in scalar context, a single multiline string).

Methods with "rendered" in their name include rule lines in their result. For example rendered_table() returns all lines in the table including rule lines, whereas table() omits rule lines.

Rules are inserted only when rendered_*() methods are called, however separators, i.e. characters between columns and at the edges of data rows, are always present because they are inserted among the original columns by 'new' and exist in the underlying Text::Table object.

OPTIONS

columns => [ column titles... ]

A list of column titles or descriptor hashrefs, as documented in Text::Table.

Separators should not be included here.

style => "ascii" | "boxrule"

Use a built-in set of separator and rule characters.

picture => "Multi\nLine\nString";
picture => [ lines ];

Specify separator and rule-line characters using a picture of what you want (see example in the SYNOPSIS).

The letter 'c' is a stand-in for cell content; all other characters in "data" rows are taken as separators including spaces (typically included for padding).

"Rule" lines should be exactly what would be displayed for a table the same size as the picture. Portions are replicated as needed to fit the actual table.

The picture must contain at least two columns; with more columns different separators may be specified at various horizontal positions (however the same separator must be used in every data row in a given column). The separator between the last two columns is re-used if the table has more columns than the picture.

Similarly, the picture must contain at least two rows and the rule between the last two rows is re-used if the actual table has more rows than the picture. Often pictures have three rows to allow a different separator between the title row and the first body row.

See "PICTURE SPECIFICATIONS" for examples.

ADDITIONAL PUBLIC METHODS

Status Information

num_body_rows()

The number of possibly-multiline rows in the body portion of the table. See ROWS above.

num_rows()

The total number of rows, including the title row.

rendered_table_height()

The number of lines in the entire title including rule lines.

rendered_title_height()

The number of lines in just the title row, including rules before and after (unlike title_height() which only counts non-rule lines).

Table Output

rendered_stringify()

Returns the entire table as a single string including rule lines. This is the same as rendered_table() but returns a string even in array context.

The object also stringifies to the same result using operator overloading.

$string = $tb->rendererd_stringify()
$string = $tb;  # same result
rendered_table()

Like table() but includes rule lines.

$line  = $tb->rendered_tables($line_index);  # one line
@lines = $tb->rendered_tables;               # all lines
@lines = $tb->rendered_tables($line_index, $num_tables);

Line index 0 is the top rule line (if there is one), index 1 is the first "real" title line, etc.

body_rows()
rendered_body_rows()

Returns rows, each of which is a ref to an array containing possibly-multiple lines. In scalar context, returns a single array ref (valid only for a single row). rendered_body_rows() includes a rule line as the last line in each row if an interior rule was defined in the picture (it is possible to omit interior rules -- see PICTURE SPECIFICATIONS).

Row index 0 is the first body row.

$lineset  = $tb->rendered_body_rows($row_index);  # one row
@linesets = $tb->rendered_body_rows;              # all rows
@linesets = $tb->rendered_body_rows($row_index, $num_rows);
title_row()
rendered_title_row()

Returns a row representation (i.e. array ref) for the title row. This is the same as row(0) or rendered_row(0).

rendered_title()

Like rendered_table() but only returns lines from the title row, ending with the rule line following the title.

rendered_body()

Returns lines from the body area of the table, including rule lines after each row. Row index 0 is the first line of the first body row.

top_rule()
mid_rule()
mid_rule($body_row_index)
bot_rule()

These return the corresponding rendered rule line. You normally do not call these yourself because rules are automatically included by the "rendered_xxx" methods

mid_rule() accepts an optional index to retrieve other than the first interior rule in the picture.

PICTURE SPECIFICATIONS

Custom separators and rules are specified as a "picture" built from several lines. There are four kinds of rules. All are optional:

  • Top rule

  • Special "mid" rule(s) used only at the indicated position.

  • Default "mid" rule, also used between subsequent body rows

  • Bottom rule

Pictures must have at least two rows and columns:

┌───┬───┐   /=======\  ⇦  top rule
│ c │ c │   | c | c |
├───┼───┤   |---+---|  ⇦  default mid rule
│ c │ c │   | c | c |
╘═══╧═══╛   \=======/  ⇦  bottom rule

The letter 'c' is a stand-in for real content. Everything between 'c's or at the edge is a separator string.

With more than two picture rows, special rules are used where indicated among the upper rows in the table. The last interior rule is the "default" rule, used between further rows if there are any. And analogously for columns:

          ⮦ Left-edge separator
          ⏐   ⮦ Special separator
          ⏐   ⏐   ⮦ Default separator
          ↓   ↓   ↓   ⮦ Right-edge separator
┌─╥─┬─┐   ┌───╥───┬───┐   ==============  ⇦  top rule
│c║c│c│   │ c ║ c │ c │   | c || c | c |
╞═╬═╪═╡   ╞═══╬═══╪═══╡   |===++===+===|  ⇦  special rule after title
│c║c│c│   │ c ║ c │ c │   | c || c | c |
┝━╋━┿━┥   ┝━━━╋━━━┿━━━┥   |___||___|___|  ⇦  special after 1st body row
│c║c│c│   │ c ║ c │ c │   | c || c | c |
├─╫─┼─┤   ├───╫───┼───┤   |---++---+---|  ⇦  default rule
│c║c│c│   │ c ║ c │ c │   | c || c | c |
╘═╩═╧═╛   ╘═══╩═══╧═══╛   ==============  ⇦  bottom rule

In the leftmost example, column separators are single characters so there is no padding around content. In the others the separators are two or three characters each including spaces for padding, e.g. "|␠", "␠|␠" or "␠|".

Outer borders can be omitted:

c║c│c    c ║ c │ c     c | c | c
═╬═╪═   ═══╬═══╪═══   ===+===+===
c║c│c    c ║ c │ c     c | c | c
─╫─┼─   ───╫───┼───   ---+---+---
c║c│c    c ║ c │ c     c | c | c

To get only outer borders, omit the interior rules and use interior separators containing only spaces (unless you want cells to touch):

┌───┐   ┌─────┐   =======
│c c│   │ c c │   | c c |
│c c│   │ c c │   | c c |
│c c│   │ c c │   | c c |
╘═══╛   ╘═════╛   =======

RENDERING EXAMPLES

If there are more actual rows and/or columns than in the picture, the "default" rule and/or column separator is repeated:

Picture    Rendered Actual Table
┌─╥─┬─┐    ┌──────╥─────┬──────────┬────────────┐ ⇦  top rule
│c║c│c│    │ NAME ║ AC  │ NUMBER   │ Pet's Name │
╞═╬═╪═╡    ╞══════╬═════╪══════════╪════════════╡ ⇦  special rule
│c║c│c│    │ Sam  ║ 800 │ 555-1212 │  Cutesy    │
├─╫─┼─┤    ├──────╫─────┼──────────┼────────────┤ ⇦  default rule
│c║c│c│    │ Mary ║ 880 │ 123-4567 │  Killer    │
╘═╩═╧═╛    ├──────╫─────┼──────────┼────────────┤ ⇦  default rule
           │ Don  ║ 880 │ 123-4567 │  Tweetie   │
           ├──────╫─────┼──────────┼────────────┤ ⇦  default rule
           │ Mico ║ 880 │ 123-4567 │  Tabby     │
           ╘══════╩═════╧══════════╧════════════╛ ⇦  bottom rule

The edge separators are always used, as are the top & bottom rules (if defined), even if there are fewer rows or columns than in the picture:

┌───┰───┬───┐    ┌───────┐ ⇦  top rule
│ c ║ c │ c │    │Meaning│
┝━━━╋━━━┿━━━┥    │of life│
│ c ║ c │ c │    ┝━━━━━━━┥ ⇦  special after-title rule
├───╫───┼───┤    │  42   │
│ c ║ c │ c │    ╘═══════╛ ⇦  bottom rule
╘═══╩═══╧═══╛

If there is a title row but no body rows, only the top and bottom rules are used:

┌──────╥─────┬────────────┐ ⇦  top rule
│ NAME ║ AC  │  NUMBER    │
╘══════╩═════╧════════════╛ ⇦  bottom rule

If there are no titles or data, nothing is rendered e.g. the object stringifies to "".

PAGER EXAMPLE

Please see Text::Table::Boxed::Pager for an example of using rows to view a table on a terminal, keeping multi-line rows together when possible.

ACKNOWLEDGMENTS

This module was inspired the example code in the Text::Table documentation by Anno Siegel and/or Shlomi Fish, and a post at https://stackoverflow.com/questions/30762521/how-can-i-print-a-table-with-multi-line-strings-using-the-texttable-module by stackoverflow user "ThisSuitIsBlackNot".

BUGS

Text::Table::Boxed is new in 2024 and actively maintained. Please report issues!

https://github.com/jimav/Text-Table-Boxed/issues

AUTHOR

Jim Avera (jim.avera at gmail)

LICENSE

CC0 or Public Domain. However your application is likely subject to the more restrictive licenses of Text::Table and other modules.