tty-table 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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