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.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +22 -0
  6. data/Gemfile +19 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +389 -0
  9. data/Rakefile +8 -0
  10. data/benchmarks/speed.rb +36 -0
  11. data/lib/tty/table/border/ascii.rb +32 -0
  12. data/lib/tty/table/border/null.rb +37 -0
  13. data/lib/tty/table/border/row_line.rb +18 -0
  14. data/lib/tty/table/border/unicode.rb +32 -0
  15. data/lib/tty/table/border.rb +219 -0
  16. data/lib/tty/table/border_dsl.rb +251 -0
  17. data/lib/tty/table/border_options.rb +53 -0
  18. data/lib/tty/table/column_set.rb +121 -0
  19. data/lib/tty/table/columns.rb +170 -0
  20. data/lib/tty/table/empty.rb +26 -0
  21. data/lib/tty/table/error.rb +39 -0
  22. data/lib/tty/table/field.rb +139 -0
  23. data/lib/tty/table/header.rb +163 -0
  24. data/lib/tty/table/indentation.rb +52 -0
  25. data/lib/tty/table/operation/alignment_set.rb +103 -0
  26. data/lib/tty/table/operation/escape.rb +30 -0
  27. data/lib/tty/table/operation/filter.rb +34 -0
  28. data/lib/tty/table/operation/padding.rb +95 -0
  29. data/lib/tty/table/operation/truncation.rb +41 -0
  30. data/lib/tty/table/operation/wrapped.rb +43 -0
  31. data/lib/tty/table/operations.rb +69 -0
  32. data/lib/tty/table/options.rb +30 -0
  33. data/lib/tty/table/orientation/horizontal.rb +48 -0
  34. data/lib/tty/table/orientation/vertical.rb +38 -0
  35. data/lib/tty/table/orientation.rb +57 -0
  36. data/lib/tty/table/padder.rb +180 -0
  37. data/lib/tty/table/renderer/ascii.rb +16 -0
  38. data/lib/tty/table/renderer/basic.rb +294 -0
  39. data/lib/tty/table/renderer/color.rb +12 -0
  40. data/lib/tty/table/renderer/unicode.rb +21 -0
  41. data/lib/tty/table/renderer.rb +101 -0
  42. data/lib/tty/table/row.rb +248 -0
  43. data/lib/tty/table/transformation.rb +39 -0
  44. data/lib/tty/table/validatable.rb +64 -0
  45. data/lib/tty/table/version.rb +7 -0
  46. data/lib/tty/table.rb +469 -0
  47. data/lib/tty-table.rb +48 -0
  48. data/spec/spec_helper.rb +51 -0
  49. data/spec/unit/access_spec.rb +86 -0
  50. data/spec/unit/add_row_spec.rb +28 -0
  51. data/spec/unit/border/ascii/rendering_spec.rb +90 -0
  52. data/spec/unit/border/new_spec.rb +27 -0
  53. data/spec/unit/border/null/rendering_spec.rb +130 -0
  54. data/spec/unit/border/options/from_spec.rb +38 -0
  55. data/spec/unit/border/options/new_spec.rb +14 -0
  56. data/spec/unit/border/unicode/rendering_spec.rb +63 -0
  57. data/spec/unit/border_options/new_spec.rb +20 -0
  58. data/spec/unit/border_options/update_spec.rb +18 -0
  59. data/spec/unit/column_set/extract_widths_spec.rb +15 -0
  60. data/spec/unit/column_set/total_width_spec.rb +15 -0
  61. data/spec/unit/column_set/widths_from_spec.rb +51 -0
  62. data/spec/unit/columns/enforce_spec.rb +67 -0
  63. data/spec/unit/columns/widths_spec.rb +35 -0
  64. data/spec/unit/data_spec.rb +14 -0
  65. data/spec/unit/each_spec.rb +41 -0
  66. data/spec/unit/each_with_index_spec.rb +57 -0
  67. data/spec/unit/empty_spec.rb +23 -0
  68. data/spec/unit/eql_spec.rb +34 -0
  69. data/spec/unit/field/equality_spec.rb +51 -0
  70. data/spec/unit/field/length_spec.rb +21 -0
  71. data/spec/unit/field/lines_spec.rb +21 -0
  72. data/spec/unit/field/new_spec.rb +29 -0
  73. data/spec/unit/field/width_spec.rb +23 -0
  74. data/spec/unit/filter_spec.rb +23 -0
  75. data/spec/unit/header/call_spec.rb +30 -0
  76. data/spec/unit/header/color_spec.rb +19 -0
  77. data/spec/unit/header/equality_spec.rb +51 -0
  78. data/spec/unit/header/height_spec.rb +27 -0
  79. data/spec/unit/header/new_spec.rb +25 -0
  80. data/spec/unit/header/set_spec.rb +20 -0
  81. data/spec/unit/header/to_ary_spec.rb +14 -0
  82. data/spec/unit/header_spec.rb +13 -0
  83. data/spec/unit/indentation/insert_indent_spec.rb +27 -0
  84. data/spec/unit/initialize_spec.rb +88 -0
  85. data/spec/unit/operation/alignment_set/call_spec.rb +39 -0
  86. data/spec/unit/operation/alignment_set/each_spec.rb +17 -0
  87. data/spec/unit/operation/alignment_set/new_spec.rb +27 -0
  88. data/spec/unit/operation/alignment_set/to_ary_spec.rb +14 -0
  89. data/spec/unit/operation/escape/call_spec.rb +16 -0
  90. data/spec/unit/operation/filter/call_spec.rb +17 -0
  91. data/spec/unit/operation/truncation/call_spec.rb +32 -0
  92. data/spec/unit/operation/wrapped/call_spec.rb +33 -0
  93. data/spec/unit/operations/new_spec.rb +30 -0
  94. data/spec/unit/options/access_spec.rb +14 -0
  95. data/spec/unit/options_spec.rb +25 -0
  96. data/spec/unit/orientation_spec.rb +145 -0
  97. data/spec/unit/padder/parse_spec.rb +45 -0
  98. data/spec/unit/padder/to_s_spec.rb +14 -0
  99. data/spec/unit/padding_spec.rb +120 -0
  100. data/spec/unit/properties_spec.rb +25 -0
  101. data/spec/unit/render_spec.rb +63 -0
  102. data/spec/unit/render_with_spec.rb +106 -0
  103. data/spec/unit/renderer/ascii/indentation_spec.rb +41 -0
  104. data/spec/unit/renderer/ascii/padding_spec.rb +61 -0
  105. data/spec/unit/renderer/ascii/render_spec.rb +68 -0
  106. data/spec/unit/renderer/ascii/resizing_spec.rb +114 -0
  107. data/spec/unit/renderer/ascii/separator_spec.rb +28 -0
  108. data/spec/unit/renderer/basic/alignment_spec.rb +88 -0
  109. data/spec/unit/renderer/basic/coloring_spec.rb +46 -0
  110. data/spec/unit/renderer/basic/extract_column_widths_spec.rb +28 -0
  111. data/spec/unit/renderer/basic/filter_spec.rb +53 -0
  112. data/spec/unit/renderer/basic/indentation_spec.rb +48 -0
  113. data/spec/unit/renderer/basic/multiline_content_spec.rb +135 -0
  114. data/spec/unit/renderer/basic/new_spec.rb +26 -0
  115. data/spec/unit/renderer/basic/options_spec.rb +52 -0
  116. data/spec/unit/renderer/basic/padding_spec.rb +52 -0
  117. data/spec/unit/renderer/basic/render_spec.rb +57 -0
  118. data/spec/unit/renderer/basic/resizing_spec.rb +96 -0
  119. data/spec/unit/renderer/basic/separator_spec.rb +43 -0
  120. data/spec/unit/renderer/basic/truncation_spec.rb +35 -0
  121. data/spec/unit/renderer/basic/wrapping_spec.rb +40 -0
  122. data/spec/unit/renderer/border_spec.rb +104 -0
  123. data/spec/unit/renderer/render_spec.rb +36 -0
  124. data/spec/unit/renderer/select_spec.rb +22 -0
  125. data/spec/unit/renderer/style_spec.rb +72 -0
  126. data/spec/unit/renderer/unicode/indentation_spec.rb +41 -0
  127. data/spec/unit/renderer/unicode/padding_spec.rb +61 -0
  128. data/spec/unit/renderer/unicode/render_spec.rb +68 -0
  129. data/spec/unit/renderer/unicode/separator_spec.rb +26 -0
  130. data/spec/unit/renderer_spec.rb +19 -0
  131. data/spec/unit/rotate_spec.rb +86 -0
  132. data/spec/unit/row/access_spec.rb +25 -0
  133. data/spec/unit/row/call_spec.rb +45 -0
  134. data/spec/unit/row/data_spec.rb +26 -0
  135. data/spec/unit/row/each_spec.rb +31 -0
  136. data/spec/unit/row/equality_spec.rb +73 -0
  137. data/spec/unit/row/height_spec.rb +27 -0
  138. data/spec/unit/row/new_spec.rb +41 -0
  139. data/spec/unit/row/to_ary_spec.rb +14 -0
  140. data/spec/unit/to_s_spec.rb +63 -0
  141. data/spec/unit/transformation/extract_tuples_spec.rb +35 -0
  142. data/spec/unit/validatable/validate_options_spec.rb +33 -0
  143. data/spec/unit/validatable_spec.rb +32 -0
  144. data/tasks/console.rake +10 -0
  145. data/tasks/coverage.rake +11 -0
  146. data/tasks/spec.rake +29 -0
  147. data/tty-table.gemspec +28 -0
  148. metadata +371 -0
