tty-table 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/README.md +458 -142
  4. data/lib/tty-table.rb +6 -6
  5. data/lib/tty/table.rb +34 -34
  6. data/lib/tty/table/alignment_set.rb +73 -0
  7. data/lib/tty/table/border.rb +54 -36
  8. data/lib/tty/table/border/null.rb +4 -4
  9. data/lib/tty/table/{columns.rb → column_constraint.rb} +30 -32
  10. data/lib/tty/table/column_set.rb +18 -17
  11. data/lib/tty/table/field.rb +50 -25
  12. data/lib/tty/table/header.rb +6 -2
  13. data/lib/tty/table/indentation.rb +7 -12
  14. data/lib/tty/table/operation/alignment.rb +59 -0
  15. data/lib/tty/table/operation/escape.rb +1 -1
  16. data/lib/tty/table/operation/filter.rb +1 -1
  17. data/lib/tty/table/operation/padding.rb +12 -61
  18. data/lib/tty/table/operation/truncation.rb +2 -2
  19. data/lib/tty/table/operation/wrapped.rb +2 -5
  20. data/lib/tty/table/operations.rb +35 -17
  21. data/lib/tty/table/orientation/vertical.rb +4 -4
  22. data/lib/tty/table/renderer.rb +1 -7
  23. data/lib/tty/table/renderer/basic.rb +69 -63
  24. data/lib/tty/table/version.rb +1 -1
  25. data/spec/spec_helper.rb +3 -4
  26. data/spec/unit/access_spec.rb +8 -8
  27. data/spec/unit/{operation/alignment_set → alignment_set}/each_spec.rb +1 -1
  28. data/spec/unit/{operation/alignment_set → alignment_set}/new_spec.rb +4 -4
  29. data/spec/unit/{operation/alignment_set → alignment_set}/to_ary_spec.rb +1 -1
  30. data/spec/unit/alignment_spec.rb +71 -0
  31. data/spec/unit/border/ascii/rendering_spec.rb +12 -12
  32. data/spec/unit/border/new_spec.rb +2 -2
  33. data/spec/unit/border/null/rendering_spec.rb +2 -2
  34. data/spec/unit/border/unicode/rendering_spec.rb +10 -10
  35. data/spec/unit/{columns → column_constraint}/enforce_spec.rb +15 -12
  36. data/spec/unit/{columns → column_constraint}/widths_spec.rb +6 -6
  37. data/spec/unit/column_set/extract_widths_spec.rb +39 -6
  38. data/spec/unit/data_spec.rb +4 -6
  39. data/spec/unit/each_spec.rb +8 -23
  40. data/spec/unit/each_with_index_spec.rb +27 -33
  41. data/spec/unit/field/length_spec.rb +23 -9
  42. data/spec/unit/field/width_spec.rb +1 -1
  43. data/spec/unit/filter_spec.rb +7 -8
  44. data/spec/unit/header/new_spec.rb +6 -15
  45. data/spec/unit/indentation/indent_spec.rb +21 -0
  46. data/spec/unit/new_spec.rb +73 -0
  47. data/spec/unit/operation/{alignment_set → alignment}/call_spec.rb +1 -1
  48. data/spec/unit/operation/escape/call_spec.rb +2 -3
  49. data/spec/unit/operation/filter/call_spec.rb +2 -3
  50. data/spec/unit/operation/truncation/call_spec.rb +6 -8
  51. data/spec/unit/operation/wrapped/call_spec.rb +15 -8
  52. data/spec/unit/operations/new_spec.rb +1 -1
  53. data/spec/unit/orientation_spec.rb +6 -6
  54. data/spec/unit/padding_spec.rb +29 -32
  55. data/spec/unit/properties_spec.rb +4 -4
  56. data/spec/unit/render_repeat_spec.rb +42 -0
  57. data/spec/unit/render_spec.rb +1 -1
  58. data/spec/unit/render_with_spec.rb +3 -3
  59. data/spec/unit/renderer/ascii/coloring_spec.rb +70 -0
  60. data/spec/unit/renderer/ascii/multiline_spec.rb +101 -0
  61. data/spec/unit/renderer/ascii/padding_spec.rb +37 -10
  62. data/spec/unit/renderer/ascii/render_spec.rb +4 -4
  63. data/spec/unit/renderer/ascii/resizing_spec.rb +22 -22
  64. data/spec/unit/renderer/ascii/separator_spec.rb +1 -1
  65. data/spec/unit/renderer/basic/alignment_spec.rb +20 -20
  66. data/spec/unit/renderer/basic/coloring_spec.rb +43 -28
  67. data/spec/unit/renderer/basic/filter_spec.rb +3 -3
  68. data/spec/unit/renderer/basic/multiline_spec.rb +74 -0
  69. data/spec/unit/renderer/basic/options_spec.rb +9 -9
  70. data/spec/unit/renderer/basic/padding_spec.rb +26 -2
  71. data/spec/unit/renderer/basic/render_spec.rb +4 -4
  72. data/spec/unit/renderer/basic/resizing_spec.rb +18 -18
  73. data/spec/unit/renderer/basic/separator_spec.rb +1 -1
  74. data/spec/unit/renderer/basic/truncation_spec.rb +6 -6
  75. data/spec/unit/renderer/basic/wrapping_spec.rb +3 -3
  76. data/spec/unit/renderer/border_spec.rb +4 -4
  77. data/spec/unit/renderer/unicode/coloring_spec.rb +70 -0
  78. data/spec/unit/renderer/unicode/indentation_spec.rb +1 -1
  79. data/spec/unit/renderer/unicode/padding_spec.rb +26 -26
  80. data/spec/unit/renderer/unicode/render_spec.rb +4 -4
  81. data/spec/unit/renderer/unicode/separator_spec.rb +1 -1
  82. data/spec/unit/to_s_spec.rb +4 -11
  83. data/spec/unit/utf_spec.rb +33 -0
  84. data/tty-table.gemspec +2 -1
  85. metadata +52 -32
  86. data/lib/tty/table/operation/alignment_set.rb +0 -103
  87. data/lib/tty/table/padder.rb +0 -180
  88. data/lib/tty/table/renderer/color.rb +0 -12
  89. data/spec/unit/indentation/insert_indent_spec.rb +0 -27
  90. data/spec/unit/initialize_spec.rb +0 -88
  91. data/spec/unit/padder/parse_spec.rb +0 -45
  92. data/spec/unit/padder/to_s_spec.rb +0 -14
  93. data/spec/unit/renderer/basic/multiline_content_spec.rb +0 -135
  94. data/spec/unit/renderer/style_spec.rb +0 -72
