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
@@ -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