Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/piotrmurach/tty-table
A flexible and intuitive table generator
https://github.com/piotrmurach/tty-table
cli ruby-gem table tty tty-components
Last synced: about 1 month ago
JSON representation
A flexible and intuitive table generator
- Host: GitHub
- URL: https://github.com/piotrmurach/tty-table
- Owner: piotrmurach
- License: mit
- Created: 2015-02-08T16:57:02.000Z (almost 10 years ago)
- Default Branch: master
- Last Pushed: 2024-03-15T14:12:10.000Z (9 months ago)
- Last Synced: 2024-11-06T10:06:39.525Z (about 2 months ago)
- Topics: cli, ruby-gem, table, tty, tty-components
- Language: Ruby
- Homepage: https://ttytoolkit.org
- Size: 350 KB
- Stars: 190
- Watchers: 5
- Forks: 22
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE.txt
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- Open-Source-Ruby-and-Rails-Apps - tty-table - A flexible and intuitive table generator π₯ β π (Happy Exploring π€)
README
# TTY::Table [![Gitter](https://badges.gitter.im/Join%20Chat.svg)][gitter]
[![Gem Version](https://badge.fury.io/rb/tty-table.svg)][gem]
[![Actions CI](https://github.com/piotrmurach/tty-table/workflows/CI/badge.svg?branch=master)][gh_actions_ci]
[![Build status](https://ci.appveyor.com/api/projects/status/8fxrbawbyomqd979?svg=true)][appveyor]
[![Code Climate](https://codeclimate.com/github/piotrmurach/tty-table/badges/gpa.svg)][codeclimate]
[![Coverage Status](https://coveralls.io/repos/github/piotrmurach/tty-table/badge.svg?branch=master)][coverage]
[![Inline docs](http://inch-ci.org/github/piotrmurach/tty-table.svg?branch=master)][inchpages][gitter]: https://gitter.im/piotrmurach/tty
[gem]: http://badge.fury.io/rb/tty-table
[gh_actions_ci]: https://github.com/piotrmurach/tty-table/actions?query=workflow%3ACI
[appveyor]: https://ci.appveyor.com/project/piotrmurach/tty-table
[codeclimate]: https://codeclimate.com/github/piotrmurach/tty-table
[coverage]: https://coveralls.io/github/piotrmurach/tty-table
[inchpages]: http://inch-ci.org/github/piotrmurach/tty-table> A flexible and intuitive table formatting.
**TTY::Table** provides independent table formatting component for [TTY](https://github.com/piotrmurach/tty) toolkit.
## Features
* Table behaves like an array with familiar API [see](#2-interface)
* Create table once and render using custom view renderers [see](#3-rendering)
* Rendering provides many display options [see](#33-options)
* Easy custom border creation [see](#352-custom)
* Supports multibyte character encodings## Installation
Add this line to your application's Gemfile:
```ruby
gem "tty-table"
```And then execute:
$ bundle
Or install it yourself as:
$ gem install tty-table
## Contents
* [1. Usage](#1-usage)
* [2. Interface](#2-interface)
* [2.1 Initialization](#21-initialization)
* [2.2 Iteration](#22-iteration)
* [2.3 Access](#23-access)
* [2.4 Size](#24-size)
* [3. Rendering](#3-rendering)
* [3.1 Render](#31-render)
* [3.2 Renderer](#32-renderer)
* [3.2.1 Basic renderer](#321-basic-renderer)
* [3.2.2 ASCII renderer](#322-ascii-renderer)
* [3.2.3 Unicode renderer](#323-unicode-renderer)
* [3.3 Options](#33-options)
* [3.4 Alignment](#34-alignment)
* [3.5 Border](#35-border)
* [3.5.1 Parts](#351-parts)
* [3.5.2 Custom](#352-custom)
* [3.5.3 Separator](#353-separator)
* [3.5.4 Style](#354-style)
* [3.6 Filter](#36-filter)
* [3.7 Multiline](#37-multiline)
* [3.8 Padding](#38-padding)
* [3.9 Resize](#39-resize)
* [3.10 Width](#310-width)## 1. Usage
First, provide **TTY::Table** with data, for example, two headers and two rows:
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
table = TTY::Table.new do |t|
t << ["a1", "a2"]
t << ["b1", "b2"]
end
```You can add rows of data after initialization with `<<` operator:
```ruby
table = TTY::Table.new
table << ["a1","a2"]
table << ["b1","b2"]
```In addition to rows, you can specify table header:
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
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):
```ruby
table[-1] # => ["b1","b2"]
```To reference element at given row(i) and column(j) do:
```ruby
table[i, j] # return element at row(i) and column(j)
table[0,0] # => "a1"
```To specifically reference column(j) do:
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
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](#33-options) either as hash value:
```ruby
table.render(:basic, alignments: [:left, :center])
```or inside a block:
```ruby
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:
```ruby
table = TTY::Table.new ["header1","header2"], [["a1", "a2"], ["b1", "b2"]]
```You can create a special renderer for it:
```ruby
multi_renderer = TTY::Table::Renderer::Basic.new(table, multiline: true)
```and then call `render`
```ruby
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:
```ruby
renderer = TTY::Table::Renderer::Basic.new(table)
``````ruby
renderer.render
# =>
# header1 header2
# a1 a2
# b1 b2
```This is the same as calling `render` directly on table:
```ruby
table.render
```#### 3.2.2 ASCII Renderer
The ascii renderer allows for formatting table with ASCII type border.
Create an instance of ASCII renderer:
```ruby
renderer = TTY::Table::Renderer::ASCII.new(table)
```and then call `render` to get the formatted data:
```ruby
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:
```ruby
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:
```ruby
renderer = TTY::Table::Renderer::Unicode.new(table)
```and then call `render` to get the formatted data:
```ruby
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:
```ruby
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:
```ruby
table.render(:basic, alignments: [:left, :center])
```Or inside a block as a property:
```ruby
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:
```ruby
table.render(:ascii, alignments: [:center, :right])
# =>
# +-------+-------+
# |header1|header2|
# +-------+-------+
# | a1 | a2|
# | b1 | b2|
# +-------+-------+
```Alternatively you can align all columns with `:alignment` option:
```ruby
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:
```ruby
table = TTY::Table.new(header: ["header1", "header2"])
table << [{value: "a1", alignment: :right}, "a2"]
table << ["b1", {value: "b2", alignment: :center}]
```and then simply render:
```ruby
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:
```ruby
table = TTY::Table.new ["header1", "header2"], [["a1", "a2"], ["b1", "b2"]]
table.render :unicode
# =>
# βββββββββ¬ββββββββ
# βheader1βheader2β
# βββββββββΌββββββββ€
# βa1 βa2 β
# βb1 βb2 β
# βββββββββ΄ββββββββ
```or by creating unicode renderer:
```ruby
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:
```ruby
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:
```ruby
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
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
table.render do |renderer|
renderer.border.style = :green
end
```All [supported colors](https://github.com/piotrmurach/pastel#3-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:
```ruby
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:
```ruby
pastel = Pastel.newtable.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).
```ruby
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.
```ruby
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.
```ruby
[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:
```ruby
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:
```ruby
table = TTY::Table.new(header: ["head1", "head2"])
table << ["Multi\nLine", "Text\nthat\nwraps"]
table << ["Some\nother\ntext", "Simple"]
```This would render as:
```ruby
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:
```ruby
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:
```ruby
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:
```ruby
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 RequestThis project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
## Copyright
Copyright (c) 2015 Piotr Murach. See LICENSE for further details.