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
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Table
5
+ module Operation
6
+ # A class which responsiblity is to align table rows and header.
7
+ class Alignment
8
+ DEFAULT = :left
9
+
10
+ # Initialize an Alignment operation
11
+ #
12
+ # @api private
13
+ def initialize(alignments, widths = nil)
14
+ @alignments = alignments
15
+ @widths = widths
16
+ end
17
+
18
+ # Evaluate alignment of the provided row
19
+ #
20
+ # @param [Array] row
21
+ # the table row
22
+ # @param [Hash] options
23
+ # the table options
24
+ #
25
+ # @return [TTY::Table::Field]
26
+ #
27
+ # @api public
28
+ def call(field, row, col)
29
+ align_field(field, col)
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :alignments
35
+
36
+ attr_reader :widths
37
+
38
+ # Align each field in a row
39
+ #
40
+ # @param [TTY::Table::Field] field
41
+ # the table field
42
+ #
43
+ # @param [Integer] co
44
+ # the table column index
45
+ #
46
+ # @param [Hash] options
47
+ #
48
+ # @return [TTY::Table::Field]
49
+ #
50
+ # @api private
51
+ def align_field(field, col)
52
+ column_width = widths[col]
53
+ direction = field.alignment || alignments[col] || DEFAULT
54
+ Verse.align(field.content, column_width, direction)
55
+ end
56
+ end # Alignment
57
+ end # Operation
58
+ end # Table
59
+ end # TTY
@@ -20,7 +20,7 @@ module TTY
20
20
  #
21
21
  # @api public
22
22
  def call(field, row, col)
23
- field.value = field.value.to_s.gsub(/(\t|\r|\n)/) do |val|
23
+ field.content.gsub(/(\t|\r|\n)/) do |val|
24
24
  val.dump.gsub('"', '')
25
25
  end
26
26
  end
@@ -26,7 +26,7 @@ module TTY
26
26
  #
27
27
  # @api public
28
28
  def call(field, row, col)
29
- field.value = @filter.call(field.value, row, col)
29
+ @filter.call(field.content, row, col)
30
30
  end
31
31
  end # Filter
32
32
  end # Operation
@@ -1,36 +1,25 @@
1
- # -*- encoding: utf-8 -*-
1
+ # coding: utf-8
2
2
 
3
3
  module TTY
4
4
  class Table
5
5
  module Operation
6
-
7
6
  # A class responsible for padding field with whitespace
7
+ #
8
+ # Used internally by {Table::Renderer}
8
9
  class Padding
9
10
 
10
- attr_reader :padding_top
11
-
12
- attr_reader :padding_right
13
-
14
- attr_reader :padding_bottom
15
-
16
- attr_reader :padding_left
17
-
18
- attr_reader :padding_width
19
-
20
- attr_reader :multiline
11
+ attr_reader :widths
21
12
 
22
13
  # Initialize a Padding operation
23
14
  #
24
- # @param [TTY::Table::Padder]
15
+ # @param [TTY::Table::Padder] padding
16
+ #
17
+ # @param [Array[Integer]] widths
25
18
  #
26
19
  # @api public
27
- def initialize(padding, multiline)
28
- @padding_top = "\n" * padding.top
29
- @padding_right = ' ' * padding.right
30
- @padding_bottom = "\n" * padding.bottom
31
- @padding_left = ' ' * padding.left
32
- @padding_width = padding.left + padding.right
33
- @multiline = multiline
20
+ def initialize(padding, widths)
21
+ @padding = padding
22
+ @widths = widths
34
23
  end
35
24
 
36
25
  # Apply padding to a field
@@ -48,47 +37,9 @@ module TTY
48
37
  #
49
38
  # @api public
50
39
  def call(field, row, col)
51
- text = field.value.to_s
52
-
53
- text = multiline ? pad_multi_line(text) : pad_single_line(text)
54
- text.insert(0, padding_top).insert(-1, padding_bottom)
55
-
56
- field.value = text
40
+ column_width = widths[col]
41
+ Verse.pad(field.content, @padding)
57
42
  end