data/lib/tty-table.rb CHANGED
@@ -6,6 +6,7 @@ require 'necromancer'
6
6
  require 'verse'
7
7
  require 'tty-screen'
8
8
  require 'pastel'
9
+ require 'unicode_utils'
9
10
 
10
11
  require 'tty/table/header'
11
12
  require 'tty/table/row'
@@ -22,23 +23,22 @@ require 'tty/table/border/ascii'
22
23
  require 'tty/table/border/null'
23
24
  require 'tty/table/border/row_line'
24
25
 
25
- require 'tty/table/renderer'
26
- require 'tty/table/renderer/ascii'
27
26
  require 'tty/table/renderer/basic'
28
- require 'tty/table/renderer/color'
27
+ require 'tty/table/renderer/ascii'
29
28
  require 'tty/table/renderer/unicode'
29
+ require 'tty/table/renderer'
30
30
 
31
+ require 'tty/table/alignment_set'
31
32
  require 'tty/table/column_set'
32
- require 'tty/table/columns'
33
+ require 'tty/table/column_constraint'
33
34
  require 'tty/table/orientation'
34
35
  require 'tty/table/orientation/horizontal'
35
36
  require 'tty/table/orientation/vertical'
36
37
  require 'tty/table/transformation'
37
38
  require 'tty/table/indentation'
38
- require 'tty/table/padder'
39
39
 
40
40
  require 'tty/table/operations'
41
- require 'tty/table/operation/alignment_set'
41
+ require 'tty/table/operation/alignment'
42
42
  require 'tty/table/operation/truncation'
43
43
  require 'tty/table/operation/wrapped'
44
44
  require 'tty/table/operation/filter'
data/lib/tty/table.rb CHANGED
@@ -61,19 +61,18 @@ module TTY
61
61
  # Instantiate a new Table
62
62
  #
63
63
  # @example of no header