@@ -0,0 +1,219 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Table
5
+ # Abstract base class that is responsible for building the table border.
6
+ class Border
7
+ include Equatable
8
+
9
+ EMPTY_CHAR = ''.freeze
10
+
11
+ SPACE_CHAR = ' '.freeze
12
+
13
+ # Represent a separtor on each row
14
+ EACH_ROW = :each_row
15
+
16
+ # The row field widths
17
+ #
18
+ # @api private
19
+ attr_reader :widths
20
+ private :widths
21
+
22
+ # The table custom border characters
23
+ attr_reader :border
24
+
25
+ # The table
26
+
27
+ class << self
28
+ # Store characters for border
29
+ #
30
+ # @api private
31
+ attr_accessor :characters
32
+ end
33
+
34
+ # Instantiate a new object
35
+ #
36
+ # @param [Array] column_widths
37
+ # the table column widths
38
+ #
39
+ # @param [BorderOptions] options
40
+ #
41
+ # @return [Object]
42
+ #
43
+ # @api private
44
+ def initialize(column_widths, options = nil)
45
+ if self.class == Border
46
+ fail NotImplementedError, "#{self} is an abstract class"
47
+ else
48
+ @widths = column_widths
49
+ @border = TTY::Table::BorderOptions.from options
50
+ @color = Pastel.new
51
+ end
52
+ end
53
+
54
+ # Define border characters
55
+ #
56
+ # @param [Hash] characters
57
+ # the border characters
58
+ #
59
+ # @return [Hash]
60
+ #
61
+ # @api public
62
+ def self.def_border(characters=(not_set=true), &block)
63
+ return self.characters = characters unless not_set
64
+
65
+ dsl = TTY::Table::BorderDSL.new(&block)
66
+ self.characters = dsl.characters
67
+ end
68
+
69
+ # Retrive individula character by type
70
+ #
71
+ # @param [String] type
72
+ # the character type
73
+ #
74
+ # @return [String]
75
+ #
76
+ # @api private
77
+ def [](type)
78
+ characters = self.class.characters
79
+ chars = border.nil? ? characters : characters.merge(border.characters)
80
+ chars[type] || EMPTY_CHAR
81
+ end
82
+
83
+ # Check if border color is set
84
+ #
85
+ # @return [Boolean]
86
+ #
87
+ # @api public
88
+ def color?
89
+ border && border.style
90
+ end
91
+
92
+ # Set color on characters
93
+ #
94
+ # @param [Symbol] color
95
+ #
96
+ # @param [Array[String]] array of strings
97
+ #
98
+ # @return [Array[String]]
99
+ #
100
+ # @api public
101
+ def set_color(color, *strings)
102
+ strings.map { |string| @color.decorate(string, color) }
103
+ end
104
+
105
+ # A line spanning all columns marking top of a table.
106
+ #
107
+ # @return [String]
108
+ #
109
+ # @api private
110
+ def top_line
111
+ (result = render(:top)).empty? ? nil : result
112
+ end
113
+
114
+ # A line spannig all columns marking bottom of a table.
115
+ #
116
+ # @return [String]
117
+ #
118
+ # @api private
119
+ def bottom_line
120
+ (result = render(:bottom)).empty? ? nil : result
121
+ end
122
+
123
+ # A line spanning all columns delemeting rows in a table.
124
+ #
125
+ # @return [String]
126
+ #
127
+ # @api private
128
+ def separator
129
+ (result = render(:mid)).empty? ? nil : result
130
+ end
131
+
132
+ # A line spanning all columns delemeting fields in a row.
133
+ #
134
+ # @param [TTY::Table::Row] row
135
+ # the table row
136
+ #
137
+ # @return [String]
138
+ #
139
+ # @api public
140
+ def row_line(row)
141
+ line = RowLine.new(self['left'], self['center'], self['right'])
142
+ line.colorize(self, border.style) if color?
143
+
144
+ result = row_heights(row, line)
145
+ result.empty? ? EMPTY_CHAR : result
146
+ end
147
+
148
+ protected
149
+
150
+ # Separate multiline string into individual rows with border.
151
+ #
152
+ # @param [TTY::Table::Row] row
153
+ # the table row
154
+ #
155
+ # @param [TTY::Table::Border::RowLine] line
156
+ #
157
+ # @api private
158
+ def row_heights(row, line)
159
+ if row.size > 0
160
+ row.height.times.map do |line_index|
161
+ row_height_line(row, line_index, line)
162
+ end.join("\n")
163
+ else
164
+ line.left + line.right
165
+ end
166
+ end
167
+
168
+ # Generate border for a given multiline row
169
+ #
170
+ # @param [TTY::Table::Row] row
171
+ # the table row
172
+ #
173
+ # @param [Integer] line
174
+ # the index for current line inside multiline
175
+ #
176
+ # @param [TTY::Table::Border::RowLine] line
177
+ #
178
+ # @return [String]
179
+ #
180
+ # @api private
181
+ def row_height_line(row, line_index, line)
182
+ line.left + row.fields.each_with_index.map do |field, index|
183
+ (field.lines[line_index] || EMPTY_CHAR).ljust(widths[index])
184
+ end.join(line.center) + line.right
185
+ end
186
+
187
+ # Generate particular border type
188
+ #
189
+ # @param [String] type
190
+ # border type one of [:top, :bottom, :mid]
191
+ #
192
+ # @api private
193
+ def render(type)
194
+ type = type.to_s
195
+ border_char = self[type]
196
+ line = render_line(border_char,
197
+ self["#{type}_left"] || border_char,
198
+ self["#{type}_right"] || border_char,
199
+ self["#{type}_mid"])
200
+
201
+ if color? && !line.empty?
202
+ line = set_color(border.style, line)
203
+ end
204
+ line
205
+ end
206
+
207
+ # Generate a border string
208
+ #
209
+ # @param [String] line
210
+ #
211
+ # @return [String]
212
+ #
213
+ # @api private
214
+ def render_line(line, left, right, intersection)
215
+ left + widths.map { |width| line * width }.join(intersection) + right
216
+ end
217
+ end # Border
218
+ end # Table
219
+ end # TTY
@@ -0,0 +1,251 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Table
5
+ # A class responsible for bulding and modifying border
6
+ #
7
+ # Used internally by {Table::Border} to allow for building custom border
8
+ # through DSL
9
+ # @api private
10
+ class BorderDSL
11
+ extend Forwardable
12
+
13
+ # Border options
14
+ #
15
+ # @return [Table::BorderOptions]
16
+ attr_reader :options
17
+
18
+ def_delegators :@options, :characters, :style
19
+
20
+ # Initialize a BorderDSL
21
+ #
22
+ # @param [Hash] characters
23
+ # the border characters
24
+ #
25
+ # @return [undefined]
26
+ #
27
+ # @api private
28
+ def initialize(characters = nil, &block)
29
+ @options = TTY::Table::BorderOptions.new
30
+ @options.characters = characters if characters
31
+ yield_or_eval(&block) if block_given?
32
+ end
33
+
34
+ # Apply style color to the border
35
+ #
36
+ # @param [Symbol] style
37
+ # the style color for the border
38
+ #
39
+ # @return [undefined]
40
+ #
41
+ # @api public
42
+ def style(value)
43
+ options.style = value
44
+ end
45
+
46
+ # Apply table tuple separator
47
+ #
48
+ # @param [Symbol] separator
49
+ # the table tuple separator
50
+ #
51
+ # @return [undefined]
52
+ #
53
+ # @api public
54
+ def separator(value)
55
+ value ? options.separator = value : options.separator
56
+ end
57
+
58
+ # Set top border character
59
+ #
60
+ # @param [String] value
61
+ # the character value
62
+ #
63
+ # @return [undefined]
64
+ #
65
+ # @api public
66
+ def top(value)
67
+ options.characters['top'] = value
68
+ end
69
+
70
+ # Set top middle border character
71
+ #
72
+ # @param [String] value
73
+ # the character value
74
+ #
75
+ # @return [undefined]
76
+ #
77
+ # @api public
78
+ def top_mid(value)
79
+ options.characters['top_mid'] = value
80
+ end
81
+
82
+ # Set top left corner border character
83
+ #
84
+ # @param [String] value
85
+ # the character value
86
+ #
87
+ # @return [undefined]
88
+ #
89
+ # @api public
90
+ def top_left(value)
91
+ options.characters['top_left'] = value
92
+ end
93
+
94
+ # Set top right corner border character
95
+ #
96
+ # @param [String] value
97
+ # the character value
98
+ #
99
+ # @return [undefined]
100
+ #
101
+ # @api public
102
+ def top_right(value)
103
+ options.characters['top_right'] = value
104
+ end
105
+
106
+ # Set bottom border character
107
+ #
108
+ # @param [String] value
109
+ # the character value
110
+ #
111
+ # @return [undefined]
112
+ #
113
+ # @api public
114
+ def bottom(value)
115
+ options.characters['bottom'] = value
116
+ end
117
+
118
+ # Set bottom middle border character
119
+ #
120
+ # @param [String] value
121
+ # the character value
122
+ #
123
+ # @return [undefined]
124
+ #
125
+ # @api public
126
+ def bottom_mid(value)
127
+ options.characters['bottom_mid'] = value
128
+ end
129
+
130
+ # Set bottom left corner border character
131
+ #
132
+ # @param [String] value
133
+ # the character value
134
+ #
135
+ # @return [undefined]
136
+ #
137
+ # @api public
138
+ def bottom_left(value)
139
+ options.characters['bottom_left'] = value
140
+ end
141
+
142
+ # Set bottom right corner border character
143
+ #
144
+ # @param [String] value
145
+ # the character value
146
+ #
147
+ # @return [undefined]
148
+ #
149
+ # @api public
150
+ def bottom_right(value)
151
+ options.characters['bottom_right'] = value
152
+ end
153
+
154
+ # Set middle border character
155
+ #
156
+ # @param [String] value
157
+ # the character value
158
+ #
159
+ # @return [undefined]
160
+ #
161
+ # @api public
162
+ def mid(value)
163
+ options.characters['mid'] = value
164
+ end
165
+
166
+ # Set middle border character
167
+ #
168
+ # @param [String] value
169
+ # the character value
170
+ #
171
+ # @return [undefined]
172
+ #
173
+ # @api public
174
+ def mid_mid(value)
175
+ options.characters['mid_mid'] = value
176
+ end
177
+
178
+ # Set middle left corner border character
179
+ #
180
+ # @param [String] value
181
+ # the character value
182
+ #
183
+ # @return [undefined]
184
+ #
185
+ # @api public
186
+ def mid_left(value)
187
+ options.characters['mid_left'] = value
188
+ end
189
+
190
+ # Set middle right corner border character
191
+ #
192
+ # @param [String] value
193
+ # the character value
194
+ #
195
+ # @return [undefined]
196
+ #
197
+ # @api public
198
+ def mid_right(value)
199
+ options.characters['mid_right'] = value
200
+ end
201
+
202
+ # Set left border character
203
+ #
204
+ # @param [String] value
205
+ # the character value
206
+ #
207
+ # @return [undefined]
208
+ #
209
+ # @api public
210
+ def left(value)
211
+ options.characters['left'] = value
212
+ end
213
+
214
+ # Set center border character
215
+ #
216
+ # @param [String] value
217
+ # the character value
218
+ #
219
+ # @return [undefined]
220
+ #
221
+ # @api public
222
+ def center(value)
223
+ options.characters['center'] = value
224
+ end
225
+
226
+ # Set right border character
227
+ #
228
+ # @param [String] value
229
+ # the character value
230
+ #
231
+ # @return [undefined]
232
+ #
233
+ # @api public
234
+ def right(value)
235
+ options.characters['right'] = value
236
+ end
237
+
238
+ private
239
+
240
+ # Evaluate block
241
+ #
242
+ # @return [Table]
243
+ #
244
+ # @api private
245
+ def yield_or_eval(&block)
246
+ return unless block
247
+ block.arity > 0 ? yield(self) : instance_eval(&block)
248
+ end
249
+ end # BorderDSL
250
+ end # Table
251
+ end # TTY
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Table
5
+ # A class that represents table border options
6
+ #
7
+ # Used internally by {Table::Border} to manage options such as style
8
+ #
9
+ # @api private
10
+ class BorderOptions < Struct.new(:characters, :separator, :style)
11
+ # Initialize a BorderOptions
12
+ #
13
+ # @api public
14
+ def initialize(*args)
15
+ super(*args)
16
+ self.characters = {} unless characters
17
+ end
18
+
19
+ # Create options instance from hash
20
+ #
21
+ # @api public
22
+ def self.from(value)
23
+ value ? new.update(value) : new
24
+ end
25
+
26
+ # Set all accessors with hash attributes
27
+ #
28
+ # @param [Hash, BorderOptions] obj
29
+ #
30
+ # @return [BorderOptions]
31
+ #
32
+ # @api public
33
+ def update(obj)
34
+ obj.each_pair do |key, value|
35
+ send("#{key}=", value)
36
+ end
37
+ self
38
+ end
39
+
40
+ # Convert to hash
41
+ #
42
+ # @api public
43
+ def to_hash
44
+ hash = {}
45
+ members.each do |key|
46
+ value = send(key)
47
+ hash[key.to_sym] = value if value
48
+ end
49
+ hash
50
+ end
51
+ end # BorderOptions
52
+ end # Table
53
+ end # TTY
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Table
5
+ # A class that represents table column properties.
6
+ #
7
+ # Used by {Table} to manage column sizing.
8
+ #
9
+ # @api private
10
+ class ColumnSet
11
+ include Equatable
12
+
13
+ attr_reader :table
14
+
15
+ # Initialize a ColumnSet
16
+ #
17
+ # @api public
18
+ def initialize(table)
19
+ @table = table
20
+ end
21
+
22
+ # Calculate total table width
23
+ #
24
+ # @return [Integer]
25
+ #
26
+ # @api public
27
+ def total_width
28
+ extract_widths.reduce(:+)
29
+ end
30
+
31
+ # Calcualte maximum column widths
32
+ #
33
+ # @return [Array] column widths
34
+ #
35
+ # @api private
36
+ def extract_widths
37
+ data = table.data
38
+ colcount = data.max { |row_a, row_b| row_a.size <=> row_b.size }.size
39
+
40
+ self.class.find_maximas(colcount, data)
41
+ end
42
+
43
+ # Assert data integrity for column widths
44
+ #
45
+ # @param [Array] column_widths
46
+ #
47
+ # @param [Integer] table_widths
48
+ #
49
+ # @raise [TTY::InvalidArgument]
50
+ #
51
+ # @api public
52
+ def self.assert_widths(column_widths, table_widths)
53
+ if column_widths.empty?
54
+ fail InvalidArgument, 'Value for :column_widths must be ' \
55
+ 'a non-empty array'
56
+ end
57
+ if column_widths.size != table_widths
58
+ fail InvalidArgument, 'Value for :column_widths must match ' \
59
+ 'table column count'
60
+ end
61
+ end
62
+
63
+ # Converts column widths to array format or infers default widths
64
+ #
65
+ # @param [TTY::Table] table
66
+ #
67
+ # @param [Array, Numeric, NilClass] column_widths
68
+ #
69
+ # @return [Array[Integer]]
70
+ #
71
+ # @api public
72
+ def self.widths_from(table, column_widths = nil)
73
+ case column_widths
74
+ when Array
75
+ assert_widths(column_widths, table.column_size)
76
+ Array(column_widths).map(&:to_i)
77
+ when Numeric
78
+ Array.new(table.column_size, column_widths)
79
+ when NilClass
80
+ new(table).extract_widths
81
+ else
82
+ fail TypeError, 'Invalid type for column widths'
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ # Find maximum widths for each row and header if present.
89
+ #
90
+ # @param [Integer] colcount
91
+ # number of columns
92
+ # @param [Array[Array]] data
93
+ # the table's header and rows
94
+ #
95
+ # @api private
96
+ def self.find_maximas(colcount, data)
97
+ maximas = []
98
+ start = 0
99
+
100
+ start.upto(colcount - 1) do |col_index|
101
+ maximas << find_maximum(data, col_index)
102
+ end
103
+ maximas
104
+ end
105
+
106
+ # Find a maximum column width. The calculation takes into account
107
+ # wether the content is escaped or not.
108
+ #
109
+ # @param [Array] data
110
+ # the table data
111
+ #
112
+ # @param [Integer] index
113
+ # the column index
114
+ #
115
+ # @api private
116
+ def self.find_maximum(data, index)
117
+ data.map { |row| (value = row.call(index)) ? value.length : 0 }.max
118
+ end
119
+ end # ColumnSet
120
+ end # Table
121
+ end # TTY