58
-
59
- # Apply padding to multi line text
60
- #
61
- # @param [String] text
62
- #
63
- # @return [String]
64
- #
65
- # @api private
66
- def pad_multi_line(text)
67
- text.split("\n", -1).map { |part| pad_around(part) }.join("\n")
68
- end
69
-
70
- # Apply padding to single line text
71
- #
72
- # @param [String] text
73
- #
74
- # @return [String]
75
- #
76
- # @api private
77
- def pad_single_line(text)
78
- pad_around(text.strip)
79
- end
80
-
81
- # Apply padding to left and right side of string
82
- #
83
- # @param [String] text
84
- #
85
- # @return [String]
86
- #
87
- # @api private
88
- def pad_around(text)
89
- text.insert(0, padding_left).insert(-1, padding_right)
90
- end
91
-
92
43
  end # Padding
93
44
  end # Operation
94
45
  end # Table
@@ -32,8 +32,8 @@ module TTY
32
32
  #
33
33
  # @api public
34
34
  def call(field, row, col)
35
- width = widths[col] || field.width
36
- field.value = Verse.truncate(field.value, width)
35
+ width = widths[col] || field.width
36
+ Verse.truncate(field.content, width)
37
37
  end
38
38
  end # Truncation
39
39
  end # Operation
@@ -9,14 +9,11 @@ module TTY
9
9
  class Wrapped
10
10
  attr_reader :widths
11
11
 
12
- attr_reader :padding
13
-
14
12
  # Initialize a Wrapped
15
13
  #
16
14
  # @api public
17
- def initialize(widths, padding)
15
+ def initialize(widths)
18
16
  @widths = widths
19
- @padding = padding.padding
20
17
  end
21
18
 
22
19
  # Apply wrapping to a field
@@ -35,7 +32,7 @@ module TTY
35
32
  # @api public
36
33
  def call(field, row, col)
37
34
  width = widths[col] || field.width
38
- field.value = Verse.wrap(field.value, width, padding: padding)
35
+ Verse.wrap(field.content, width)
39
36
  end
40
37
  end # Wrapped
41
38
  end # Operation
@@ -6,19 +6,6 @@ module TTY
6
6
  #
7
7
  # @api private
8
8
  class Operations
9
- # The table
10
- #
11
- # @api private
12
- attr_reader :table
13
- private :table
14
-
15
- # Available operations
16
- #
17
- # @return [Hash]
18
- #
19
- # @api public
20
- attr_reader :operations
21
-
22
9
  # Initialize Operations
23
10
  #
24
11
  # @param [TTY::Table] table
@@ -46,7 +33,19 @@ module TTY
46
33
  operations[operation_type] << object
47
34
  end
48
35
 
49
- # Apply operations to a table row
36
+ # Lookup operation
37
+ #
38
+ # @param [Symbol] operation
39
+ #
40
+ # @return [Object]
41
+ # the operation
42
+ #
43
+ # @api public
44
+ def [](operation)
45
+ operations[operation]
46
+ end
47
+
48
+ # Apply operations to a table data
50
49
  #
51
50
  # @param [Array[Symbol]] types
52
51
  # the operation types
@@ -58,12 +57,31 @@ module TTY
58
57
  # @api public
59
58
  def run_operations(*args)
60
59
  operation_types = args
61
- table.each_with_index do |val, row, col|
62
- operation_types.each do |type|
63
- operations[type].each { |op| op.call(val, row, col) }
60
+ table.data.each_with_index do |row, row_i|
61
+ row.fields.each_with_index do |field, col_i|
62
+ field.reset!
63
+ operation_types.each do |type|
64
+ operations[type].each do |operation|
65
+ field.content = operation.call(field, row_i, col_i)
66
+ end
67
+ end
64
68
  end
65
69
  end
66
70
  end
71
+
72
+ private
73
+
74
+ # The table
75
+ #
76
+ # @api private
77
+ attr_reader :table
78
+
79
+ # Available operations
80
+ #
81
+ # @return [Hash]
82
+ #
83
+ # @api public
84
+ attr_reader :operations
67
85
  end # Operations
68
86
  end # Table
69
87
  end # TTY
@@ -23,12 +23,12 @@ module TTY
23
23
  #
24
24
  # @api public
25
25
  def slice(table)
26
- header = table.header
27
- row_size = table.row_size
26
+ header = table.header
27
+ rows_size = table.rows_size
28
28
 
29
- head = header ? header : (0..row_size).map { |n| (n + 1).to_s }
29
+ head = header ? header : (0..rows_size).map { |n| (n + 1).to_s }
30
30
 
31
- (0...row_size).reduce([]) do |array, index|
31
+ (0...rows_size).reduce([]) do |array, index|
32
32
  array + head.zip(table.rows[index]).map { |row| table.to_row(row) }