64
- # rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
65
- # table = Table.new rows
64
+ # table = Table.new [['a1', 'a2'], ['b1', 'b2']]
66
65
  #
67
66
  # @example of direct parameters
68
- # rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
67
+ # rows = [['a1', 'a2'], ['b1', 'b2']]
69
68
  # table = Table.new ['Header 1', 'Header 2'], rows
70
69
  #
71
70
  # @example of parameters passed as options
72
- # rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
71
+ # rows = [['a1', 'a2'], ['b1', 'b2']]
73
72
  # table = Table.new header: ['Header 1', 'Header 2'], rows: rows
74
73
  #
75
74
  # @example of parameters passed as hash
76
- # Table.new [ {'Header1' => ['a1','a2'], 'Header2' => ['b1', 'b2'] }] }
75
+ # Table.new [{'Header1' => ['a1','a2'], 'Header2' => ['b1', 'b2'] }]}
77
76
  #
78
77
  # @param [Array[Symbol], Hash] *args
79
78
  #
@@ -156,8 +155,8 @@ module TTY
156
155
  #
157
156
  # @api private
158
157
  def rotate_vertical
159
- @original_columns = column_size
160
- @original_rows = row_size
158
+ @original_columns = columns_size
159
+ @original_rows = rows_size
161
160
  @rows = orientation.slice(self)
162
161
  @header = [] if header
163
162
  @rotated = true
@@ -179,6 +178,15 @@ module TTY
179
178
 
180
179
  # Lookup element of the table given a row(i) and column(j)
181
180
  #
181
+ # @param [Integer] row_index
182
+ # @param [Integer] column_index
183
+ #
184
+ # @example
185
+ # table = TTY::Table.new [['a1','a2'], ['b1','b2']]
186
+ # table[0] # => ['a1','a2']
187
+ # table[0,0] # => 'a1'
188
+ # table[-1] # => ['b1','b2']
189
+ #
182
190
  # @api public
183
191
  def [](row_index, column_index = false)
184
192
  return row(row_index) unless column_index
@@ -188,9 +196,9 @@ module TTY
188
196
  fail TTY::Table::TupleMissing.new(row_index, column_index)
189
197
  end
190
198
  end
191
- alias at []
192
- alias element []
193
- alias component []
199
+ alias_method :at, :[]
200
+ alias_method :element, :[]
201
+ alias_method :component, :[]
194
202
 
195
203
  # Set table value at row(i) and column(j)
196
204
  #
@@ -204,9 +212,9 @@ module TTY
204
212
  # When a block is given, the elements of that Array are iterated over.
205
213
  #
206
214
  # @example
207
- # rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
208
- # table = TTY::Table.new :rows => rows
209
- # table.row(1) { |element| ... }
215
+ # rows = [['a1', 'a2'], ['b1', 'b2']]
216
+ # table = TTY::Table.new rows: rows
217
+ # table.row(1) { |row| ... }
210
218
  #
211
219
  # @param [Integer] index
212
220
  #
@@ -247,7 +255,7 @@ module TTY
247
255
  #
248
256
  # @api public
249
257
  def column(index)
250
- index_unknown = index.is_a?(Integer) && (index >= column_size || index < 0)
258
+ index_unknown = index.is_a?(Integer) && (index >= columns_size || index < 0)
251
259
  if block_given?
252
260
  return self if index_unknown
253
261
  rows.map { |row| yield row[index] }
@@ -288,29 +296,22 @@ module TTY
288
296
  self
289
297
  end
290
298
 
291
- # Iterate over each element yielding in addition row and column index
299
+ # Same as #each but passes the index of the row with the row itself
292
300
  #
293
301
  # @example
294
302
  # table = TTY::Table.new(header, tuples)
295
- # table.each_with_index { |el, row, col| puts "#{el} at #{row},#{col}" }
303
+ # table.each_with_index { |row, index|
304
+ # puts "#{row} at #{index}"
305
+ # }
296
306
  #
297
307
  # @return self
298
308
  #
299
309
  # @api public
300
310
  def each_with_index
301
311
  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
312
+ start_index = -1
313
+ data.each do |row|
314
+ yield row.to_a, start_index += 1
314
315
  end
315
316
  self
316
317
  end
@@ -318,13 +319,12 @@ module TTY
318
319
  # Return the number of columns
