• Stars
    star
    190
  • Rank 203,739 (Top 5 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 10 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A flexible and intuitive table generator
TTY Toolkit logo

TTY::Table Gitter

Gem Version Actions CI Build status Code Climate Coverage Status Inline docs

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 data, for example, two headers and two rows:

table = TTY::Table.new(["header1","header2"], [["a1", "a2"], ["b1", "b2"]])

Then to print to the console, call the render method with border type as a first argument:

puts 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 the rows one by one inside a block:

table = TTY::Table.new do |t|
  t << ["a1", "a2"]
  t << ["b1", "b2"]
end

You can add rows of data after initialization with << operator:

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"]])

You can also mix 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 reference 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. Defaults to :left.
  • :border - hash of border options out of :characters, :style and :separator
  • :border_class - a type of border to use such as TTY::Table::Border::Null, TTY::Table::Border::ASCII and 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 - when 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. Defaults to [0,0,0,0].
  • :resize - when true will expand/shrink table column sizes to match the terminal width, otherwise when false will rotate table vertically. Defaults to false.
  • :width - constrains the table total width. Defaults to value automatically calculated based on the 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 as a property:

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 individually 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 the table to render a 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     |
#  +-------+-------+

If you want more control you can provide an array of rows after which a separator will be added:

table = TTY::Table.new ["header1", "header2"], [["a1", "a2"], ["b1", "b2"], ["c1", "c2"]]
table.render do |renderer|
  renderer.border.separator = [0, 2]
end
# =>
#  +-------+-------+
#  |header1|header2|
#  +-------+-------+
#  |a1     |a2     |
#  |b1     |b2     |
#  +-------+-------+
#  |c1     |c2     |
#  +-------+-------+

Note: if you supply a detailed list of rows to separate, then the separator between the header and the rows will not be automatically added.

You can also give the separator option a proc to control where the separators are:

table = TTY::Table.new ["header1", "header2"],
                       [["a1", "a2"], ["b1", "b2"], ["c1", "c2"], ["d1", "d2"]]
table.render do |renderer|
  renderer.border.separator = ->(row) { row == 0 || (row+1) % 2 == 0} # separate every two rows
end
# =>
#  +-------+-------+
#  |header1|header2|
#  +-------+-------+
#  |a1     |a2     |
#  |b1     |b2     |
#  +-------+-------+
#  |c1     |c2     |
#  |d1     |d2     |
#  +-------+-------+

Finally you can also position a separator using the :separator key word in place of a row:

table = TTY::Table.new ["header1", "header2"],
                       [:separator, ["a1", "a2"], ["b1", "b2"]]
table << :separator << ["c1", "c2"]  # you can push separators on too!
table.render
# =>
#  +-------+-------+
#  |header1|header2|
#  +-------+-------+
#  |a1     |a2     |
#  |b1     |b2     |
#  +-------+-------+
#  |c1     |c2     |
#  +-------+-------+

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 field value before it is rendered. A filter can be a callable such as proc.

Here's an example that formats capitalizes each field in second column skipping the header:

table = TTY::Table.new(["header1", "header2"], [["a1", "a2"], ["b1", "b2"]])
table.render do |renderer|
  renderer.filter = ->(val, row_index, col_index) do
    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 = ->(val, row_index, col_index) do
    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"]

This 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

You can force table to resize to the terminal full width using the :resize option:

table.render(:ascii, resize: true)

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.

For example, given the following table:

header = ["h1", "h2", "h3"]
rows   = [["aaa1", "aa2", "aaaaaaa3"], ["b1", "b2", "b3"]]
table = TTY::Table.new(header, rows)

The result of rending to 80 columns width will produce:

table.render(width: 80, resize: true)
# =>
#  +---------+-------+------------+
#  |h1       |h2     |h3          |
#  +---------+-------+------------+
#  |aaa1     |aa2    |aaaaaaa3    |
#  |b1       |b2     |b3          |
#  +---------+-------+------------+

Contributing

  1. Fork it ( https://github.com/piotrmurach/tty-table/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. 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 (c) 2015 Piotr Murach. See LICENSE for further details.

More Repositories

1

tty

Toolkit for developing sleek command line apps.
Ruby
2,505
star
2

tty-prompt

A beautiful and powerful interactive command line prompt
Ruby
1,467
star
3

github

Ruby interface to GitHub API
Ruby
1,151
star
4

finite_machine

A minimal finite state machine with a straightforward syntax.
Ruby
807
star
5

pastel

Terminal output styling with intuitive and clean API.
Ruby
638
star
6

rspec-benchmark

Performance testing matchers for RSpec
Ruby
602
star
7

tty-spinner

A terminal spinner for tasks that have non-deterministic time frame.
Ruby
428
star
8

tty-progressbar

Display a single or multiple progress bars in the terminal.
Ruby
422
star
9

loaf

Manages and displays breadcrumb trails in Rails app - lean & mean.
Ruby
407
star
10

tty-command

Execute shell commands with pretty output logging and capture stdout, stderr and exit status.
Ruby
400
star
11

tty-markdown

Convert a markdown document or text into a terminal friendly output.
Ruby
307
star
12

tty-logger

A readable, structured and beautiful logging for the terminal
Ruby
294
star
13

github_cli

GitHub on your command line. Use your terminal, not the browser.
Ruby
266
star
14

tty-box

Draw various frames and boxes in your terminal window
Ruby
183
star
15

awesome-ruby-cli-apps

A curated list of awesome command-line applications in Ruby.
Ruby
169
star
16

rack-policy

Rack middleware for the EU ePrivacy Directive compliance in Ruby Web Apps
Ruby
147
star
17

tty-pie

Draw pie charts in your terminal window
Ruby
140
star
18

necromancer

Conversion from one object type to another with a bit of black magic.
Ruby
135
star
19

strings

A set of useful functions for transforming strings.
Ruby
129
star
20

coinpare

Compare cryptocurrency trading data across multiple exchanges and blockchains in the comfort of your terminal
Ruby
113
star
21

tty-exit

Terminal exit codes.
Ruby
99
star
22

strings-case

Convert strings between different cases.
Ruby
97
star
23

tty-reader

A set of methods for processing keyboard input in character, line and multiline modes.
Ruby
89
star
24

tty-screen

Terminal screen detection - cross platform, major ruby interpreters
Ruby
86
star
25

tty-option

A declarative command-line parser
Ruby
85
star
26

merkle_tree

A merkle tree is a data structure used for efficiently summarizing sets of data, often one-time signatures.
Ruby
82
star
27

verse

[DEPRECATED] Text transformations
Ruby
71
star
28

tty-cursor

Terminal cursor movement and manipulation of cursor properties such as visibility
Ruby
70
star
29

tty-file

File manipulation utility methods
Ruby
67
star
30

supervision

Write distributed systems that are resilient and self-heal.
Ruby
65
star
31

tty-config

A highly customisable application configuration interface for building terminal tools.
Ruby
63
star
32

tty-font

Terminal fonts
Ruby
60
star
33

benchmark-trend

Measure performance trends of Ruby code
Ruby
60
star
34

lex

Lex is an implementation of lex tool in Ruby.
Ruby
56
star
35

tty-tree

Print directory or structured data in a tree like format
Ruby
56
star
36

strings-truncation

Truncate strings with fullwidth characters and ANSI codes.
Ruby
50
star
37

slideck

Present Markdown-powered slide decks in the terminal.
Ruby
44
star
38

tty-pager

Terminal output paging - cross-platform, major ruby interpreters
Ruby
40
star
39

tty-color

Terminal color capabilities detection
Ruby
35
star
40

tty-link

Hyperlinks in your terminal
Ruby
32
star
41

strings-inflection

Convert between singular and plural forms of English nouns
Ruby
31
star
42

tty-platform

Operating system detection
Ruby
29
star
43

tty-sparkline

Sparkline charts for terminal applications.
Ruby
29
star
44

tty-editor

Opens a file or text in the user's preferred editor
Ruby
28
star
45

communist

Library for mocking CLI calls to external APIs
Ruby
25
star
46

splay_tree

A self-balancing binary tree optimised for fast access to frequently used nodes.
Ruby
24
star
47

equatable

Allows ruby objects to implement equality comparison and inspection methods.
Ruby
24
star
48

minehunter

Terminal mine hunting game.
Ruby
23
star
49

rotation.js

Responsive and mobile enabled jQuery plugin to help create rotating content.
JavaScript
22
star
50

strings-ansi

Handle ANSI escape codes in strings
Ruby
20
star
51

benchmark-malloc

Trace memory allocations and collect stats
Ruby
20
star
52

strings-numeral

Express numbers as string numerals
Ruby
20
star
53

tty-which

Cross-platform implementation of Unix `which` command
Ruby
19
star
54

benchmark-perf

Benchmark execution time and iterations per second
Ruby
13
star
55

tty-runner

A command routing tree for terminal applications
Ruby
12
star
56

queen

English language linter to hold your files in high esteem.
Ruby
8
star
57

impact

Ruby backend for Impact.js framework
Ruby
8
star
58

pastel-cli

CLI tool for intuitive terminal output styling
Ruby
7
star
59

dotfiles

Configuration files for Unix tools
Vim Script
7
star
60

tty-markdown-cli

CLI tool for displaying nicely formatted Markdown documents in the terminal
Ruby
6
star
61

static_deploy

Automate deployment of static websites
Ruby
6
star
62

tenpin

Terminal tenpin bowling game
Ruby
4
star
63

tty.github.io

TTY toolkit website.
SCSS
3
star
64

tytus

Helps you manage page titles in your Rails app.
Ruby
3
star
65

peter-murach.github.com

Personal webpage
JavaScript
2
star
66

wc.rb

A Ruby clone of Unix wc utility.
Ruby
2
star
67

exportable

Rails plugin to ease exporting tasks.
Ruby
1
star
68

capistrano-git-stages

Multistage capistrano git tags
Ruby
1
star
69

leek

Cucumber steps and RSpec expectations for command line apps
Ruby
1
star
70

tabster

Ruby
1
star
71

unicorn.github.io

Website for the github_api and github_cli ruby gems.
CSS
1
star
72

tty-color-cli

CLI tool for terminal color capabilities detection
Ruby
1
star
73

finite_machine.github.io

Website for finite_machine Ruby gem
SCSS
1
star
74

strings-wrapping

Wrap strings with fullwidth characters and ANSI codes
Ruby
1
star