tty 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/README.md +45 -6
- data/lib/tty.rb +23 -2
- data/lib/tty/color.rb +0 -4
- data/lib/tty/support/conversion.rb +34 -0
- data/lib/tty/support/delegatable.rb +44 -0
- data/lib/tty/support/utils.rb +2 -0
- data/lib/tty/system.rb +31 -0
- data/lib/tty/table.rb +155 -20
- data/lib/tty/table/error.rb +10 -0
- data/lib/tty/table/renderer.rb +16 -6
- data/lib/tty/table/renderer/basic.rb +60 -20
- data/lib/tty/table/renderer/color.rb +1 -1
- data/lib/tty/table/renderer/unicode.rb +1 -1
- data/lib/tty/table/validatable.rb +34 -0
- data/lib/tty/terminal.rb +149 -0
- data/lib/tty/version.rb +1 -1
- data/spec/tty/support/conversion_spec.rb +38 -0
- data/spec/tty/support/delegatable_spec.rb +26 -0
- data/spec/tty/support/fixtures/classes.rb +17 -0
- data/spec/tty/system/platform_spec.rb +21 -0
- data/spec/tty/table/access_spec.rb +59 -0
- data/spec/tty/table/eql_spec.rb +28 -0
- data/spec/tty/table/initialize_spec.rb +53 -0
- data/spec/tty/table/properties_spec.rb +24 -0
- data/spec/tty/table/renderer/basic_spec.rb +20 -0
- data/spec/tty/table/renderer_spec.rb +7 -0
- data/spec/tty/table/validatable_spec.rb +19 -0
- data/spec/tty/terminal/size_spec.rb +94 -0
- metadata +34 -11
- data/lib/tty/support/.utils.rb.swo +0 -0
- data/spec/tty/table/table_spec.rb +0 -75
data/README.md
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# TTY
|
2
|
-
[][travis] [][travis] [][codeclimate]
|
3
3
|
|
4
4
|
[travis]: http://travis-ci.org/peter-murach/tty
|
5
|
-
[gemnasium]: https://gemnasium.com/peter-murach/tty
|
6
5
|
[codeclimate]: https://codeclimate.com/github/peter-murach/tty
|
7
6
|
|
8
|
-
Toolbox for developing CLI clients.
|
7
|
+
Toolbox for developing CLI clients in Ruby.
|
9
8
|
|
10
9
|
## Features
|
11
10
|
|
@@ -14,9 +13,11 @@ Jump-start development of your command line app:
|
|
14
13
|
* Fully customizable table rendering with an easy-to-use API.
|
15
14
|
(status: In Progress)
|
16
15
|
* Terminal output colorization. (status: TODO)
|
17
|
-
* Terminal & System detection utilities. (status:
|
16
|
+
* Terminal & System detection utilities. (status: In Progress)
|
18
17
|
* Text alignment/padding and diffs. (status: TODO)
|
19
18
|
* Shell user interface. (status: TODO)
|
19
|
+
* Progress bar. (status: TODO)
|
20
|
+
* Fully tested with major ruby interpreters.
|
20
21
|
* No dependencies to allow for easy gem vendoring.
|
21
22
|
|
22
23
|
## Installation
|
@@ -37,14 +38,22 @@ Or install it yourself as:
|
|
37
38
|
|
38
39
|
### Table
|
39
40
|
|
40
|
-
|
41
|
+
To instantiate table
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
table = TTY::Table.new :rows => [['a1', 'a2'], ['b1', 'b2']]
|
45
|
+
table = TTY::Table[['a1', 'a2'], ['b1', 'b2']]
|
46
|
+
```
|
47
|
+
|
48
|
+
Table behaves like an array so `<<` and similar methods can be used
|
41
49
|
|
42
50
|
```ruby
|
43
|
-
table = TTY::Table.new ['Header 1', 'Header 2']
|
44
51
|
table << ['a1', 'a2', 'a3']
|
45
52
|
table << ['b1', 'b2', 'b3']
|
46
53
|
```
|
47
54
|
|
55
|
+
or pass your rows in a block
|
56
|
+
|
48
57
|
```ruby
|
49
58
|
table = TTY::Table.new header: ['Header 1', 'Header 2'] do |t|
|
50
59
|
t << ['a1', 'a2', 'a3']
|
@@ -52,6 +61,36 @@ Creating tables
|
|
52
61
|
end
|
53
62
|
```
|
54
63
|
|
64
|
+
And then to print do
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
table.to_s # => a1 a2 a3
|
68
|
+
# b1 b2 b3
|
69
|
+
```
|
70
|
+
|
71
|
+
To print `unicode` table
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
table = TTY::Table.new renderer: 'unicode'
|
75
|
+
table.to_s
|
76
|
+
```
|
77
|
+
|
78
|
+
### Terminal
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
term = TTY::Terminal.new
|
82
|
+
term.width # => 140
|
83
|
+
term.height # => 60
|
84
|
+
term.color? # => true or false
|
85
|
+
```
|
86
|
+
|
87
|
+
### System
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
TTY::System.unix? # => true
|
91
|
+
TTY::System.windows? # => false
|
92
|
+
```
|
93
|
+
|
55
94
|
## Contributing
|
56
95
|
|
57
96
|
1. Fork it
|
data/lib/tty.rb
CHANGED
@@ -1,11 +1,32 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
require 'tty/version'
|
4
|
-
require 'tty/table'
|
5
|
-
require 'tty/color'
|
6
4
|
|
7
5
|
require 'tty/support/utils'
|
6
|
+
require 'tty/support/delegatable'
|
7
|
+
require 'tty/support/conversion'
|
8
|
+
|
9
|
+
require 'tty/color'
|
10
|
+
require 'tty/terminal'
|
11
|
+
require 'tty/system'
|
12
|
+
require 'tty/table'
|
8
13
|
|
9
14
|
module TTY
|
10
15
|
|
16
|
+
# Raised when the argument type is different from expected
|
17
|
+
class TypeError < ArgumentError; end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
# Return terminal instance
|
22
|
+
#
|
23
|
+
# @return [TTY::Terminal]
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def terminal
|
27
|
+
@terminal ||= Terminal.new
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
11
32
|
end # TTY
|
data/lib/tty/color.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
# A mixin to allow instances conversion to different types
|
5
|
+
module Conversion
|
6
|
+
|
7
|
+
# Converts the object into an Array. If copy is set to true
|
8
|
+
# a copy of object will be made.
|
9
|
+
#
|
10
|
+
# @param [Object] object
|
11
|
+
#
|
12
|
+
# @param [Boolean] copy
|
13
|
+
#
|
14
|
+
# @return [Array]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def convert_to_array(object, copy=false)
|
18
|
+
case object
|
19
|
+
when Array
|
20
|
+
copy ? object.dup : object
|
21
|
+
when Hash
|
22
|
+
Array(object)
|
23
|
+
else
|
24
|
+
begin
|
25
|
+
converted = object.to_ary
|
26
|
+
rescue Exception => e
|
27
|
+
raise TTY::TypeError, "Cannot convert #{object.class} into an Array (#{e.message})"
|
28
|
+
end
|
29
|
+
converted
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end # Conversion
|
34
|
+
end # TTY
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
# A mixin to allow delegetable methods to be added
|
5
|
+
module Delegatable
|
6
|
+
|
7
|
+
# Create delegator for each specified method
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# delegatable_method :source, :method
|
11
|
+
#
|
12
|
+
# @param [Symbol] source
|
13
|
+
#
|
14
|
+
# @param [Array] methods
|
15
|
+
#
|
16
|
+
# @return [self]
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
def delegatable_method(source, *methods)
|
20
|
+
methods.each { |method| define_delegatable_method(source, method)}
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Create a delegator method for the method name
|
27
|
+
#
|
28
|
+
# @param [Symbol] source
|
29
|
+
#
|
30
|
+
# @param [Symbol] method name
|
31
|
+
#
|
32
|
+
# @return [undefined]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
def define_delegatable_method(source, method)
|
36
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
37
|
+
def #{method}(*args, &block)
|
38
|
+
#{source}.#{method}(*args, &block)
|
39
|
+
end
|
40
|
+
RUBY
|
41
|
+
end
|
42
|
+
|
43
|
+
end # Delegatable
|
44
|
+
end # TTY
|
data/lib/tty/support/utils.rb
CHANGED
data/lib/tty/system.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
module TTY
|
6
|
+
class System
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Check if windows platform.
|
11
|
+
#
|
12
|
+
# @return [Boolean]
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def windows?
|
16
|
+
RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/
|
17
|
+
end
|
18
|
+
|
19
|
+
# Check if unix platform
|
20
|
+
#
|
21
|
+
# @return [Boolean]
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
def unix?
|
25
|
+
RbConfig::CONFIG['host_os'] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end # System
|
31
|
+
end # TTY
|
data/lib/tty/table.rb
CHANGED
@@ -2,10 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'forwardable'
|
4
4
|
require 'tty/table/renderer'
|
5
|
+
require 'tty/table/error'
|
6
|
+
require 'tty/table/validatable'
|
5
7
|
|
6
8
|
module TTY
|
7
9
|
class Table
|
8
|
-
include Comparable, Enumerable, Renderer
|
10
|
+
include Comparable, Enumerable, Renderer, Conversion
|
11
|
+
include Validatable
|
9
12
|
extend Forwardable
|
10
13
|
|
11
14
|
# The table header
|
@@ -34,6 +37,16 @@ module TTY
|
|
34
37
|
# TODO implement table orientation
|
35
38
|
end
|
36
39
|
|
40
|
+
# Create a new Table where each argument is a row
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# table = TTY::Table.new[['a1', 'a2'], ['b1', 'b2']]
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
def self.[](*rows)
|
47
|
+
self.new(:rows => rows)
|
48
|
+
end
|
49
|
+
|
37
50
|
# Instantiate a new Table
|
38
51
|
#
|
39
52
|
# @example of direct parameters
|
@@ -44,6 +57,8 @@ module TTY
|
|
44
57
|
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
45
58
|
# table = Table.new :header => ['Header 1', 'Header 2'], :rows => rows
|
46
59
|
#
|
60
|
+
# @param [Array[Symbol], Hash] *args
|
61
|
+
#
|
47
62
|
# @api public
|
48
63
|
def self.new(*args, &block)
|
49
64
|
options = Utils.extract_options!(args)
|
@@ -58,28 +73,105 @@ module TTY
|
|
58
73
|
# Initialize a Table
|
59
74
|
#
|
60
75
|
# @param [Hash] options
|
76
|
+
# the options to create the table with
|
77
|
+
# @option options [String] :header
|
78
|
+
# column names to be displayed
|
79
|
+
# @option options [String] :rows
|
80
|
+
# Array of Arrays expressin the rows
|
81
|
+
# @option options [String] :renderer
|
82
|
+
# used to format table output
|
83
|
+
#
|
61
84
|
# @return [Table]
|
62
85
|
#
|
63
86
|
# @api private
|
64
87
|
def initialize(options={}, &block)
|
65
88
|
@header = options.fetch :header, []
|
66
|
-
@rows = options.fetch :rows, []
|
89
|
+
@rows = coerce(options.fetch :rows, [])
|
67
90
|
@renderer = pick_renderer options[:renderer]
|
91
|
+
assert_row_sizes @rows
|
68
92
|
yield_or_eval &block if block_given?
|
69
93
|
end
|
70
94
|
|
71
|
-
# Lookup
|
95
|
+
# Lookup element of the table given a row(i) and column(j)
|
72
96
|
#
|
73
|
-
|
74
|
-
|
75
|
-
|
97
|
+
# @api public
|
98
|
+
def [](i, j)
|
99
|
+
if i >= 0 && j >= 0
|
100
|
+
rows.fetch(i){return nil}[j]
|
76
101
|
else
|
77
102
|
raise IndexError.new("index #{index} not found")
|
78
103
|
end
|
79
104
|
end
|
105
|
+
alias element []
|
106
|
+
alias component []
|
107
|
+
|
108
|
+
# Set table value at row(i) and column(j)
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
def []=(i, j, val)
|
112
|
+
@rows[i][j] = val
|
113
|
+
end
|
114
|
+
private :[]=
|
115
|
+
|
116
|
+
# Return a row number at the index of the table as an Array.
|
117
|
+
# When a block is given, the elements of that Array are iterated over.
|
118
|
+
#
|
119
|
+
# @example
|
120
|
+
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
121
|
+
# table = TTY::Table.new :rows => rows
|
122
|
+
# table.row(1) { |element| ... }
|
123
|
+
#
|
124
|
+
# @param [Integer] index
|
125
|
+
#
|
126
|
+
# @yield []
|
127
|
+
# optional block to execute in the iteration operation
|
128
|
+
#
|
129
|
+
# @return [self]
|
130
|
+
#
|
131
|
+
# @api public
|
132
|
+
def row(index, &block)
|
133
|
+
if block_given?
|
134
|
+
rows.fetch(index){return self}.each(&block)
|
135
|
+
self
|
136
|
+
else
|
137
|
+
rows.fetch(index){return nil}
|
138
|
+
end
|
139
|
+
end
|
80
140
|
|
141
|
+
# Return a column number at the index of the table as an Array.
|
142
|
+
# When a block is given, the elements of that Array are iterated over.
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
146
|
+
# table = TTY::Table.new :rows => rows
|
147
|
+
# table.column(1) { |element| ... }
|
148
|
+
#
|
149
|
+
# @param [Integer] index
|
150
|
+
#
|
151
|
+
# @yield []
|
152
|
+
# optional block to execute in the iteration operation
|
153
|
+
#
|
154
|
+
# @return [self]
|
155
|
+
#
|
156
|
+
# @api public
|
157
|
+
def column(index)
|
158
|
+
if block_given?
|
159
|
+
return self if index >= column_size || index < 0
|
160
|
+
rows.map { |row| yield row[index].compact }
|
161
|
+
else
|
162
|
+
return nil if index >= column_size || index < 0
|
163
|
+
rows.map { |row| row[index] }.compact
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Add row to table
|
168
|
+
#
|
169
|
+
# @param [Array] row
|
170
|
+
#
|
81
171
|
# @api public
|
82
172
|
def <<(row)
|
173
|
+
rows_copy = rows.dup
|
174
|
+
assert_row_sizes rows_copy << row
|
83
175
|
rows << row
|
84
176
|
end
|
85
177
|
|
@@ -87,11 +179,12 @@ module TTY
|
|
87
179
|
#
|
88
180
|
# @example
|
89
181
|
# table = TTY::Table.new(header, tuples)
|
90
|
-
# table.each { |
|
182
|
+
# table.each { |row| ... }
|
91
183
|
#
|
92
|
-
# @yield [
|
184
|
+
# @yield [Array[Array]]
|
93
185
|
#
|
94
186
|
# @return [self]
|
187
|
+
#
|
95
188
|
# @api public
|
96
189
|
def each
|
97
190
|
return to_enum unless block_given?
|
@@ -101,22 +194,62 @@ module TTY
|
|
101
194
|
self
|
102
195
|
end
|
103
196
|
|
197
|
+
# Return the number of columns
|
198
|
+
#
|
199
|
+
# @example
|
200
|
+
# table.column_size # => 5
|
201
|
+
#
|
202
|
+
# @return [Integer]
|
203
|
+
#
|
204
|
+
# @api public
|
205
|
+
def column_size
|
206
|
+
return rows[0].size if (rows.size > 0)
|
207
|
+
return 0
|
208
|
+
end
|
209
|
+
|
104
210
|
# Return the number of rows
|
105
211
|
#
|
106
212
|
# @example
|
107
|
-
# table.
|
213
|
+
# table.row_size # => 5
|
108
214
|
#
|
109
215
|
# @return [Integer]
|
216
|
+
#
|
217
|
+
# @api public
|
218
|
+
def row_size
|
219
|
+
rows.size
|
220
|
+
end
|
221
|
+
|
222
|
+
# Return the number of rows and columns
|
223
|
+
#
|
224
|
+
# @example
|
225
|
+
# table.size # => [3,5]
|
226
|
+
#
|
227
|
+
# @return [Array] row x columns
|
228
|
+
#
|
229
|
+
# @api public
|
110
230
|
def size
|
111
|
-
|
112
|
-
return 0
|
231
|
+
[row_size, column_size]
|
113
232
|
end
|
114
233
|
|
115
234
|
# Check table width
|
116
235
|
#
|
117
236
|
# @return [Integer] width
|
237
|
+
#
|
238
|
+
# @api public
|
118
239
|
def width
|
119
|
-
|
240
|
+
extract_column_widths(rows)
|
241
|
+
total_width
|
242
|
+
end
|
243
|
+
|
244
|
+
# Compare this table with other table for equality
|
245
|
+
#
|
246
|
+
# @param [TTY::Table] other
|
247
|
+
#
|
248
|
+
# @return [Boolean]
|
249
|
+
#
|
250
|
+
# @api public
|
251
|
+
def eql?(other)
|
252
|
+
instance_of?(other.class)
|
120
253
|
end
|
121
254
|
|
122
255
|
# Compare the table with other table for equivalency
|
@@ -135,23 +268,25 @@ module TTY
|
|
135
268
|
|
136
269
|
# Return string representation of table
|
137
270
|
#
|
271
|
+
# @return [String]
|
272
|
+
#
|
138
273
|
# @api public
|
139
274
|
def to_s
|
140
|
-
|
275
|
+
render(rows)
|
141
276
|
end
|
142
277
|
|
143
278
|
# Coerce an Enumerable into a Table
|
279
|
+
# This coercion mechanism is used by Table to handle Enumerable types
|
280
|
+
# and force them into array type.
|
144
281
|
#
|
145
282
|
# @param [Enumerable] object
|
146
283
|
# the object to coerce
|
147
284
|
#
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
array << object.values
|
154
|
-
end
|
285
|
+
# @return [Array]
|
286
|
+
#
|
287
|
+
# @api public
|
288
|
+
def coerce(rows)
|
289
|
+
convert_to_array(rows)
|
155
290
|
end
|
156
291
|
|
157
292
|
private
|