TTY
Toolbox for developing CLI clients in Ruby. This library provides a fluid interface for working with terminals.
Features
Jump-start development of your command line app:
- Fully customizable table rendering with an easy-to-use API. (status: In Progress)
- Terminal output colorization. (status: DONE)
- Terminal & System detection utilities. (status: In Progress)
- Text alignment/padding/indentation. (status: In Progress)
- Shell user interface. (status: In Progress)
- File diffs. (status: TODO)
- Progress bar. (status: TODO)
- Configuration file management. (status: TODO)
- Fully tested with major ruby interpreters.
- No dependencies to allow for easy gem vendoring.
Installation
Add this line to your application's Gemfile:
gem 'tty'
And then execute:
$ bundle
Or install it yourself as:
$ gem install tty
Usage
Table
To instantiate table 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']]
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']}]
Apart from rows
and header
, you can provide other customization options such as
column_widths # array of maximum columns widths
column_aligns # array of cell alignments out of :left, :center and :right
renderer # enforce display type out of :basic, :color, :unicode, :ascii
orientation # either :horizontal or :vertical
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
table.each { |row| ... } # iterate over rows
table[i, j] # return element at row(i) and column(j)
table.row(i) { ... } # return array for row(i)
table.column(j) { ... } # return array for column(j)
table.row_size # return row size
table.column_size # return column size
table.size # return an array of [row_size, column_size]
or pass your rows in a block
table = TTY::Table.new do |t|
t << ['a1', 'a2', 'a3']
t << ['b1', 'b2', 'b3']
end
And then to print do
table.to_s
a1 a2 a3
b1 b2 b3
To print border around data table you need to specify renderer
type out of basic
, ascii
, unicode
. For instance to output unicode border:
table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2'], renderer: 'unicode'
table.to_s
┌───────┬───────┐
│header1│header2│
├───────┼───────┤
│a1 │a2 │
│b1 │b2 │
└───────┴───────┘
You can also create your own custom border by subclassing TTY::Table::Border
class MyBorder < TTY::Table::Border
def_border do
{
'bottom' => ' ',
'bottom_mid' => '*',
'bottom_left' => '*',
'bottom_right' => '*',
'left' => '$',
'right' => '$'
}
end
end
Next pass the border to your table
table.renders_with MyBorder
Terminal
To read general terminal properties you can use on of the helpers
term = TTY::Terminal.new
term.width # => 140
term.height # => 60
term.color? # => true or false
term.echo(false) { } # switch off echo for the block
To colorize your output do
term.color.set 'text...', :bold, :red, :on_green # => red bold text on green background
term.color.remove 'text...' # strips off ansi escape sequences
term.color.code :red # ansi escape code for the supplied color
Shell
Main responsibility is to interact with the prompt and provide convenience methods.
Available methods are
shell = TTY::Shell.new
shell.ask # print question
shell.read # read from stdin
shell.say # print message to stdout
shell.confirm # print message(s) in green
shell.warn # print message(s) in yellow
shell.error # print message(s) in red
shell.print_table # print table to stdout
In order to ask question and parse answers:
shell = TTY::Shell.new
answer = shell.ask("What is your name?").read_string
The library provides small DSL to help with parsing and asking precise questions
argument # :required or :optional
character # turn character based input, otherwise line (default: false)
clean # reset question
default # default value used if none is provided
echo # turn echo on and off (default: true)
mask # mask characters i.e '****' (default: false)
modify # apply answer modification :upcase, :downcase, :trim, :chomp etc..
range # specify range '0-9', '0..9', '0...9' or negative '-1..-9'
validate # regex against which stdin input is checked
valid # a list of expected valid options
You can chain question methods or configure them inside a block
shell.ask("What is your name?").argument(:required).default('Piotr').validate(/\w+\s\w+/).read_string
shell.ask "What is your name?" do
argument :required
default 'Piotr'
validate /\w+\s\w+/
valid ['Piotr', 'Piotrek']
modify :capitalize
end.read_string
Reading answers and converting them into required types can be done with custom readers
read_bool # return true or false for strings such as "Yes", "No"
read_date # return date type
read_datetime # return datetime type
read_email # validate answer against email regex
read_float # return decimal or error if cannot convert
read_int # return integer or error if cannot convert
read_multiple # return multiple line string
read_password # return string with echo turned off
read_range # return range type
read_string # return string
For example, if we wanted to ask a user for a single digit in given range
ask("Provide number in range: 0-9") do
range '0-9'
on_error :retry
end.read_int
on the other hand, if we are interested in range answer then
ask("Provide range of numbers?").read_range
System
TTY::System.unix? # => true
TTY::System.windows? # => false
Contributing
- Fork it
- 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 new Pull Request
Copyright
Copyright (c) 2012-2013 Piotr Murach. See LICENSE for further details.