tty-table 0.1.0
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.
- 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
|