319
320
  #
320
321
  # @example
321
- # table.column_size # => 5
322
+ # table.columns_size # => 5
322
323
  #
323
324
  # @return [Integer]
324
325
  #
325
326
  # @api public
326
- # TODO: renmae to columns_size
327
- def column_size
327
+ def columns_size
328
328
  rows.size > 0 ? rows[0].size : 0
329
329
  end
330
330
 
@@ -336,7 +336,7 @@ module TTY
336
336
  # @return [Integer]
337
337
  #
338
338
  # @api public
339
- def row_size
339
+ def rows_size
340
340
  rows.size
341
341
  end
342
342
 
@@ -349,7 +349,7 @@ module TTY
349
349
  #
350
350
  # @api public
351
351
  def size
352
- [row_size, column_size]
352
+ [rows_size, columns_size]
353
353
  end
354
354
 
355
355
  # Check table width
@@ -368,7 +368,7 @@ module TTY
368
368
  #
369
369
  # @api public
370
370
  def empty?
371
- column_size == 0 || row_size == 0
371
+ columns_size == 0 || rows_size == 0
372
372
  end
373
373
 
374
374
  # Return string representation of table using basic renderer.
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Table
5
+ # A class responsible for column alignments
6
+ #
7
+ # Used internally by {TTY::Table::Operation::Alignment}
8
+ class AlignmentSet
9
+ include Enumerable
10
+
11
+ DEFAULT = :left
12
+
13
+ # Initialize an AlignmentSet
14
+ #
15
+ # @param [AlignmentSet, Array] alignments
16
+ # the alignments for the renderer
17
+ #
18
+ # @api private
19
+ def initialize(alignments)
20
+ @converter = Necromancer.new
21
+ @alignments = @converter.convert(alignments).to(:array).map(&:to_sym)
22
+ end
23
+
24
+ # Iterate over each element in the alignment set
25
+ #
26
+ # @example
27
+ # alignment = AlignmentSet.new [1,2,3]
28
+ # alignment.each { |element| ... }
29
+ #
30
+ # @return [self]
31
+ #
32
+ # @api public
33
+ def each
34
+ return to_enum unless block_given?
35
+ to_ary.each { |element| yield element }
36
+ self
37
+ end
38
+
39
+ # Lookup an alignment by index
40
+ #
41
+ # @param [Integer]
42
+ #
43
+ # @return [Symbol] alignment
44
+ #
45
+ # @api public
46
+ def [](index)
47
+ alignments.fetch(index, DEFAULT)
48
+ end
49
+
50
+ # Convert to array
51
+ #
52
+ # @return [Array]
53
+ #
54
+ # @api public
55
+ def to_ary
56
+ alignments.to_a
57
+ end
58
+
59
+ # String representation of aligments
60
+ #
61
+ # @return [String]
62
+ #
63
+ # @api public
64
+ def to_s
65
+ to_ary
66
+ end
67
+
68
+ private
69
+
70
+ attr_reader :alignments
71
+ end # AlignmentSet
72
+ end # Table
73
+ end # TTY
@@ -13,17 +13,6 @@ module TTY
13
13
  # Represent a separtor on each row
14
14
  EACH_ROW = :each_row
15
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
16
  class << self
28
17
  # Store characters for border
29
18
  #
@@ -41,12 +30,13 @@ module TTY
41
30
  # @return [Object]
42
31
  #
43
32
  # @api private
44
- def initialize(column_widths, options = nil)
33
+ def initialize(column_widths, padding, options = nil)
45
34
  if self.class == Border
46
35
  fail NotImplementedError, "#{self} is an abstract class"
47
36
  else
48
37
  @widths = column_widths
49
- @border = TTY::Table::BorderOptions.from options
38
+ @padding = Verse::Padder.parse(padding)
39
+ @border_options = TTY::Table::BorderOptions.from options
50
40
  @color = Pastel.new
51
41
  end
52
42
  end
@@ -66,7 +56,7 @@ module TTY
66
56
  self.characters = dsl.characters
67
57
  end
68
58
 
69
- # Retrive individula character by type
59
+ # Retrive individual character by type
70
60
  #
71
61
  # @param [String] type
72
62
  # the character type