33
33
  end
34
34
  end
@@ -8,22 +8,16 @@ module TTY
8
8
  #
9
9
  # @api private
10
10
  class Renderer
11
- autoload :ASCII, 'tty/table/renderer/ascii'
12
- autoload :Basic, 'tty/table/renderer/basic'
13
- autoload :Color, 'tty/table/renderer/color'
14
- autoload :Unicode, 'tty/table/renderer/unicode'
15
-
16
11
  RENDERER_MAPPER = {
17
12
  ascii: TTY::Table::Renderer::ASCII,
18
13
  basic: TTY::Table::Renderer::Basic,
19
- color: TTY::Table::Renderer::Color,
20
14
  unicode: TTY::Table::Renderer::Unicode
21
15
  }
22
16
 
23
17
  # Select renderer class based on string name.
24
18
  #
25
19
  # The possible values for renderer are
26
- # [:basic, :ascii, :unicode, :color]
20
+ # [:basic, :ascii, :unicode]
27
21
  #
28
22
  # @param [Symbol] renderer
29
23
  # the renderer used for displaying table
@@ -1,7 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'tty/table/validatable'
4
-
5
3
  module TTY
6
4
  class Table
7
5
  class Renderer
@@ -11,14 +9,6 @@ module TTY
11
9
  class Basic
12
10
  include TTY::Table::Validatable
13
11
 
14
- # Table to be rendered
15
- #
16
- # @return [TTY::Table]
17
- #
18
- # @api public
19
- attr_reader :table
20
- # private :table
21
-
22
12
  # Table border to be rendered
23
13
  #
24
14
  # @return [TTY::Table::Border]
@@ -38,12 +28,7 @@ module TTY
38
28
  # @return [Array]
39
29
  #
40
30
  # @api private
41
- attr_accessor :column_aligns
42
-
43
- # The table operations applied to rows
44
- #
45
- # @api public
46
- attr_reader :operations
31
+ attr_accessor :alignments
47
32
 
48
33
  # A callable object used for formatting field content
49
34
  #
@@ -63,7 +48,7 @@ module TTY
63
48
  # @return [Integer]
64
49
  #
65
50
  # @api public
66
- attr_accessor :indent
51
+ attr_reader :indent
67
52
 
68
53
  # The table totabl width
69
54
  #
@@ -91,8 +76,10 @@ module TTY
91
76
  # Initialize a Renderer
92
77
  #
93
78
  # @param [Hash] options
94
- # @option options [String] :column_aligns
79
+ # @option options [String] :alignments
95
80
  # used to format table individual column alignment
81
+ # @option options [Hash[Symbol]] :border
82
+ # the border options
96
83
  # @option options [String] :column_widths
97
84
  # used to format table individula column width
98
85
  # @option options [Integer] :indent
@@ -106,17 +93,16 @@ module TTY
106
93
  def initialize(table, options = {})
107
94
  @table = assert_table_type(table)
108
95
  @multiline = options.fetch(:multiline) { false }
109
- @operations = TTY::Table::Operations.new(table)
110
- @operations.add(:escape, Operation::Escape.new)
111
96
  @border = TTY::Table::BorderOptions.from(options.delete(:border))
112
97
  @column_widths = options.fetch(:column_widths, nil)
113
- @column_aligns = Array(options.delete(:column_aligns)).map(&:to_sym)
98
+ alignment = Array(options[:alignment]) * table.columns_size
99
+ @alignments = TTY::Table::AlignmentSet.new(options[:alignments] || alignment)
114
100
  @filter = options.fetch(:filter) { proc { |val, _| val } }
115
101
  @width = options.fetch(:width) { TTY::Screen.width }
116
102
  @border_class = options.fetch(:border_class) { Border::Null }
117
103
  @indent = options.fetch(:indent) { 0 }
118
104
  @resize = options.fetch(:resize) { false }
119
- @padding = TTY::Table::Padder.parse(options[:padding])
105
+ @padding = Verse::Padder.parse(options[:padding])
120
106
  end
121
107
 
122
108
  # Parses supplied column widths, if not present
@@ -147,40 +133,16 @@ module TTY
147
133
  end
148
134
  @border
149
135
  end
136
+ alias_method :border=, :border
150
137
 
