TTY::Table
¶ ↑
A flexible and intuitive table formatting.
TTY::Table provides independent table formatting component for TTY toolkit.
Features¶ ↑
-
Table behaves like an array with familiar API see
-
Create table once and render using custom view renderers see
-
Rendering provides many display options see
-
Easy custom border creation see
-
Supports multibyte character encodings
Installation¶ ↑
Add this line to your application's Gemfile:
gem 'tty-table'
And then execute:
$ bundle
Or install it yourself as:
$ gem install tty-table
Contents¶ ↑
1. Usage¶ ↑
First, provide TTY::Table with headers and data:
table = TTY::Table.new ['header1','header2'], [['a1', 'a2'], ['b1', 'b2']]
Then simply call render on the instance with with border type
as first argument:
table.render(:ascii) # => # +-------+-------+ # |header1|header2| # +-------+-------+ # |a1 |a2 | # +-------+-------+ # |b1 |b2 | # +-------+-------+
2. Interface¶ ↑
2.1 Initialization¶ ↑
TTY::Table can be created in variety of ways. The easiest way is to pass 2-dimensional array:
table = TTY::Table[['a1', 'a2'], ['b1', 'b2']] table = TTY::Table.new [['a1', 'a2'], ['b1', 'b2']] table = TTY::Table.new rows: [['a1', 'a2'], ['b1', 'b2']]
Alternatively you can specify rows one by one inside block:
table = TTY::Table.new do |t| t << ['a1', 'a2'] t << ['b1', 'b2'] end
You can add rows of data after initialization:
table = TTY::Table.new table << ['a1','a2'] table << ['b1','b2']
In addition to rows you can specify table header:
table = TTY::Table.new ['h1', 'h2'], [['a1', 'a2'], ['b1', 'b2']] table = TTY::Table.new header: ['h1', 'h2'], rows: [['a1', 'a2'], ['b1', 'b2']]
or cross header with rows inside a hash like so
table = TTY::Table.new [{'h1' => ['a1', 'a2'], 'h2' => ['b1', 'b2']}]
2.2 Iteration¶ ↑
Table behaves like an Array so <<, each and
familiar methods can be used:
table << ['a1', 'a2', 'a3'] table << ['b1', 'b2', 'b3'] table << ['a1', 'a2'] << ['b1', 'b2'] # chain rows assignment
In order to iterate over table rows including headers do:
table.each { |row| ... } # iterate over rows table.each_with_index { |row, index| ... } # iterate over rows with an index
2.3 Access¶ ↑
In order to referene the row at index do:
table = TTY::Table.new [['a1','a2'], ['b1','b2']] table[0] # => ['a1','a2'] table.row(0) # => ['a1','a2'] table.row(i) { |row| ... } # return array for row(i)
Negative indices count backwards from the end of table data
(-1 is the last element):
table[-1] # => ['b1','b2']
To reference element at given row(i) and column(j) do:
table[i, j] # return element at row(i) and column(j) table[0,0] # => 'a1'
To specifically reference column(j) do:
table.column(j) { ... } # return array for column(j) table.column(0) # => ['a1','b1'] table.column(name) # return array for column(name), name of header
An IndexError is raised for indexes outside of data range.
2.4 Size¶ ↑
In order to query the number of rows, columns or size do:
table.rows_size # return row size table.columns_size # return column size table.size # return an array of [row_size, column_size]
2.5 Orientation¶ ↑
3 Rendering¶ ↑
TTY-Table rendering process means you can create tabular data once and then create different renderers to match your needs for formatting the data.
3.1 Render¶ ↑
Given a table:
table = TTY::Table.new ['header1','header2'], [['a1', 'a2'], ['b1', 'b2']]
Once you have an instance of TTY::Table you can decorate the
content using the render method. In order to display a basic
whitespace delimited view do:
table.render(:basic) # => # header1 header2 # a1 a2 # b1 b2
This will use so called :basic renderer with default options.
The other renderers are :ascii and :unicode.
The render method can accept as a second argument the rendering options either as hash value:
table.render(:basic, alignments: [:left, :center])
or inside a block:
table.render(:basic) do |renderer| renderer.alignments= [:left, :center] end
3.2 Renderer¶ ↑
TTY::Table has a definition of
TTY::Table::Renderer which allows you to provide different
view for your tabular data. It comes with few initial renderers built in
such as TTY::Table::Renderer::Basic,
TTY::Table::Renderer::ASCII and
TTY::Table::Renderer:Unicode.
Given a table of data:
table = TTY::Table.new ['header1','header2'], [['a1', 'a2'], ['b1', 'b2']]
You can create a special renderer for it:
multi_renderer = TTY::Table::Renderer::Basic.new(table, multiline: true)
and then call render
multi_renderer.render
This way, you create tabular data once and then create different renderers to match your needs for formatting the data.
3.2.1 Basic Renderer¶ ↑
The basic render allows for formatting table with whitespace without any border:
renderer = TTY::Table::Renderer::Basic.new(table)
renderer.render # => # header1 header2 # a1 a2 # b1 b2
This is the same as calling render directly on table:
table.render
3.2.2 ASCII Renderer¶ ↑
The ascii renderer allows for formatting table with ASCII type border.
Create an instance of ASCII renderer:
renderer = TTY::Table::Renderer::ASCII.new(table)
and then call render to get the formatted data:
renderer.render # => # +-------+-------+ # |header1|header2| # +-------+-------+ # |a1 |a2 | # |b1 |b2 | # +-------+-------+
This is the same as calling render directly on table instance
with :ascii as the first argument:
table.render(:ascii)
3.2.3 Unicode Renderer¶ ↑
The uniocde renderer allows for formatting table with Unicode type border.
Create an instance of Unicode renderer:
renderer = TTY::Table::Renderer::Unicode.new(table)
and then call render to get the formatted data:
renderer.render # => # ┌───────┬───────┐ # │header1│header2│ # ├───────┼───────┤ # │a1 │a2 │ # │b1 │b2 │ # └───────┴───────┘
This is the same as calling render directly on table instance
with :unicode as the first argument:
table.render(:unicode)
3.3 Options¶ ↑
Rendering of TTY-Table includes numerous customization options:
alignments # array of cell alignments out of :left, :center and :right, # default :left border # hash of border options - :characters, :style and :separator border_class # a type of border to use such as TTY::Table::Border::Null, # TTY::Table::Border::ASCII, TTY::Table::Border::Unicode column_widths # array of maximum column widths filter # a proc object that is applied to every field in a row indent # indentation applied to rendered table, by default 0 multiline # if true will wrap text at new line or column width, # when false will escape special characters padding # array of integers to set table fields padding, # by default [0,0,0,0] resize # if true will expand/shrink table column sizes to match # the terminal width, otherwise if false will rotate # table vertically. By default set to false width # constrain the table total width, by default dynamically # calculated based on content and terminal size
The render method can accept as a second argument the above
options either as hash value:
table.render(:basic, alignments: [:left, :center])
or inside a block:
table.render(:basic) do |renderer| renderer.alignments= [:left, :center] end
3.4 Alignment¶ ↑
By default all columns are :left aligned.
You can align each column individuall by passing alignments
option to table renderer:
table.render :ascii, alignments: [:center, :right] # => # +-------+-------+ # |header1|header2| # +-------+-------+ # | a1 | a2| # | b1 | b2| # +-------+-------+
Alternatively you can align all columns with alignment option:
table.render :ascii, alignment: [:center] # => # +-------+-------+ # |header1|header2| # +-------+-------+ # | a1 | a2 | # | b1 | b2 | # +-------+-------+
If you require a more granular alignment you can align individual fields in
a row by passing :alignment option like so:
table = TTY::Table.new header: ['header1', 'header2'] table << [{value: 'a1', alignment: :right}, 'a2'] table << ['b1', {value: 'b2', alignment: :center}]
and then simply render:
table.render(:ascii) # => # +-------+-------+ # |header1|header2| # +-------+-------+ # | a1|a2 | # |b1 | b2 | # +-------+-------+
3.5 Border¶ ↑
To print border around data table you need to specify renderer
type out of basic, ascii, unicode.
By default basic is used. For instance, to output unicode
border:
table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2']] table.render :unicode # => # ┌───────┬───────┐ # │header1│header2│ # ├───────┼───────┤ # │a1 │a2 │ # │b1 │b2 │ # └───────┴───────┘
or by creating unicode renderer:
renderer = TTY::Table::Renderer::Unicode.new(table) renderer.render
3.5.1 Parts¶ ↑
The following are available border parts:
| Part | ASCII | Unicode | | ————- |:—–:|:——-:| | top | - |
─ | | top_mid | + | ┬ | | top_left |
+ | ┌ | | top_right | + |
┐ | | bottom | - | ─ | | bottom_mid
| + | ┴ | | bottom_left | + |
└ | | bottom_right | + | ┘ | | mid |
- | ─ | | mid_mid | + |
┼ | | mid_left | + | ├ | | mid_right
| + | ┤ | | left | | |
│ | | center | | | │ | | right |
| | │ |
Using the above border parts you can create your own border with the
border helper:
table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2'] table.render do |renderer| renderer.border do mid '=' mid_mid ' ' end end # => # header1 header2 # ======= ======= # a1 a2 # b1 b2
3.5.2 Custom¶ ↑
You can also create your own custom border by subclassing
TTY::Table::Border and implementing the
def_border method using internal DSL methods like so:
class MyBorder < TTY::Table::Border def_border do left '$' center '$' right '$' bottom ' ' bottom_mid '*' bottom_left '*' bottom_right '*' end end
Next pass the border class to your table instance render_with
method
table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2'] table.render_with MyBorder # => # $header1$header2$ # $a1 $a2 $ # * * *
3.5.3 Separator¶ ↑
In addition to specifying border characters you can force table to render separator line on each row like:
table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2']] table.render do |renderer| renderer.border.separator = :each_row end # => # +-------+-------+ # |header1|header2| # +-------+-------+ # |a1 |a2 | # +-------+-------+ # |b1 |b2 | # +-------+-------+
3.5.4 Style¶ ↑
If you want to change the display color of your border do:
table.render do |renderer| renderer.border.style = :green end
All supported colors are provided by the Pastel dependency.
3.6 Filter¶ ↑
You can define filters that will modify individual table fields value before they are rendered. A filter can be a callable such as proc. Here's an example that formats
table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2']] table.render do |renderer| renderer.filter = Proc.new do |val, row_index, col_index| if col_index == 1 and !(row_index == 0) val.capitalize else val end end end # => # +-------+-------+ # |header1|header2| # +-------+-------+ # |a1 |A2 | # +-------+-------+ # |b1 |B2 | # +-------+-------+
To color even fields red on green background add filter like so
pastel = Pastel.new table.render do |renderer| renderer.filter = proc do |val, row_index, col_index| col_index % 2 == 1 ? pastel.red.on_green(val) : val end end
3.7 Multiline¶ ↑
Renderer options may include multiline parameter. When set to
true, table fields will wrap at their natural line breaks or
the column widths(if provided).
table = TTY::Table.new [ ["First", '1'], ["Multi\nLine\nContent", '2'], ["Third", '3']] table.render :ascii, multiline: true # => # +-------+-+ # |First |1| # |Multi |2| # |Line | | # |Content| | # |Third |3| # +-------+-+
When multiline is set to false, all line break
characters will be escaped. In cases when the column widths are set, the
content will be truncated.
table = TTY::Table.new [["First", '1'], ["Multiline\nContent", '2'], ["Third", '3']] table.render :ascii, multiline: false # => # +------------------+-+ # |First |1| # |Multiline\nContent|2| # |Third |3| # +------------------+-+
3.8 Padding¶ ↑
Renderer also accepts padding option which accepts array with
arguments similar to CSS padding.
[2,2,2,2] # => pad left and right with 2 characters, add 2 lines above and below [1,2] # => pad left and right with 2 characters, add 1 line above and below 1 # => pad left and right with 1 character, and 1 lines above and below
Therefore, to apply padding to the example table do:
table.render(:ascii, padding: [1,2,1,2]) # => # +---------+---------+ # | | | # | header1 | header2 | # | | | # +---------+---------+ # | | | # | a1 | a2 | # | | | # | | | # | b1 | b2 | # | | | # +---------+---------+
However, when adding top or bottom padding to content with line breaks, the
multiline option needs to be set to true to allow
for rows to span multiple lines. For example:
table = TTY::Table.new header: ['head1', 'head2'] table << ["Multi\nLine", "Text\nthat\nwraps"] table << ["Some\nother\ntext", 'Simple']
would render as:
table.render :ascii, multiline: true, padding: [1,2,1,2] # => # +---------+----------+ # | | | # | h1 | head2 | # | | | # +---------+----------+ # | | | # | Multi | Text | # | Line | that | # | | wraps | # | | | # | | | # | Some | Simple | # | other | | # | text | | # | | | # +---------+----------+
3.9 Resize¶ ↑
3.10 Width¶ ↑
To control table's column sizes pass width,
resize options. By default table's natural column widths
are calculated from the content. If the total table width does not fit in
terminal window then the table is rotated vertically to preserve content.
The resize property will force the table to expand/shrink to
match the terminal width or custom width. On its own the
width property will not resize table but only enforce table
vertical rotation if content overspills.
header = ['h1', 'h2', 'h3'] rows = [['aaa1', 'aa2', 'aaaaaaa3'], ['b1', 'b2', 'b3']] table = TTY::Table.new header, rows table.render width: 80, resize: true # => # +---------+-------+------------+ # |h1 |h2 |h3 | # +---------+-------+------------+ # |aaa1 |aa2 |aaaaaaa3 | # |b1 |b2 |b3 | # +---------+-------+------------+
Contributing¶ ↑
-
Fork it ( github.com/piotrmurach/tty-table/fork )
-
Create your feature branch (
git checkout -b my-new-feature) -
Commit your changes (
git commit -am 'Add some feature') -
Push to the branch (
git push origin my-new-feature) -
Create a new Pull Request
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
Copyright¶ ↑
Copyright © 2015-2018 Piotr Murach. See LICENSE for further details.