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