tty-table 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +22 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +389 -0
- data/Rakefile +8 -0
- data/benchmarks/speed.rb +36 -0
- data/lib/tty/table/border/ascii.rb +32 -0
- data/lib/tty/table/border/null.rb +37 -0
- data/lib/tty/table/border/row_line.rb +18 -0
- data/lib/tty/table/border/unicode.rb +32 -0
- data/lib/tty/table/border.rb +219 -0
- data/lib/tty/table/border_dsl.rb +251 -0
- data/lib/tty/table/border_options.rb +53 -0
- data/lib/tty/table/column_set.rb +121 -0
- data/lib/tty/table/columns.rb +170 -0
- data/lib/tty/table/empty.rb +26 -0
- data/lib/tty/table/error.rb +39 -0
- data/lib/tty/table/field.rb +139 -0
- data/lib/tty/table/header.rb +163 -0
- data/lib/tty/table/indentation.rb +52 -0
- data/lib/tty/table/operation/alignment_set.rb +103 -0
- data/lib/tty/table/operation/escape.rb +30 -0
- data/lib/tty/table/operation/filter.rb +34 -0
- data/lib/tty/table/operation/padding.rb +95 -0
- data/lib/tty/table/operation/truncation.rb +41 -0
- data/lib/tty/table/operation/wrapped.rb +43 -0
- data/lib/tty/table/operations.rb +69 -0
- data/lib/tty/table/options.rb +30 -0
- data/lib/tty/table/orientation/horizontal.rb +48 -0
- data/lib/tty/table/orientation/vertical.rb +38 -0
- data/lib/tty/table/orientation.rb +57 -0
- data/lib/tty/table/padder.rb +180 -0
- data/lib/tty/table/renderer/ascii.rb +16 -0
- data/lib/tty/table/renderer/basic.rb +294 -0
- data/lib/tty/table/renderer/color.rb +12 -0
- data/lib/tty/table/renderer/unicode.rb +21 -0
- data/lib/tty/table/renderer.rb +101 -0
- data/lib/tty/table/row.rb +248 -0
- data/lib/tty/table/transformation.rb +39 -0
- data/lib/tty/table/validatable.rb +64 -0
- data/lib/tty/table/version.rb +7 -0
- data/lib/tty/table.rb +469 -0
- data/lib/tty-table.rb +48 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/unit/access_spec.rb +86 -0
- data/spec/unit/add_row_spec.rb +28 -0
- data/spec/unit/border/ascii/rendering_spec.rb +90 -0
- data/spec/unit/border/new_spec.rb +27 -0
- data/spec/unit/border/null/rendering_spec.rb +130 -0
- data/spec/unit/border/options/from_spec.rb +38 -0
- data/spec/unit/border/options/new_spec.rb +14 -0
- data/spec/unit/border/unicode/rendering_spec.rb +63 -0
- data/spec/unit/border_options/new_spec.rb +20 -0
- data/spec/unit/border_options/update_spec.rb +18 -0
- data/spec/unit/column_set/extract_widths_spec.rb +15 -0
- data/spec/unit/column_set/total_width_spec.rb +15 -0
- data/spec/unit/column_set/widths_from_spec.rb +51 -0
- data/spec/unit/columns/enforce_spec.rb +67 -0
- data/spec/unit/columns/widths_spec.rb +35 -0
- data/spec/unit/data_spec.rb +14 -0
- data/spec/unit/each_spec.rb +41 -0
- data/spec/unit/each_with_index_spec.rb +57 -0
- data/spec/unit/empty_spec.rb +23 -0
- data/spec/unit/eql_spec.rb +34 -0
- data/spec/unit/field/equality_spec.rb +51 -0
- data/spec/unit/field/length_spec.rb +21 -0
- data/spec/unit/field/lines_spec.rb +21 -0
- data/spec/unit/field/new_spec.rb +29 -0
- data/spec/unit/field/width_spec.rb +23 -0
- data/spec/unit/filter_spec.rb +23 -0
- data/spec/unit/header/call_spec.rb +30 -0
- data/spec/unit/header/color_spec.rb +19 -0
- data/spec/unit/header/equality_spec.rb +51 -0
- data/spec/unit/header/height_spec.rb +27 -0
- data/spec/unit/header/new_spec.rb +25 -0
- data/spec/unit/header/set_spec.rb +20 -0
- data/spec/unit/header/to_ary_spec.rb +14 -0
- data/spec/unit/header_spec.rb +13 -0
- data/spec/unit/indentation/insert_indent_spec.rb +27 -0
- data/spec/unit/initialize_spec.rb +88 -0
- data/spec/unit/operation/alignment_set/call_spec.rb +39 -0
- data/spec/unit/operation/alignment_set/each_spec.rb +17 -0
- data/spec/unit/operation/alignment_set/new_spec.rb +27 -0
- data/spec/unit/operation/alignment_set/to_ary_spec.rb +14 -0
- data/spec/unit/operation/escape/call_spec.rb +16 -0
- data/spec/unit/operation/filter/call_spec.rb +17 -0
- data/spec/unit/operation/truncation/call_spec.rb +32 -0
- data/spec/unit/operation/wrapped/call_spec.rb +33 -0
- data/spec/unit/operations/new_spec.rb +30 -0
- data/spec/unit/options/access_spec.rb +14 -0
- data/spec/unit/options_spec.rb +25 -0
- data/spec/unit/orientation_spec.rb +145 -0
- data/spec/unit/padder/parse_spec.rb +45 -0
- data/spec/unit/padder/to_s_spec.rb +14 -0
- data/spec/unit/padding_spec.rb +120 -0
- data/spec/unit/properties_spec.rb +25 -0
- data/spec/unit/render_spec.rb +63 -0
- data/spec/unit/render_with_spec.rb +106 -0
- data/spec/unit/renderer/ascii/indentation_spec.rb +41 -0
- data/spec/unit/renderer/ascii/padding_spec.rb +61 -0
- data/spec/unit/renderer/ascii/render_spec.rb +68 -0
- data/spec/unit/renderer/ascii/resizing_spec.rb +114 -0
- data/spec/unit/renderer/ascii/separator_spec.rb +28 -0
- data/spec/unit/renderer/basic/alignment_spec.rb +88 -0
- data/spec/unit/renderer/basic/coloring_spec.rb +46 -0
- data/spec/unit/renderer/basic/extract_column_widths_spec.rb +28 -0
- data/spec/unit/renderer/basic/filter_spec.rb +53 -0
- data/spec/unit/renderer/basic/indentation_spec.rb +48 -0
- data/spec/unit/renderer/basic/multiline_content_spec.rb +135 -0
- data/spec/unit/renderer/basic/new_spec.rb +26 -0
- data/spec/unit/renderer/basic/options_spec.rb +52 -0
- data/spec/unit/renderer/basic/padding_spec.rb +52 -0
- data/spec/unit/renderer/basic/render_spec.rb +57 -0
- data/spec/unit/renderer/basic/resizing_spec.rb +96 -0
- data/spec/unit/renderer/basic/separator_spec.rb +43 -0
- data/spec/unit/renderer/basic/truncation_spec.rb +35 -0
- data/spec/unit/renderer/basic/wrapping_spec.rb +40 -0
- data/spec/unit/renderer/border_spec.rb +104 -0
- data/spec/unit/renderer/render_spec.rb +36 -0
- data/spec/unit/renderer/select_spec.rb +22 -0
- data/spec/unit/renderer/style_spec.rb +72 -0
- data/spec/unit/renderer/unicode/indentation_spec.rb +41 -0
- data/spec/unit/renderer/unicode/padding_spec.rb +61 -0
- data/spec/unit/renderer/unicode/render_spec.rb +68 -0
- data/spec/unit/renderer/unicode/separator_spec.rb +26 -0
- data/spec/unit/renderer_spec.rb +19 -0
- data/spec/unit/rotate_spec.rb +86 -0
- data/spec/unit/row/access_spec.rb +25 -0
- data/spec/unit/row/call_spec.rb +45 -0
- data/spec/unit/row/data_spec.rb +26 -0
- data/spec/unit/row/each_spec.rb +31 -0
- data/spec/unit/row/equality_spec.rb +73 -0
- data/spec/unit/row/height_spec.rb +27 -0
- data/spec/unit/row/new_spec.rb +41 -0
- data/spec/unit/row/to_ary_spec.rb +14 -0
- data/spec/unit/to_s_spec.rb +63 -0
- data/spec/unit/transformation/extract_tuples_spec.rb +35 -0
- data/spec/unit/validatable/validate_options_spec.rb +33 -0
- data/spec/unit/validatable_spec.rb +32 -0
- data/tasks/console.rake +10 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +29 -0
- data/tty-table.gemspec +28 -0
- metadata +371 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Table
|
5
|
+
# Mixin to provide validation for {Table}.
|
6
|
+
#
|
7
|
+
# Include this mixin to add validation for options.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
module Validatable
|
11
|
+
# Check if table rows are the equal size
|
12
|
+
#
|
13
|
+
# @raise [DimensionMismatchError]
|
14
|
+
# if the rows are not equal length
|
15
|
+
#
|
16
|
+
# @return [nil]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
def assert_row_sizes(rows)
|
20
|
+
size = (rows[0] || []).size
|
21
|
+
rows.each do |row|
|
22
|
+
next if row.size == size
|
23
|
+
fail TTY::Table::DimensionMismatchError,
|
24
|
+
"row size differs (#{row.size} should be #{size})"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Check if table type is provided
|
29
|
+
#
|
30
|
+
# @raise [ArgumentRequired]
|
31
|
+
#
|
32
|
+
# @return [Table]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
def assert_table_type(value)
|
36
|
+
return value if value.is_a?(TTY::Table)
|
37
|
+
fail ArgumentRequired,
|
38
|
+
"Expected TTY::Table instance, got #{value.inspect}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# def assert_matching_widths(rows)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# def assert_string_values(rows)
|
45
|
+
# end
|
46
|
+
|
47
|
+
# Check if options are of required type
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
def validate_options!(options)
|
51
|
+
header = options[:header]
|
52
|
+
rows = options[:rows]
|
53
|
+
|
54
|
+
if header && (!header.is_a?(Array) || header.empty?)
|
55
|
+
fail InvalidArgument, ':header must be a non-empty array'
|
56
|
+
end
|
57
|
+
|
58
|
+
if rows && !(rows.is_a?(Array) || rows.is_a?(Hash))
|
59
|
+
fail InvalidArgument, ':rows must be a non-empty array or hash'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end # Validatable
|
63
|
+
end # Table
|
64
|
+
end # TTY
|
data/lib/tty/table.rb
ADDED
@@ -0,0 +1,469 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
# A core class intended for storing data in a structured, tabular form.
|
5
|
+
# Once the data is stored in a TTY::Table various operations can be performed
|
6
|
+
# before the information is dumped into a stdout.
|
7
|
+
class Table
|
8
|
+
include Comparable, Enumerable, Validatable, Equatable
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
# The table header
|
12
|
+
#
|
13
|
+
# @return [Enumerable]
|
14
|
+
#
|
15
|
+
# @api public
|
16
|
+
attr_reader :header
|
17
|
+
|
18
|
+
# The table rows
|
19
|
+
#
|
20
|
+
# @return [Enumerable]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
attr_reader :rows
|
24
|
+
# private :rows
|
25
|
+
|
26
|
+
# The table orientation out of :horizontal and :vertical
|
27
|
+
#
|
28
|
+
# @reutrn [TTY::Table::Orientation]
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
attr_reader :orientation
|
32
|
+
|
33
|
+
# The table original row count
|
34
|
+
#
|
35
|
+
# @reutrn [Integer]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
attr_reader :original_rows
|
39
|
+
|
40
|
+
# The table original column count
|
41
|
+
#
|
42
|
+
# @reutrn [Integer]
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
attr_reader :original_columns
|
46
|
+
|
47
|
+
# Subset of safe methods that both Array and Hash implement
|
48
|
+
def_delegators(:data, :assoc, :flatten, :include?, :index,
|
49
|
+
:length, :select, :to_a, :values_at, :pretty_print, :rassoc)
|
50
|
+
|
51
|
+
# Create a new Table where each argument is a row
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# table = TTY::Table[['a1', 'a2'], ['b1', 'b2']]
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def self.[](*rows)
|
58
|
+
new(rows: rows)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Instantiate a new Table
|
62
|
+
#
|
63
|
+
# @example of no header
|
64
|
+
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
65
|
+
# table = Table.new rows
|
66
|
+
#
|
67
|
+
# @example of direct parameters
|
68
|
+
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
69
|
+
# table = Table.new ['Header 1', 'Header 2'], rows
|
70
|
+
#
|
71
|
+
# @example of parameters passed as options
|
72
|
+
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
73
|
+
# table = Table.new header: ['Header 1', 'Header 2'], rows: rows
|
74
|
+
#
|
75
|
+
# @example of parameters passed as hash
|
76
|
+
# Table.new [ {'Header1' => ['a1','a2'], 'Header2' => ['b1', 'b2'] }] }
|
77
|
+
#
|
78
|
+
# @param [Array[Symbol], Hash] *args
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
def self.new(*args, &block)
|
82
|
+
options = args.last.respond_to?(:to_hash) ? args.pop : {}
|
83
|
+
if args.size.nonzero?
|
84
|
+
super(Transformation.extract_tuples(args).merge(options), &block)
|
85
|
+
else
|
86
|
+
super(options, &block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Initialize a Table
|
91
|
+
#
|
92
|
+
# @param [Hash] options
|
93
|
+
# the options to create the table with
|
94
|
+
# @option options [String] :header
|
95
|
+
# column names to be displayed
|
96
|
+
# @option options [String] :rows
|
97
|
+
# Array of Arrays expressing the rows
|
98
|
+
# @option options [Symbol] :orientation
|
99
|
+
# used to transform table orientation
|
100
|
+
#
|
101
|
+
# @return [TTY::Table]
|
102
|
+
#
|
103
|
+
# @api private
|
104
|
+
def initialize(options = {}, &block)
|
105
|
+
validate_options! options
|
106
|
+
@converter = Necromancer.new
|
107
|
+
@header = (value = options[:header]) ? Header.new(value) : nil
|
108
|
+
@rows = coerce(options.fetch(:rows) { Row.new([]) })
|
109
|
+
@rotated = false
|
110
|
+
self.orientation = options.fetch(:orientation) { :horizontal }
|
111
|
+
|
112
|
+
assert_row_sizes @rows
|
113
|
+
orientation.transform(self)
|
114
|
+
|
115
|
+
yield_or_eval(&block) if block_given?
|
116
|
+
end
|
117
|
+
|
118
|
+
# Provides access to all table data
|
119
|
+
#
|
120
|
+
# @return [Array]
|
121
|
+
#
|
122
|
+
# @api public
|
123
|
+
def data
|
124
|
+
(header && !header.empty?) ? [header] + rows : rows
|
125
|
+
end
|
126
|
+
|
127
|
+
# Sets table orientation
|
128
|
+
#
|
129
|
+
# @param [String,Symbol] value
|
130
|
+
#
|
131
|
+
# @api public
|
132
|
+
def orientation=(value)
|
133
|
+
@orientation = Orientation.coerce(value)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Marks this table as rotated
|
137
|
+
#
|
138
|
+
# @return [Boolean]
|
139
|
+
#
|
140
|
+
# @api public
|
141
|
+
def rotated?
|
142
|
+
@rotated
|
143
|
+
end
|
144
|
+
|
145
|
+
# Rotate the table between vertical and horizontal orientation
|
146
|
+
#
|
147
|
+
# @return [self]
|
148
|
+
#
|
149
|
+
# @api private
|
150
|
+
def rotate
|
151
|
+
orientation.transform(self)
|
152
|
+
self
|
153
|
+
end
|
154
|
+
|
155
|
+
# Rotate the table vertically
|
156
|
+
#
|
157
|
+
# @api private
|
158
|
+
def rotate_vertical
|
159
|
+
@original_columns = column_size
|
160
|
+
@original_rows = row_size
|
161
|
+
@rows = orientation.slice(self)
|
162
|
+
@header = [] if header
|
163
|
+
@rotated = true
|
164
|
+
end
|
165
|
+
|
166
|
+
# Rotate the table horizontally
|
167
|
+
#
|
168
|
+
# @api private
|
169
|
+
def rotate_horizontal
|
170
|
+
return unless rotated?
|
171
|
+
head, body = orientation.slice(self)
|
172
|
+
if header && header.empty?
|
173
|
+
@header = head[0]
|
174
|
+
@rows = body.map { |row| to_row(row, @header) }
|
175
|
+
else
|
176
|
+
@rows = body.map { |row| to_row(row) }
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Lookup element of the table given a row(i) and column(j)
|
181
|
+
#
|
182
|
+
# @api public
|
183
|
+
def [](row_index, column_index = false)
|
184
|
+
return row(row_index) unless column_index
|
185
|
+
if row_index >= 0 && column_index >= 0
|
186
|
+
rows.fetch(row_index) { return nil }[column_index]
|
187
|
+
else
|
188
|
+
fail TTY::Table::TupleMissing.new(row_index, column_index)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
alias at []
|
192
|
+
alias element []
|
193
|
+
alias component []
|
194
|
+
|
195
|
+
# Set table value at row(i) and column(j)
|
196
|
+
#
|
197
|
+
# @api private
|
198
|
+
def []=(row_index, column_index, val)
|
199
|
+
@rows[row_index][column_index] = val
|
200
|
+
end
|
201
|
+
private :[]=
|
202
|
+
|
203
|
+
# Return a row number at the index of the table as an Array.
|
204
|
+
# When a block is given, the elements of that Array are iterated over.
|
205
|
+
#
|
206
|
+
# @example
|
207
|
+
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
208
|
+
# table = TTY::Table.new :rows => rows
|
209
|
+
# table.row(1) { |element| ... }
|
210
|
+
#
|
211
|
+
# @param [Integer] index
|
212
|
+
#
|
213
|
+
# @yield []
|
214
|
+
# optional block to execute in the iteration operation
|
215
|
+
#
|
216
|
+
# @return [self]
|
217
|
+
#
|
218
|
+
# @api public
|
219
|
+
def row(index, &block)
|
220
|
+
if block_given?
|
221
|
+
rows.fetch(index) { return self }.each(&block)
|
222
|
+
self
|
223
|
+
else
|
224
|
+
rows.fetch(index) { return nil }
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Return a column number at the index of the table as an Array.
|
229
|
+
# If the table has a header then column can be searched by header name.
|
230
|
+
# When a block is given, the elements of that Array are iterated over.
|
231
|
+
#
|
232
|
+
# @example
|
233
|
+
# header = [:h1, :h2]
|
234
|
+
# rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
|
235
|
+
# table = TTY::Table.new :rows => rows, :header => header
|
236
|
+
# table.column(1)
|
237
|
+
# table.column(1) { |element| ... }
|
238
|
+
# table.column(:h1)
|
239
|
+
# table.column(:h1) { |element| ... }
|
240
|
+
#
|
241
|
+
# @param [Integer, String, Symbol] index
|
242
|
+
#
|
243
|
+
# @yield []
|
244
|
+
# optional block to execute in the iteration operation
|
245
|
+
#
|
246
|
+
# @return [self]
|
247
|
+
#
|
248
|
+
# @api public
|
249
|
+
def column(index)
|
250
|
+
index_unknown = index.is_a?(Integer) && (index >= column_size || index < 0)
|
251
|
+
if block_given?
|
252
|
+
return self if index_unknown
|
253
|
+
rows.map { |row| yield row[index] }
|
254
|
+
else
|
255
|
+
return nil if index_unknown
|
256
|
+
rows.map { |row| row[index] }.compact
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Add row to table
|
261
|
+
#
|
262
|
+
# @param [Array] row
|
263
|
+
#
|
264
|
+
# @return [self]
|
265
|
+
#
|
266
|
+
# @api public
|
267
|
+
def <<(row)
|
268
|
+
rows_copy = rows.dup
|
269
|
+
assert_row_sizes rows_copy << row
|
270
|
+
rows << to_row(row)
|
271
|
+
self
|
272
|
+
end
|
273
|
+
|
274
|
+
# Iterate over each tuple in the set
|
275
|
+
#
|
276
|
+
# @example
|
277
|
+
# table = TTY::Table.new(header, tuples)
|
278
|
+
# table.each { |row| ... }
|
279
|
+
#
|
280
|
+
# @yield [Array[Array]]
|
281
|
+
#
|
282
|
+
# @return [self]
|
283
|
+
#
|
284
|
+
# @api public
|
285
|
+
def each
|
286
|
+
return to_enum unless block_given?
|
287
|
+
data.each { |row| yield row }
|
288
|
+
self
|
289
|
+
end
|
290
|
+
|
291
|
+
# Iterate over each element yielding in addition row and column index
|
292
|
+
#
|
293
|
+
# @example
|
294
|
+
# table = TTY::Table.new(header, tuples)
|
295
|
+
# table.each_with_index { |el, row, col| puts "#{el} at #{row},#{col}" }
|
296
|
+
#
|
297
|
+
# @return self
|
298
|
+
#
|
299
|
+
# @api public
|
300
|
+
def each_with_index
|
301
|
+
return to_enum unless block_given?
|
302
|
+
start_index = 0
|
303
|
+
if header && !header.empty?
|
304
|
+
header.attributes.each_with_index do |el, col_index|
|
305
|
+
yield el, 0, col_index
|
306
|
+
end
|
307
|
+
start_index = 1
|
308
|
+
end
|
309
|
+
|
310
|
+
rows.each_with_index do |row, row_index|
|
311
|
+
row.fields.each_with_index do |el, col_index|
|
312
|
+
yield el, row_index + start_index, col_index
|
313
|
+
end
|
314
|
+
end
|
315
|
+
self
|
316
|
+
end
|
317
|
+
|
318
|
+
# Return the number of columns
|
319
|
+
#
|
320
|
+
# @example
|
321
|
+
# table.column_size # => 5
|
322
|
+
#
|
323
|
+
# @return [Integer]
|
324
|
+
#
|
325
|
+
# @api public
|
326
|
+
# TODO: renmae to columns_size
|
327
|
+
def column_size
|
328
|
+
rows.size > 0 ? rows[0].size : 0
|
329
|
+
end
|
330
|
+
|
331
|
+
# Return the number of rows
|
332
|
+
#
|
333
|
+
# @example
|
334
|
+
# table.row_size # => 5
|
335
|
+
#
|
336
|
+
# @return [Integer]
|
337
|
+
#
|
338
|
+
# @api public
|
339
|
+
def row_size
|
340
|
+
rows.size
|
341
|
+
end
|
342
|
+
|
343
|
+
# Return the number of rows and columns
|
344
|
+
#
|
345
|
+
# @example
|
346
|
+
# table.size # => [3,5]
|
347
|
+
#
|
348
|
+
# @return [Array] row x columns
|
349
|
+
#
|
350
|
+
# @api public
|
351
|
+
def size
|
352
|
+
[row_size, column_size]
|
353
|
+
end
|
354
|
+
|
355
|
+
# Check table width
|
356
|
+
#
|
357
|
+
# @return [Integer] width
|
358
|
+
#
|
359
|
+
# @api public
|
360
|
+
def width
|
361
|
+
ColumnSet.new(self).total_width
|
362
|
+
end
|
363
|
+
|
364
|
+
# Return true if this is an empty table, i.e. if the number of
|
365
|
+
# rows or the number of columns is 0
|
366
|
+
#
|
367
|
+
# @return [Boolean]
|
368
|
+
#
|
369
|
+
# @api public
|
370
|
+
def empty?
|
371
|
+
column_size == 0 || row_size == 0
|
372
|
+
end
|
373
|
+
|
374
|
+
# Return string representation of table using basic renderer.
|
375
|
+
#
|
376
|
+
# @return [String]
|
377
|
+
#
|
378
|
+
# @api public
|
379
|
+
def to_s
|
380
|
+
render(:basic)
|
381
|
+
end
|
382
|
+
|
383
|
+
# Return renderer for this table
|
384
|
+
#
|
385
|
+
# @param [Symbol] type
|
386
|
+
# the renderer type
|
387
|
+
#
|
388
|
+
# @param [Hash] options
|
389
|
+
# the renderer options
|
390
|
+
#
|
391
|
+
def renderer(type = :basic, options = {})
|
392
|
+
@renderer ||= Renderer.select(type).new(self, options)
|
393
|
+
end
|
394
|
+
|
395
|
+
# Render a given table. This method takes options which will be passed
|
396
|
+
# to the renderer prior to rendering, which allows the caller to set any
|
397
|
+
# table rendering variables.
|
398
|
+
#
|
399
|
+
# @param [Symbol] renderer_type
|
400
|
+
# the renderer to be used
|
401
|
+
#
|
402
|
+
# @param [Hash] options
|
403
|
+
#
|
404
|
+
# @yield [renderer]
|
405
|
+
#
|
406
|
+
# @yieldparam [TTY::Table::Renderer] renderer
|
407
|
+
# the renderer for the table
|
408
|
+
#
|
409
|
+
# @return [String]
|
410
|
+
#
|
411
|
+
# @api public
|
412
|
+
def render(*args, &block)
|
413
|
+
render_with(nil, *args, &block)
|
414
|
+
end
|
415
|
+
|
416
|
+
# Render a given table using custom border class.
|
417
|
+
#
|
418
|
+
# @param [TTY::Table::Border]
|
419
|
+
#
|
420
|
+
# @param [Symbol] renderer_type
|
421
|
+
#
|
422
|
+
# @yield [renderer]
|
423
|
+
#
|
424
|
+
# @yieldparam [TTY::Table::Renderer] renderer
|
425
|
+
# the renderer for the table
|
426
|
+
#
|
427
|
+
# @return [String]
|
428
|
+
#
|
429
|
+
# @api public
|
430
|
+
def render_with(border_class, renderer_type=(not_set=true), options={}, &block)
|
431
|
+
unless not_set
|
432
|
+
if renderer_type.respond_to?(:to_hash)
|
433
|
+
options = renderer_type
|
434
|
+
else
|
435
|
+
options[:renderer] = renderer_type
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
Renderer.render_with(border_class, self, options, &block)
|
440
|
+
end
|
441
|
+
|
442
|
+
# Coerce an Enumerable into a Table
|
443
|
+
# This coercion mechanism is used by Table to handle Enumerable types
|
444
|
+
# and force them into array type.
|
445
|
+
#
|
446
|
+
# @param [Enumerable] object
|
447
|
+
# the object to coerce
|
448
|
+
#
|
449
|
+
# @return [Array]
|
450
|
+
#
|
451
|
+
# @api public
|
452
|
+
def coerce(rows)
|
453
|
+
rows = @converter.convert(rows).to(:array)
|
454
|
+
rows.map { |row| to_row(row, header) }
|
455
|
+
end
|
456
|
+
|
457
|
+
private
|
458
|
+
|
459
|
+
# Evaluate block
|
460
|
+
#
|
461
|
+
# @return [Table]
|
462
|
+
#
|
463
|
+
# @api private
|
464
|
+
def yield_or_eval(&block)
|
465
|
+
return unless block
|
466
|
+
block.arity > 0 ? yield(self) : instance_eval(&block)
|
467
|
+
end
|
468
|
+
end # Table
|
469
|
+
end # TTY
|
data/lib/tty-table.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'equatable'
|
4
|
+
require 'forwardable'
|
5
|
+
require 'necromancer'
|
6
|
+
require 'verse'
|
7
|
+
require 'tty-screen'
|
8
|
+
require 'pastel'
|
9
|
+
|
10
|
+
require 'tty/table/header'
|
11
|
+
require 'tty/table/row'
|
12
|
+
require 'tty/table/field'
|
13
|
+
require 'tty/table/version'
|
14
|
+
require 'tty/table/validatable'
|
15
|
+
require 'tty/table/error'
|
16
|
+
|
17
|
+
require 'tty/table/border'
|
18
|
+
require 'tty/table/border_dsl'
|
19
|
+
require 'tty/table/border_options'
|
20
|
+
require 'tty/table/border/unicode'
|
21
|
+
require 'tty/table/border/ascii'
|
22
|
+
require 'tty/table/border/null'
|
23
|
+
require 'tty/table/border/row_line'
|
24
|
+
|
25
|
+
require 'tty/table/renderer'
|
26
|
+
require 'tty/table/renderer/ascii'
|
27
|
+
require 'tty/table/renderer/basic'
|
28
|
+
require 'tty/table/renderer/color'
|
29
|
+
require 'tty/table/renderer/unicode'
|
30
|
+
|
31
|
+
require 'tty/table/column_set'
|
32
|
+
require 'tty/table/columns'
|
33
|
+
require 'tty/table/orientation'
|
34
|
+
require 'tty/table/orientation/horizontal'
|
35
|
+
require 'tty/table/orientation/vertical'
|
36
|
+
require 'tty/table/transformation'
|
37
|
+
require 'tty/table/indentation'
|
38
|
+
require 'tty/table/padder'
|
39
|
+
|
40
|
+
require 'tty/table/operations'
|
41
|
+
require 'tty/table/operation/alignment_set'
|
42
|
+
require 'tty/table/operation/truncation'
|
43
|
+
require 'tty/table/operation/wrapped'
|
44
|
+
require 'tty/table/operation/filter'
|
45
|
+
require 'tty/table/operation/escape'
|
46
|
+
require 'tty/table/operation/padding'
|
47
|
+
|
48
|
+
require 'tty/table'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS'])
|
4
|
+
require 'simplecov'
|
5
|
+
require 'coveralls'
|
6
|
+
|
7
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
8
|
+
SimpleCov::Formatter::HTMLFormatter,
|
9
|
+
Coveralls::SimpleCov::Formatter
|
10
|
+
]
|
11
|
+
|
12
|
+
SimpleCov.start do
|
13
|
+
command_name 'spec'
|
14
|
+
add_filter 'spec'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'tty-table'
|
19
|
+
|
20
|
+
RSpec.configure do |config|
|
21
|
+
config.expect_with :rspec do |expectations|
|
22
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
23
|
+
end
|
24
|
+
|
25
|
+
config.mock_with :rspec do |mocks|
|
26
|
+
mocks.verify_partial_doubles = true
|
27
|
+
end
|
28
|
+
|
29
|
+
# Limits the available syntax to the non-monkey patched syntax that is recommended.
|
30
|
+
config.disable_monkey_patching!
|
31
|
+
|
32
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
33
|
+
# be too noisy due to issues in dependencies.
|
34
|
+
config.warnings = true
|
35
|
+
|
36
|
+
if config.files_to_run.one?
|
37
|
+
config.default_formatter = 'doc'
|
38
|
+
end
|
39
|
+
|
40
|
+
config.profile_examples = 2
|
41
|
+
|
42
|
+
config.order = :random
|
43
|
+
|
44
|
+
Kernel.srand config.seed
|
45
|
+
end
|
46
|
+
|
47
|
+
class String
|
48
|
+
def normalize
|
49
|
+
gsub(/^[ \t]*/, '').chomp
|
50
|
+
end
|
51
|
+
end
|