tty 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -1
- data/.travis.yml +3 -6
- data/README.md +232 -134
- data/lib/tty/plugins/plugin.rb +56 -0
- data/lib/tty/plugins.rb +75 -0
- data/lib/tty/shell/suggestion.rb +102 -0
- data/lib/tty/shell.rb +41 -14
- data/lib/tty/system/editor.rb +111 -0
- data/lib/tty/system/which.rb +13 -1
- data/lib/tty/system.rb +44 -28
- data/lib/tty/table/border/null.rb +0 -9
- data/lib/tty/table/border/row_line.rb +21 -0
- data/lib/tty/table/border.rb +63 -32
- data/lib/tty/table/border_dsl.rb +1 -1
- data/lib/tty/table/column_set.rb +16 -17
- data/lib/tty/table/field.rb +27 -7
- data/lib/tty/table/header.rb +18 -9
- data/lib/tty/table/operation/alignment_set.rb +20 -25
- data/lib/tty/table/operation/escape.rb +30 -0
- data/lib/tty/table/operation/filter.rb +36 -0
- data/lib/tty/table/operation/truncation.rb +22 -11
- data/lib/tty/table/operation/wrapped.rb +21 -10
- data/lib/tty/table/operations.rb +10 -8
- data/lib/tty/table/orientation/horizontal.rb +1 -1
- data/lib/tty/table/renderer/ascii.rb +3 -3
- data/lib/tty/table/renderer/basic.rb +135 -65
- data/lib/tty/table/renderer/color.rb +1 -4
- data/lib/tty/table/renderer/unicode.rb +3 -3
- data/lib/tty/table/renderer.rb +48 -61
- data/lib/tty/table/row.rb +30 -3
- data/lib/tty/table/transformation.rb +38 -0
- data/lib/tty/table/validatable.rb +7 -5
- data/lib/tty/table.rb +78 -99
- data/lib/tty/terminal/color.rb +2 -2
- data/lib/tty/terminal/echo.rb +1 -1
- data/lib/tty/terminal/pager/basic.rb +52 -0
- data/lib/tty/terminal/pager/system.rb +39 -0
- data/lib/tty/terminal/pager.rb +95 -0
- data/lib/tty/terminal.rb +30 -1
- data/lib/tty/version.rb +1 -1
- data/lib/tty.rb +41 -1
- data/spec/spec_helper.rb +20 -0
- data/spec/tty/plugins/find_spec.rb +28 -0
- data/spec/tty/plugins/load_spec.rb +20 -0
- data/spec/tty/plugins/plugin/load_spec.rb +30 -0
- data/spec/tty/plugins/plugin/new_spec.rb +18 -0
- data/spec/tty/shell/suggest_spec.rb +50 -0
- data/spec/tty/support/conversion_spec.rb +3 -3
- data/spec/tty/support/delegatable_spec.rb +1 -1
- data/spec/tty/support/equatable_spec.rb +6 -9
- data/spec/tty/system/editor/available_spec.rb +40 -0
- data/spec/tty/system/editor/build_spec.rb +40 -0
- data/spec/tty/system/editor/command_spec.rb +16 -0
- data/spec/tty/system/editor/executables_spec.rb +13 -0
- data/spec/tty/system/editor/invoke_spec.rb +38 -0
- data/spec/tty/system/editor/open_spec.rb +27 -0
- data/spec/tty/system/platform_spec.rb +4 -6
- data/spec/tty/system/which/which_spec.rb +48 -0
- data/spec/tty/system/which_spec.rb +8 -34
- data/spec/tty/table/border/ascii/rendering_spec.rb +19 -5
- data/spec/tty/table/border/new_spec.rb +1 -1
- data/spec/tty/table/border/null/rendering_spec.rb +24 -8
- data/spec/tty/table/border/unicode/rendering_spec.rb +19 -5
- data/spec/tty/table/column_set/extract_widths_spec.rb +4 -15
- data/spec/tty/table/column_set/total_width_spec.rb +15 -0
- data/spec/tty/table/data_spec.rb +14 -0
- data/spec/tty/table/each_spec.rb +17 -4
- data/spec/tty/table/each_with_index_spec.rb +34 -6
- data/spec/tty/table/field/length_spec.rb +21 -0
- data/spec/tty/table/field/lines_spec.rb +21 -0
- data/spec/tty/table/filter_spec.rb +23 -0
- data/spec/tty/table/header/call_spec.rb +1 -1
- data/spec/tty/table/header/height_spec.rb +27 -0
- data/spec/tty/table/initialize_spec.rb +6 -6
- data/spec/tty/table/operation/alignment_set/call_spec.rb +39 -0
- data/spec/tty/table/operation/escape/call_spec.rb +16 -0
- data/spec/tty/table/operation/filter/call_spec.rb +17 -0
- data/spec/tty/table/operation/truncation/call_spec.rb +15 -10
- data/spec/tty/table/operation/truncation/truncate_spec.rb +1 -1
- data/spec/tty/table/operation/wrapped/call_spec.rb +15 -10
- data/spec/tty/table/operation/wrapped/wrap_spec.rb +1 -1
- data/spec/tty/table/operations/new_spec.rb +4 -4
- data/spec/tty/table/options_spec.rb +0 -28
- data/spec/tty/table/orientation_spec.rb +5 -6
- data/spec/tty/table/properties_spec.rb +1 -4
- data/spec/tty/table/render_spec.rb +57 -0
- data/spec/tty/table/{renders_with_spec.rb → render_with_spec.rb} +29 -10
- data/spec/tty/table/renderer/ascii/render_spec.rb +68 -0
- data/spec/tty/table/renderer/ascii/separator_spec.rb +28 -0
- data/spec/tty/table/renderer/basic/alignment_spec.rb +18 -16
- data/spec/tty/table/renderer/basic/extract_column_widths_spec.rb +17 -12
- data/spec/tty/table/renderer/basic/filter_spec.rb +53 -0
- data/spec/tty/table/renderer/basic/multiline_content_spec.rb +135 -0
- data/spec/tty/table/renderer/basic/new_spec.rb +13 -2
- data/spec/tty/table/renderer/basic/options_spec.rb +48 -0
- data/spec/tty/table/renderer/basic/render_spec.rb +19 -121
- data/spec/tty/table/renderer/basic/separator_spec.rb +14 -48
- data/spec/tty/table/renderer/basic/truncation_spec.rb +35 -0
- data/spec/tty/table/renderer/basic/wrapping_spec.rb +40 -0
- data/spec/tty/table/{border_spec.rb → renderer/border_spec.rb} +17 -20
- data/spec/tty/table/renderer/select_spec.rb +22 -0
- data/spec/tty/table/{border → renderer}/style_spec.rb +13 -14
- data/spec/tty/table/renderer/unicode/render_spec.rb +68 -0
- data/spec/tty/table/renderer/unicode/separator_spec.rb +26 -0
- data/spec/tty/table/rotate_spec.rb +2 -3
- data/spec/tty/table/row/call_spec.rb +1 -1
- data/spec/tty/table/row/each_spec.rb +31 -0
- data/spec/tty/table/row/height_spec.rb +27 -0
- data/spec/tty/table/to_s_spec.rb +3 -3
- data/spec/tty/table/transformation/extract_tuples_spec.rb +35 -0
- data/spec/tty/table/validatable/validate_options_spec.rb +1 -2
- data/spec/tty/terminal/home_spec.rb +3 -3
- data/spec/tty/terminal/page_spec.rb +13 -0
- data/spec/tty/terminal/pager/available_spec.rb +40 -0
- data/spec/tty/terminal/pager/basic/page_spec.rb +54 -0
- data/spec/tty/terminal/pager/command_spec.rb +16 -0
- data/spec/tty/terminal/pager/executables_spec.rb +13 -0
- data/spec/tty/terminal/pager/page_spec.rb +47 -0
- data/spec/tty/terminal/pager/system/page_spec.rb +29 -0
- data/spec/tty/text/distance/distance_spec.rb +12 -0
- data/tty.gemspec +7 -3
- metadata +160 -27
- data/spec/tty/table/operation/alignment_set/align_rows_spec.rb +0 -53
- data/spec/tty/table/renderer/pick_renderer_spec.rb +0 -25
- data/spec/tty/table/renderer_spec.rb +0 -49
@@ -1,12 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
+
require 'tty/table/validatable'
|
4
|
+
|
3
5
|
module TTY
|
4
6
|
class Table
|
5
|
-
|
7
|
+
class Renderer
|
6
8
|
|
7
9
|
# Renders table without any border styles.
|
8
10
|
class Basic
|
9
|
-
|
11
|
+
include TTY::Table::Validatable
|
10
12
|
|
11
13
|
# Table to be rendered
|
12
14
|
#
|
@@ -14,40 +16,108 @@ module TTY
|
|
14
16
|
#
|
15
17
|
# @api public
|
16
18
|
attr_reader :table
|
19
|
+
private :table
|
17
20
|
|
18
21
|
# Table border to be rendered
|
19
22
|
#
|
20
23
|
# @return [TTY::Table::Border]
|
21
24
|
#
|
22
25
|
# @api private
|
23
|
-
|
26
|
+
attr_accessor :border_class
|
24
27
|
|
25
|
-
|
28
|
+
# The table enforced column widths
|
29
|
+
#
|
30
|
+
# @return [Array]
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
attr_accessor :column_widths
|
26
34
|
|
27
|
-
|
35
|
+
# The table column alignments
|
36
|
+
#
|
37
|
+
# @return [Array]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
attr_accessor :column_aligns
|
28
41
|
|
29
|
-
#
|
42
|
+
# The table operations applied to rows
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
attr_reader :operations
|
46
|
+
|
47
|
+
# A callable object used for formatting field content
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
attr_accessor :filter
|
51
|
+
|
52
|
+
# The table column span behaviour. When true the column's line breaks
|
53
|
+
# cause the column to span multiple rows. By default set to false.
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
attr_accessor :multiline
|
59
|
+
|
60
|
+
# Initialize a Renderer
|
30
61
|
#
|
31
62
|
# @param [Hash] options
|
63
|
+
# @option options [String] :column_aligns
|
64
|
+
# used to format table individual column alignment
|
65
|
+
# @option options [String] :column_widths
|
66
|
+
# used to format table individula column width
|
67
|
+
#
|
32
68
|
# :indent - Indent the first column by indent value
|
33
69
|
# :padding - Pad out the row cell by padding value
|
34
70
|
#
|
35
|
-
# @return [Table::Renderer::Basic]
|
36
|
-
|
37
|
-
|
71
|
+
# @return [TTY::Table::Renderer::Basic]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
def initialize(table, options={})
|
75
|
+
validate_rendering_options!(options)
|
76
|
+
@table = table || (raise ArgumentRequired, "Expected TTY::Table instance, got #{table.inspect}")
|
77
|
+
@multiline = options.fetch(:multiline) { false }
|
78
|
+
@operations = TTY::Table::Operations.new(table)
|
79
|
+
unless multiline
|
80
|
+
@operations.add_operation(:escape, Operation::Escape.new)
|
81
|
+
@operations.run_operations(:escape)
|
82
|
+
end
|
83
|
+
|
84
|
+
@border = TTY::Table::BorderOptions.from(options.delete(:border))
|
85
|
+
@column_widths = Array(options.fetch(:column_widths) {
|
86
|
+
ColumnSet.new(table).extract_widths
|
87
|
+
}).map(&:to_i)
|
88
|
+
@column_aligns = Array(options.delete(:column_aligns)).map(&:to_sym)
|
89
|
+
@filter = options.fetch(:filter) { proc { |val, row, col| val } }
|
90
|
+
@width = options.fetch(:width) { TTY.terminal.width }
|
91
|
+
@border_class = options.fetch(:border_class) { Border::Null }
|
38
92
|
end
|
39
93
|
|
40
|
-
#
|
94
|
+
# Store border characters, style and separator for the table rendering
|
95
|
+
#
|
96
|
+
# @param [Hash, BorderOptions] options
|
41
97
|
#
|
42
|
-
# @
|
98
|
+
# @yield [] block representing border options
|
99
|
+
#
|
100
|
+
# @api public
|
101
|
+
def border(options=(not_set=true), &block)
|
102
|
+
@border = TTY::Table::BorderOptions.new unless @border
|
103
|
+
if block_given?
|
104
|
+
border_dsl = TTY::Table::BorderDSL.new(&block)
|
105
|
+
@border = border_dsl.options
|
106
|
+
elsif !not_set
|
107
|
+
@border = TTY::Table::BorderOptions.from(options)
|
108
|
+
end
|
109
|
+
@border
|
110
|
+
end
|
111
|
+
|
112
|
+
# Initialize and add operations
|
43
113
|
#
|
44
114
|
# @api private
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
115
|
+
def add_operations
|
116
|
+
operations.add_operation(:alignment, Operation::AlignmentSet.new(column_aligns, column_widths))
|
117
|
+
operations.add_operation(:filter, Operation::Filter.new(filter))
|
118
|
+
operations.add_operation(:truncation, Operation::Truncation.new(column_widths))
|
119
|
+
operations.add_operation(:wrapping, Operation::Wrapped.new(column_widths))
|
49
120
|
end
|
50
|
-
private :setup
|
51
121
|
|
52
122
|
# Sets the output padding,
|
53
123
|
#
|
@@ -59,74 +129,72 @@ module TTY
|
|
59
129
|
@padding = [0, value].max
|
60
130
|
end
|
61
131
|
|
62
|
-
# @api public
|
63
|
-
def self.render(table, options={})
|
64
|
-
new(options).render(table)
|
65
|
-
end
|
66
|
-
|
67
132
|
# Renders table
|
68
133
|
#
|
69
|
-
# @param [TTY::Table] table
|
70
|
-
# the table to be rendered
|
71
|
-
#
|
72
134
|
# @return [String] string representation of table
|
73
135
|
#
|
74
136
|
# @api public
|
75
|
-
def render
|
76
|
-
@table = table
|
77
|
-
@border_class = table.border_class || border_class
|
137
|
+
def render
|
78
138
|
return if table.empty?
|
79
139
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
body.compact.join("\n")
|
140
|
+
# TODO: throw an error if too many columns as compared to terminal width
|
141
|
+
# and then change table.orientation from vertical to horizontal
|
142
|
+
# TODO: Decide about table orientation
|
143
|
+
add_operations
|
144
|
+
ops = [:filter, :alignment]
|
145
|
+
multiline ? ops << :wrapping : ops << :truncation
|
146
|
+
operations.run_operations(*ops)
|
147
|
+
render_data.compact.join("\n")
|
90
148
|
end
|
91
149
|
|
92
150
|
private
|
93
151
|
|
94
|
-
#
|
152
|
+
# Render table data
|
153
|
+
#
|
154
|
+
# @api private
|
155
|
+
def render_data
|
156
|
+
first_row = table.first
|
157
|
+
data_border = border_class.new(column_widths, border)
|
158
|
+
header = render_header(first_row, data_border)
|
159
|
+
rows_with_border = render_rows(data_border)
|
160
|
+
|
161
|
+
[header, rows_with_border, data_border.bottom_line].compact
|
162
|
+
end
|
163
|
+
|
164
|
+
# Format the header if present
|
165
|
+
#
|
166
|
+
# @param [TTY::Table::Row, TTY::Table::Header] row
|
167
|
+
# the first row in the table
|
168
|
+
#
|
169
|
+
# @param [TTY::Table::Border] data_boder
|
170
|
+
# the border for this table
|
95
171
|
#
|
96
|
-
# @return [
|
172
|
+
# @return [String]
|
97
173
|
#
|
98
174
|
# @api private
|
99
|
-
def render_header
|
100
|
-
|
101
|
-
if
|
102
|
-
|
103
|
-
operations.run_operations(:alignment, header)
|
104
|
-
border = border_class.new(header, table.border)
|
105
|
-
[ border.top_line, border.row_line ].compact
|
175
|
+
def render_header(row, data_border)
|
176
|
+
top_line = data_border.top_line
|
177
|
+
if row.is_a?(TTY::Table::Header)
|
178
|
+
[top_line, data_border.row_line(row), data_border.separator].compact
|
106
179
|
else
|
107
|
-
|
180
|
+
top_line
|
108
181
|
end
|
109
182
|
end
|
110
183
|
|
111
184
|
# Format the rows
|
112
185
|
#
|
186
|
+
# @param [TTY::Table::Border] data_boder
|
187
|
+
# the border for this table
|
188
|
+
#
|
113
189
|
# @return [Arrays[String]]
|
114
190
|
#
|
115
191
|
# @api private
|
116
|
-
def render_rows
|
117
|
-
|
118
|
-
|
119
|
-
|
192
|
+
def render_rows(data_border)
|
193
|
+
rows = table.rows
|
194
|
+
size = rows.size
|
195
|
+
rows.each_with_index.map do |row, index|
|
196
|
+
render_row(row, data_border, size != (index += 1))
|
120
197
|
end
|
121
|
-
aligned = table.to_a
|
122
|
-
first_row_border = border_class.new(aligned.first, table.border)
|
123
|
-
aligned_border = aligned.each_with_index.map { |row, index|
|
124
|
-
render_row(row, aligned.size != (index += 1))
|
125
|
-
}
|
126
|
-
|
127
|
-
[ table.header ? first_row_border.separator : first_row_border.top_line,
|
128
|
-
aligned_border,
|
129
|
-
first_row_border.bottom_line ].compact
|
130
198
|
end
|
131
199
|
|
132
200
|
# Format a single row with border
|
@@ -134,15 +202,17 @@ module TTY
|
|
134
202
|
# @param [Array] row
|
135
203
|
# a row to decorate
|
136
204
|
#
|
205
|
+
# @param [TTY::Table::Border] data_boder
|
206
|
+
# the border for this table
|
207
|
+
#
|
137
208
|
# @param [Boolean] is_last_row
|
138
209
|
#
|
139
210
|
# @api private
|
140
|
-
def render_row(row, is_last_row)
|
141
|
-
|
142
|
-
|
143
|
-
row_line = border.row_line
|
211
|
+
def render_row(row, data_border, is_last_row)
|
212
|
+
separator = data_border.separator
|
213
|
+
row_line = data_border.row_line(row)
|
144
214
|
|
145
|
-
if (
|
215
|
+
if (border.separator == TTY::Table::Border::EACH_ROW) && is_last_row
|
146
216
|
[row_line, separator]
|
147
217
|
else
|
148
218
|
row_line
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
module TTY
|
4
4
|
class Table
|
5
|
-
|
5
|
+
class Renderer
|
6
6
|
class Unicode < Basic
|
7
7
|
|
8
|
-
def
|
9
|
-
super
|
8
|
+
def initialize(table, options={})
|
9
|
+
super(table, options.merge(:border_class => TTY::Table::Border::Unicode))
|
10
10
|
end
|
11
11
|
|
12
12
|
end # Unicode
|
data/lib/tty/table/renderer.rb
CHANGED
@@ -3,39 +3,13 @@
|
|
3
3
|
module TTY
|
4
4
|
class Table
|
5
5
|
|
6
|
-
#
|
7
|
-
|
8
|
-
# @return [TTY::Table::Renderer]
|
9
|
-
#
|
10
|
-
# @api public
|
11
|
-
def self.renderer
|
12
|
-
@renderer ||= if TTY.terminal.color?
|
13
|
-
TTY::Table::Renderer::Color
|
14
|
-
else
|
15
|
-
TTY::Table::Renderer::Basic
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# @api public
|
20
|
-
def self.renderer=(klass)
|
21
|
-
@renderer = klass
|
22
|
-
end
|
23
|
-
|
24
|
-
# A mixin to allow common rendering methods
|
25
|
-
#
|
26
|
-
# @return [self]
|
27
|
-
#
|
28
|
-
# @api public
|
29
|
-
module Renderer
|
30
|
-
extend TTY::Delegatable
|
31
|
-
|
6
|
+
# A class responsible for rendering tabular data
|
7
|
+
class Renderer
|
32
8
|
autoload :ASCII, 'tty/table/renderer/ascii'
|
33
9
|
autoload :Basic, 'tty/table/renderer/basic'
|
34
10
|
autoload :Color, 'tty/table/renderer/color'
|
35
11
|
autoload :Unicode, 'tty/table/renderer/unicode'
|
36
12
|
|
37
|
-
RENDERER_DELEGATED_METHODS = [ :render, :total_width]
|
38
|
-
|
39
13
|
RENDERER_MAPPER = {
|
40
14
|
:ascii => TTY::Table::Renderer::ASCII,
|
41
15
|
:basic => TTY::Table::Renderer::Basic,
|
@@ -43,44 +17,45 @@ module TTY
|
|
43
17
|
:unicode => TTY::Table::Renderer::Unicode
|
44
18
|
}
|
45
19
|
|
46
|
-
#
|
47
|
-
#
|
48
|
-
# @api private
|
49
|
-
def initialize(options={})
|
50
|
-
super()
|
51
|
-
end
|
52
|
-
|
53
|
-
# Determine renderer class based on string name
|
20
|
+
# Select renderer class based on string name
|
54
21
|
#
|
55
22
|
# @param [Symbol] renderer
|
56
|
-
# the renderer used for displaying table out of [:basic, :
|
23
|
+
# the renderer used for displaying table out of [:basic, :ascii, :unicode, :color]
|
57
24
|
#
|
58
25
|
# @return [TTY::Table::Renderer]
|
59
26
|
#
|
60
27
|
# @api private
|
61
|
-
def
|
62
|
-
|
28
|
+
def self.select(type)
|
29
|
+
RENDERER_MAPPER[type || :basic]
|
63
30
|
end
|
64
31
|
|
65
|
-
#
|
32
|
+
# Raises an error if provided border class is of wrong type or has invalid
|
33
|
+
# implementation
|
66
34
|
#
|
67
|
-
# @
|
35
|
+
# @raise [TypeError]
|
36
|
+
# raised when providing wrong class for border
|
37
|
+
#
|
38
|
+
# @raise [NoImplementationError]
|
39
|
+
# raised when border class does not implement core methods
|
68
40
|
#
|
69
41
|
# @api public
|
70
|
-
def
|
71
|
-
|
42
|
+
def self.assert_border_class(border_class)
|
43
|
+
return unless border_class
|
44
|
+
unless border_class <= TTY::Table::Border
|
45
|
+
raise TypeError, "#{border_class} should inherit from TTY::Table::Border"
|
46
|
+
end
|
47
|
+
unless border_class.characters
|
48
|
+
raise NoImplementationError, "#{border_class} should implement def_border"
|
49
|
+
end
|
72
50
|
end
|
73
51
|
|
74
|
-
#
|
52
|
+
# Add custom border for the renderer
|
75
53
|
#
|
76
|
-
# @
|
54
|
+
# @param [TTY::Table::Border] border_class
|
77
55
|
#
|
78
|
-
# @
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
# Add custom border for the renderer
|
56
|
+
# @param [TTY::Table] table
|
57
|
+
#
|
58
|
+
# @param [Hash] options
|
84
59
|
#
|
85
60
|
# @raise [TypeError]
|
86
61
|
# raised if the klass does not inherit from Table::Border
|
@@ -89,18 +64,30 @@ module TTY
|
|
89
64
|
# raise if the klass does not implement def_border
|
90
65
|
#
|
91
66
|
# @api public
|
92
|
-
def
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
unless klass.characters
|
97
|
-
raise NoImplementationError, "#{klass} should implement def_border"
|
98
|
-
end
|
99
|
-
@border_class = klass
|
67
|
+
def self.render_with(border_class, table, options={}, &block)
|
68
|
+
assert_border_class(border_class)
|
69
|
+
options[:border_class] = border_class if border_class
|
70
|
+
render(table, options, &block)
|
100
71
|
end
|
101
72
|
|
102
|
-
|
103
|
-
|
73
|
+
# Render a given table and return the string representation.
|
74
|
+
#
|
75
|
+
# @param [TTY::Table] table
|
76
|
+
# the table to be rendered
|
77
|
+
#
|
78
|
+
# @param [Hash] options
|
79
|
+
# the options to render the table with
|
80
|
+
# @option options [String] :renderer
|
81
|
+
# used to format table output
|
82
|
+
#
|
83
|
+
# @return [String]
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
def self.render(table, options={}, &block)
|
87
|
+
renderer = select(options[:renderer]).new(table, options)
|
88
|
+
yield renderer if block_given?
|
89
|
+
renderer.render
|
90
|
+
end
|
104
91
|
end # Renderer
|
105
92
|
|
106
93
|
end # Table
|
data/lib/tty/table/row.rb
CHANGED
@@ -35,6 +35,8 @@ module TTY
|
|
35
35
|
# @api private
|
36
36
|
attr_reader :data
|
37
37
|
|
38
|
+
attr_reader :fields
|
39
|
+
|
38
40
|
# Initialize a Row
|
39
41
|
#
|
40
42
|
# @example
|
@@ -59,11 +61,11 @@ module TTY
|
|
59
61
|
case data
|
60
62
|
when Array
|
61
63
|
@attributes = (header || (0...data.length)).to_a
|
62
|
-
fields = data.inject([]) { |arr, datum| arr << to_field(datum) }
|
64
|
+
@fields = data.inject([]) { |arr, datum| arr << to_field(datum) }
|
63
65
|
@data = Hash[@attributes.zip(fields)]
|
64
66
|
when Hash
|
65
67
|
@data = data.dup
|
66
|
-
fields = @data.values.inject([]){|arr, datum| arr << to_field(datum) }
|
68
|
+
@fields = @data.values.inject([]){|arr, datum| arr << to_field(datum) }
|
67
69
|
@attributes = (header || data.keys).to_a
|
68
70
|
@data = Hash[@attributes.zip(fields)]
|
69
71
|
end
|
@@ -95,7 +97,13 @@ module TTY
|
|
95
97
|
end.value
|
96
98
|
end
|
97
99
|
end
|
98
|
-
|
100
|
+
|
101
|
+
# Lookup attribute without evaluation
|
102
|
+
#
|
103
|
+
# @api public
|
104
|
+
def call(attribute)
|
105
|
+
data[attributes[attribute]]
|
106
|
+
end
|
99
107
|
|
100
108
|
# Set value at index
|
101
109
|
#
|
@@ -123,6 +131,15 @@ module TTY
|
|
123
131
|
end
|
124
132
|
alias :length :size
|
125
133
|
|
134
|
+
# Find maximum row height
|
135
|
+
#
|
136
|
+
# @return [Integer]
|
137
|
+
#
|
138
|
+
# @api public
|
139
|
+
def height
|
140
|
+
fields.map { |field| field.height }.max
|
141
|
+
end
|
142
|
+
|
126
143
|
# Convert the Row into Array
|
127
144
|
#
|
128
145
|
# @example
|
@@ -163,11 +180,21 @@ module TTY
|
|
163
180
|
to_a.hash
|
164
181
|
end
|
165
182
|
|
183
|
+
# Map field values
|
184
|
+
#
|
185
|
+
# @api public
|
166
186
|
def map!(&block)
|
167
187
|
data.values_at(*attributes).each do |field|
|
168
188
|
field.value = block.call(field)
|
169
189
|
end
|
170
190
|
end
|
191
|
+
|
192
|
+
# String representation of a row with its fields
|
193
|
+
#
|
194
|
+
# @api public
|
195
|
+
def inspect
|
196
|
+
"#<#{self.class.name} fields=#{to_a}>"
|
197
|
+
end
|
171
198
|
end # Row
|
172
199
|
|
173
200
|
end # Table
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
module TTY
|
4
|
+
class Table
|
5
|
+
|
6
|
+
# A class for transforming table values
|
7
|
+
class Transformation
|
8
|
+
|
9
|
+
# Extract the header and row tuples from the value
|
10
|
+
#
|
11
|
+
# @param [Array] args
|
12
|
+
#
|
13
|
+
# @return [Object]
|
14
|
+
#
|
15
|
+
# @api public
|
16
|
+
def self.extract_tuples(args)
|
17
|
+
rows = args.pop
|
18
|
+
header = args.size.zero? ? nil : args.first
|
19
|
+
if rows.first.is_a?(Hash)
|
20
|
+
header, rows = group_header_and_rows(rows)
|
21
|
+
end
|
22
|
+
{ header: header, rows: rows }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Group hash keys into header and values into rows
|
26
|
+
#
|
27
|
+
# @params [Hash] value
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
def self.group_header_and_rows(value)
|
31
|
+
header = value.map(&:keys).flatten.uniq
|
32
|
+
rows = value.inject([]) { |arr, el| arr + el.values }
|
33
|
+
[header, rows]
|
34
|
+
end
|
35
|
+
|
36
|
+
end # Transformation
|
37
|
+
end # Table
|
38
|
+
end # TTY
|
@@ -29,6 +29,13 @@ module TTY
|
|
29
29
|
def assert_string_values(rows)
|
30
30
|
end
|
31
31
|
|
32
|
+
def validate_rendering_options!(options)
|
33
|
+
if (column_widths = options[:column_widths]) &&
|
34
|
+
(!column_widths.kind_of?(Array) || column_widths.empty?)
|
35
|
+
raise InvalidArgument, ":column_widths must be a non-empty array"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
32
39
|
# Check if options are of required type
|
33
40
|
#
|
34
41
|
# @api private
|
@@ -42,11 +49,6 @@ module TTY
|
|
42
49
|
!(rows.kind_of?(Array) || rows.kind_of?(Hash))
|
43
50
|
raise InvalidArgument, ":rows must be a non-empty array or hash"
|
44
51
|
end
|
45
|
-
|
46
|
-
if (column_widths = options[:column_widths]) &&
|
47
|
-
(!column_widths.kind_of?(Array) || column_widths.empty?)
|
48
|
-
raise InvalidArgument, ":column_widths must be a non-empty array"
|
49
|
-
end
|
50
52
|
end
|
51
53
|
|
52
54
|
end # Validatable
|