151
- # Initialize and add operations
152
- #
153
- # @api private
154
- def add_operations
155
- operations.add(:alignment, Operation::AlignmentSet.new(column_aligns,
156
- column_widths))
157
- operations.add(:filter, Operation::Filter.new(filter))
158
- operations.add(:truncation, Operation::Truncation.new(column_widths))
159
- operations.add(:wrapping, Operation::Wrapped.new(column_widths, padding))
160
- operations.add(:padding, Operation::Padding.new(padding, multiline))
161
- end
162
-
163
- # Initializes indentation
138
+ # Change the value of indentation
164
139
  #
165
- # @return [TTY::Table::Indentation]
166
- #
167
- # @api private
168
- def indentation
169
- @indentation ||= TTY::Table::Indentation.new(self)
170
- end
171
-
172
- # Delegate indentation insertion
140
+ # @param [Integer]
141
+ # the indentation value
173
142
  #
174
143
  # @api public
175
- def insert_indent(line)
176
- indentation.insert_indent(line)
177
- end
178
-
179
- # Return column contraints
180
- #
181
- # @api private
182
- def columns_constraints
183
- TTY::Table::Columns.new(self)
144
+ def indent=(value)
145
+ @indentation.indentation = value
184
146
  end
185
147
 
186
148
  # Sets the output padding,
@@ -190,37 +152,81 @@ module TTY
190
152
  #
191
153
  # @api public
192
154
  def padding=(value)
193
- @padding = TTY::Table::Padder.parse(value)
155
+ @padding = Verse::Padder.parse(value)
194
156
  end
195
157
 
196
- # Renders table
158
+ # Renders table as string with border
197
159
  #
198
- # @return [String] string representation of table
160
+ # @example
161
+ # renderer = TTY::Table::Renderer::Basic.new(table)
162
+ # renderer.render
163
+ #
164
+ # @return [String]
165
+ # the string representation of table
199
166
  #
200
167
  # @api public
201
168
  def render
202
169
  return if table.empty?
203
170
 
204
- operations.run_operations(:escape) unless multiline
205
- columns_constraints.enforce
206
- add_operations
207
- ops = [:alignment]
208
- ops << :padding unless padding.empty?
209
- multiline ? ops << :wrapping : ops << :truncation
171
+ @operations = TTY::Table::Operations.new(table)
172
+ @operations.add(:escape, Operation::Escape.new)
173
+ @operations.run_operations(:escape) unless multiline
174
+ column_constraint = ColumnConstraint.new(table, self)
175
+ @column_widths = column_constraint.enforce
176
+ add_operations(@column_widths)
177
+ ops = []
178
+ ops << :escape unless multiline
179
+ ops << :alignment
180
+ ops << (multiline ? :wrapping : :truncation)
181
+ ops << :padding
210
182
  ops << :filter
211
- operations.run_operations(*ops)
183
+ @operations.run_operations(*ops)
212
184
 
213
185
  render_data.compact.join("\n")
214
186
  end
215
187
 
188
+ # Initialize and add operations
189
+ #
190
+ # @api private
191
+ def add_operations(widths)
192
+ @operations.add(:alignment, Operation::Alignment.new(alignments, widths))
193
+ @operations.add(:filter, Operation::Filter.new(filter))
194
+ @operations.add(:truncation, Operation::Truncation.new(widths))
195
+ @operations.add(:wrapping, Operation::Wrapped.new(widths))
196
+ @operations.add(:padding, Operation::Padding.new(padding, widths))
197
+ end
198
+
216
199
  private
217
200
 
201
+ # Table to be rendered
202
+ #
203
+ # @return [TTY::Table]
204
+ #
205
+ # @api public
206
+ attr_reader :table
207
+
208
+ # Initializes indentation
209
+ #
210
+ # @return [TTY::Table::Indentation]
211
+ #
212
+ # @api private
213
+ def indentation
214
+ @indentation ||= TTY::Table::Indentation.new(indent)
215
+ end
216
+
217
+ # Delegate indentation insertion
218
+ #
219
+ # @api public
220
+ def insert_indent(line)
221
+ indentation.indent(line)
222
+ end
223
+
218
224
  # Render table data
219
225
  #
220
226
  # @api private
221
227
  def render_data
222
228
  first_row = table.first
223
- data_border = border_class.new(column_widths, border)
229
+ data_border = border_class.new(column_widths, padding, border)
224
230
  header = render_header(first_row, data_border)
225
231
  rows_with_border = render_rows(data_border)
226
232
  bottom_line = data_border.bottom_line