@@ -76,7 +66,11 @@ module TTY
76
66
  # @api private
77
67
  def [](type)
78
68
  characters = self.class.characters
79
- chars = border.nil? ? characters : characters.merge(border.characters)
69
+ chars = if border_options.nil?
70
+ characters
71
+ else
72
+ characters.merge(border_options.characters)
73
+ end
80
74
  chars[type] || EMPTY_CHAR
81
75
  end
82
76
 
@@ -86,20 +80,7 @@ module TTY
86
80
  #
87
81
  # @api public
88
82
  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) }
83
+ border_options && border_options.style
103
84
  end
104
85
 
105
86
  # A line spanning all columns marking top of a table.
@@ -139,14 +120,48 @@ module TTY
139
120
  # @api public
140
121
  def row_line(row)
141
122
  line = RowLine.new(self['left'], self['center'], self['right'])
142
- line.colorize(self, border.style) if color?
123
+ line.colorize(self, border_options.style) if color?
143
124
 
144
125
  result = row_heights(row, line)
145
126
  result.empty? ? EMPTY_CHAR : result
146
127
  end
147
128
 
129
+ # Set color on characters
130
+ #
131
+ # @param [Symbol] color
132
+ #
133
+ # @param [Array[String]] array of strings
134
+ #
135
+ # @return [Array[String]]
136
+ #
137
+ # @api public
138
+ def set_color(color, *strings)
139
+ strings.map do |string|
140
+ if string.gsub(/\s+/, '').empty?
141
+ string
142
+ else
143
+ @color.decorate(string, color)
144
+ end
145
+ end
146
+ end
147
+
148
148
  protected
149
149
 
150
+ # The row field widths
151
+ #
152
+ # @api private
153
+ attr_reader :widths
154
+
155
+ # The table custom border options including styling
156
+ #
157
+ # @api private
158
+ attr_reader :border_options
159
+
160
+ # The padding to apply to each field
161
+ #
162
+ # @api private
163
+ attr_reader :padding
164
+
150
165
  # Separate multiline string into individual rows with border.
151
166
  #
152
167
  # @param [TTY::Table::Row] row
@@ -180,7 +195,9 @@ module TTY
180
195
  # @api private
181
196
  def row_height_line(row, line_index, line)
182
197
  line.left + row.fields.each_with_index.map do |field, index|
183
- (field.lines[line_index] || EMPTY_CHAR).ljust(widths[index])
198
+ direction = field.alignment || :left
199
+ field_content = field.lines[line_index] || SPACE_CHAR * field.length
200
+ Verse.align(field_content, widths[index], direction)
184
201
  end.join(line.center) + line.right
185
202
  end
186
203
 
@@ -198,21 +215,22 @@ module TTY
198
215
  self["#{type}_right"] || border_char,
199
216
  self["#{type}_mid"])
200
217
 
201
- if color? && !line.empty?
202
- line = set_color(border.style, line)
203
- end
204
- line
218
+ return line unless color?
219
+ set_color(border_options.style, line).join
205
220
  end
206
221
 
207
222
  # Generate a border string
208
223
  #
209
224
  # @param [String] line
225
+ # the line character
210
226
  #
211
227
  # @return [String]
212
228
  #
213
229
  # @api private
214
230
  def render_line(line, left, right, intersection)
215
- left + widths.map { |width| line * width }.join(intersection) + right
231
+ left + widths.map do |width|
232
+ line * (padding.left + width + padding.right)
233
+ end.join(intersection) + right
216
234
  end
217
235
  end # Border
218
236
  end # Table
@@ -14,22 +14,22 @@ module TTY
14
14
  #
15
15
  # @api private
16
16
  def top_line
17
- border ? super : nil
17
+ border_options ? super : nil
18
18
  end
19
19
 
20
20
  # A stub separator line
21
21
  #
22
22
  # @api private
23
23
  def separator
24
- return [] if border.separator == EACH_ROW
25
- border ? super : nil
24
+ return [] if border_options.separator == EACH_ROW
25
+ border_options ? super : nil
26
26
  end
27
27
 
28
28
  # A stub bottom line
29
29
  #
30
30
  # @api private
31
31
  def bottom_line
32
- border ? super : nil
32
+ border_options ? super : nil
33
33
  end
34
34
  end # Null
35
35
  end # Border