tty-table 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -3
  3. data/CHANGELOG.md +16 -0
  4. data/Gemfile +4 -4
  5. data/README.md +3 -3
  6. data/appveyor.yml +2 -0
  7. data/benchmarks/speed.rb +3 -5
  8. data/examples/alignment.rb +3 -3
  9. data/examples/basic.rb +2 -2
  10. data/examples/orientation.rb +13 -0
  11. data/examples/padding.rb +15 -0
  12. data/examples/resize.rb +15 -0
  13. data/lib/tty/table.rb +2 -1
  14. data/lib/tty/table/border.rb +4 -12
  15. data/lib/tty/table/column_constraint.rb +15 -7
  16. data/lib/tty/table/columns.rb +42 -68
  17. data/lib/tty/table/field.rb +3 -13
  18. data/lib/tty/table/indentation.rb +9 -20
  19. data/lib/tty/table/operation/alignment.rb +2 -2
  20. data/lib/tty/table/operation/padding.rb +3 -3
  21. data/lib/tty/table/operation/truncation.rb +3 -3
  22. data/lib/tty/table/operation/wrapped.rb +3 -3
  23. data/lib/tty/table/operations.rb +3 -14
  24. data/lib/tty/table/renderer.rb +28 -24
  25. data/lib/tty/table/renderer/ascii.rb +1 -1
  26. data/lib/tty/table/renderer/basic.rb +42 -41
  27. data/lib/tty/table/renderer/unicode.rb +1 -1
  28. data/lib/tty/table/version.rb +1 -3
  29. data/spec/unit/border/ascii/rendering_spec.rb +1 -1
  30. data/spec/unit/border/null/rendering_spec.rb +1 -1
  31. data/spec/unit/border/unicode/rendering_spec.rb +1 -1
  32. data/spec/unit/column_constraint/enforce_spec.rb +2 -2
  33. data/spec/unit/columns/extract_widths_spec.rb +7 -12
  34. data/spec/unit/columns/total_width_spec.rb +3 -4
  35. data/spec/unit/indentation/indent_spec.rb +2 -6
  36. data/spec/unit/operations/new_spec.rb +3 -5
  37. data/spec/unit/renderer/ascii/padding_spec.rb +29 -0
  38. data/tty-table.gemspec +3 -4
  39. metadata +12 -24
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'equatable'
4
4
  require 'pastel'
5
- require 'unicode/display_width'
5
+ require 'strings'
6
6
 
7
7
  module TTY
8
8
  class Table
@@ -104,7 +104,7 @@ module TTY
104
104
  #
105
105
  # @api public
106
106
  def width
107
- @width || display_width(@content)
107
+ @width || Strings::Align.display_width(@content)
108
108
  end
109
109
 
110
110
  # Return number of lines this value spans.
@@ -127,7 +127,7 @@ module TTY
127
127
  # @api public
128
128
  def length
129
129
  (lines.map do |line|
130
- display_width(self.class.color.strip(line))
130
+ Strings::Align.display_width(line)
131
131
  end << 0).max
132
132
  end
133
133
 
@@ -152,16 +152,6 @@ module TTY
152
152
  def to_s
153
153
  content
154
154
  end
155
-
156
- # @api public
157
- def self.color
158
- @color ||= Pastel.new(enabled: true)
159
- end
160
-
161
- # @api public
162
- def display_width(string)
163
- Unicode::DisplayWidth.of(string)
164
- end
165
155
  end # Field
166
156
  end # Table
167
157
  end # TTY
@@ -1,36 +1,24 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module TTY
4
5
  class Table
5
- # A class responsible for indenting table representation
6
- class Indentation
7
- # The amount of indentation
8
- #
9
- # @api public
10
- attr_accessor :indentation
11
-
12
- # Initialize an Indentation
13
- #
14
- # @api public
15
- def initialize(indentation)
16
- @indentation = indentation
17
- end
18
-
6
+ # A module responsible for indenting table representation
7
+ module Indentation
19
8
  # Return a table part with indentation inserted
20
9
  #
21
10
  # @param [#map, #to_s] part
22
11
  # the rendered table part
23
12
  #
24
13
  # @api public
25
- def indent(part)
14
+ def indent(part, indentation)
26
15
  if part.respond_to?(:to_a)
27
- part.map { |line| insert_indentation(line) }
16
+ part.map { |line| insert_indentation(line, indentation) }
28
17
  else
29
- insert_indentation(part)
18
+ insert_indentation(part, indentation)
30
19
  end
31
20
  end
32
-
33
- private
21
+ module_function :indent
34
22
 
35
23
  # Insert indentation into a table renderd line
36
24
  #
@@ -38,10 +26,11 @@ module TTY
38
26
  # the rendered table line
39
27
  #
40
28
  # @api public
41
- def insert_indentation(line)
29
+ def insert_indentation(line, indentation)
42
30
  line = line.is_a?(Array) ? line[0] : line
43
31
  line.insert(0, ' ' * indentation) if line
44
32
  end
33
+ module_function :insert_indentation
45
34
  end # Indentation
46
35
  end # Table
47
36
  end # TTY
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'verse'
3
+ require 'strings'
4
4
 
5
5
  module TTY
6
6
  class Table
@@ -53,7 +53,7 @@ module TTY
53
53
  def align_field(field, col)
54
54
  column_width = widths[col]
55
55
  direction = field.alignment || alignments[col] || DEFAULT
56
- Verse.align(field.content, column_width, direction)
56
+ Strings.align(field.content, column_width, direction: direction)
57
57
  end
58
58
  end # Alignment
59
59
  end # Operation
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'verse'
3
+ require 'strings'
4
4
 
5
5
  module TTY
6
6
  class Table
@@ -11,7 +11,7 @@ module TTY
11
11
  class Padding
12
12
  # Initialize a Padding operation
13
13
  #
14
- # @param [Verse::Padder] padding
14
+ # @param [Strings::Padder] padding
15
15
  #
16
16
  # @param [Array[Integer]] widths
17
17
  #
@@ -35,7 +35,7 @@ module TTY
35
35
  #
36
36
  # @api public
37
37
  def call(field, *)
38
- Verse.pad(field.content, padding)
38
+ Strings.pad(field.content, padding)
39
39
  end
40
40
 
41
41
  protected
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'verse'
3
+ require 'strings'
4
4
 
5
5
  module TTY
6
6
  class Table
@@ -34,8 +34,8 @@ module TTY
34
34
  #
35
35
  # @api public
36
36
  def call(field, row, col)
37
- width = widths[col] || field.width
38
- Verse.truncate(field.content, width)
37
+ column_width = widths[col] || field.width
38
+ Strings.truncate(field.content, column_width)
39
39
  end
40
40
  end # Truncation
41
41
  end # Operation
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'verse'
3
+ require 'strings'
4
4
 
5
5
  module TTY
6
6
  class Table
@@ -33,8 +33,8 @@ module TTY
33
33
  #
34
34
  # @api public
35
35
  def call(field, row, col)
36
- width = widths[col] || field.width
37
- Verse.wrap(field.content, width)
36
+ column_width = widths[col] || field.width
37
+ Strings.wrap(field.content, column_width)
38
38
  end
39
39
  end # Wrapped
40
40
  end # Operation
@@ -8,14 +8,8 @@ module TTY
8
8
  class Operations
9
9
  # Initialize Operations
10
10
  #
11
- # @param [TTY::Table] table
12
- # the table to perform operations on
13
- #
14
- # @return [Object]
15
- #
16
11
  # @api public
17
- def initialize(table)
18
- @table = table
12
+ def initialize
19
13
  @operations = Hash.new { |hash, key| hash[key] = [] }
20
14
  end
21
15
 
@@ -55,14 +49,14 @@ module TTY
55
49
  # @return [TTY::Table]
56
50
  #
57
51
  # @api public
58
- def run_operations(*args)
52
+ def apply_to(table, *args)
59
53
  operation_types = args
60
54
  table.data.each_with_index do |row, row_i|
61
55
  row.fields.each_with_index do |field, col_i|
62
56
  field.reset!
63
57
  operation_types.each do |type|
64
58
  operations[type].each do |operation|
65
- field.content = operation.call(field, row_i, col_i)
59
+ field.content = operation.(field, row_i, col_i)
66
60
  end
67
61
  end
68
62
  end
@@ -71,11 +65,6 @@ module TTY
71
65
 
72
66
  protected
73
67
 
74
- # The table
75
- #
76
- # @api private
77
- attr_reader :table
78
-
79
68
  # Available operations
80
69
  #
81
70
  # @return [Hash]
@@ -7,12 +7,12 @@ require_relative 'renderer/unicode'
7
7
 
8
8
  module TTY
9
9
  class Table
10
- # A class responsible for rendering tabular data
10
+ # A module responsible for selecting tabule data renderer
11
11
  #
12
12
  # Used internally by {Table} to render table content out.
13
13
  #
14
14
  # @api private
15
- class Renderer
15
+ module Renderer
16
16
  RENDERER_MAPPER = {
17
17
  ascii: TTY::Table::Renderer::ASCII,
18
18
  basic: TTY::Table::Renderer::Basic,
@@ -30,9 +30,10 @@ module TTY
30
30
  # @return [TTY::Table::Renderer]
31
31
  #
32
32
  # @api private
33
- def self.select(type)
33
+ def select(type)
34
34
  RENDERER_MAPPER[type || :basic]
35
35
  end
36
+ module_function :select
36
37
 
37
38
  # Raises an error if provided border class is of wrong type or has invalid
38
39
  # implementation
@@ -44,7 +45,7 @@ module TTY
44
45
  # raised when border class does not implement core methods
45
46
  #
46
47
  # @api public
47
- def self.assert_border_class(border_class)
48
+ def assert_border_class(border_class)
48
49
  return unless border_class
49
50
  unless border_class <= TTY::Table::Border
50
51
  fail TypeError,
@@ -55,6 +56,27 @@ module TTY
55
56
  "#{border_class} should implement def_border"
56
57
  end
57
58
  end
59
+ module_function :assert_border_class
60
+
61
+ # Render a given table and return the string representation.
62
+ #
63
+ # @param [TTY::Table] table
64
+ # the table to be rendered
65
+ #
66
+ # @param [Hash] options
67
+ # the options to render the table with
68
+ # @option options [String] :renderer
69
+ # used to format table output
70
+ #
71
+ # @return [String]
72
+ #
73
+ # @api public
74
+ def render(table, options = {}, &block)
75
+ renderer = select(options[:renderer]).new(table, options)
76
+ yield renderer if block_given?
77
+ renderer.render
78
+ end
79
+ module_function :render
58
80
 
59
81
  # Add custom border for the renderer
60
82
  #
@@ -71,30 +93,12 @@ module TTY
71
93
  # raise if the klass does not implement def_border
72
94
  #
73
95
  # @api public
74
- def self.render_with(border_class, table, options = {}, &block)
96
+ def render_with(border_class, table, options = {}, &block)
75
97
  assert_border_class(border_class)
76
98
  options[:border_class] = border_class if border_class
77
99
  render(table, options, &block)
78
100
  end
79
-
80
- # Render a given table and return the string representation.
81
- #
82
- # @param [TTY::Table] table
83
- # the table to be rendered
84
- #
85
- # @param [Hash] options
86
- # the options to render the table with
87
- # @option options [String] :renderer
88
- # used to format table output
89
- #
90
- # @return [String]
91
- #
92
- # @api public
93
- def self.render(table, options = {}, &block)
94
- renderer = select(options[:renderer]).new(table, options)
95
- yield renderer if block_given?
96
- renderer.render
97
- end
101
+ module_function :render_with
98
102
  end # Renderer
99
103
  end # Table
100
104
  end # TTY
@@ -5,7 +5,7 @@ require_relative '../renderer/basic'
5
5
 
6
6
  module TTY
7
7
  class Table
8
- class Renderer
8
+ module Renderer
9
9
  class ASCII < Basic
10
10
  # Create ASCII renderer
11
11
  #
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'tty-screen'
4
- require 'verse'
4
+ require 'strings'
5
5
 
6
6
  require_relative '../alignment_set'
7
7
  require_relative '../border_dsl'
@@ -22,7 +22,7 @@ require_relative '../validatable'
22
22
 
23
23
  module TTY
24
24
  class Table
25
- class Renderer
25
+ module Renderer
26
26
  # Renders table without any border styles.
27
27
  #
28
28
  # @api private
@@ -70,7 +70,7 @@ module TTY
70
70
  # @api public
71
71
  attr_reader :indent
72
72
 
73
- # The table totabl width
73
+ # The table total width
74
74
  #
75
75
  # @return [Integer]
76
76
  #
@@ -122,7 +122,7 @@ module TTY
122
122
  @border_class = options.fetch(:border_class) { Border::Null }
123
123
  @indent = options.fetch(:indent) { 0 }
124
124
  @resize = options.fetch(:resize) { false }
125
- @padding = Verse::Padder.parse(options[:padding])
125
+ @padding = Strings::Padder.parse(options[:padding])
126
126
  end
127
127
 
128
128
  # Parses supplied column widths, if not present
@@ -162,7 +162,7 @@ module TTY
162
162
  #
163
163
  # @api public
164
164
  def indent=(value)
165
- @indentation.indentation = value
165
+ @indent = value
166
166
  end
167
167
 
168
168
  # Sets the output padding,
@@ -172,7 +172,7 @@ module TTY
172
172
  #
173
173
  # @api public
174
174
  def padding=(value)
175
- @padding = Verse::Padder.parse(value)
175
+ @padding = Strings::Padder.parse(value)
176
176
  end
177
177
 
178
178
  # Renders table as string with border
@@ -188,32 +188,48 @@ module TTY
188
188
  def render
189
189
  return if table.empty?
190
190
 
191
- @operations = TTY::Table::Operations.new(table)
192
- @operations.add(:escape, Operation::Escape.new)
193
- @operations.run_operations(:escape) unless multiline
191
+ operations = TTY::Table::Operations.new
192
+ operations.add(:escape, Operation::Escape.new)
193
+ operations.apply_to(table, :escape) unless multiline
194
+
194
195
  column_constraint = ColumnConstraint.new(table, self)
195
196
  @column_widths = column_constraint.enforce
196
- add_operations(@column_widths)
197
+ widths_without_padding = @column_widths.map do |_width|
198
+ _width - padding.left - padding.right
199
+ end
200
+ create_operations(widths_without_padding).each do |op|
201
+ operations.add(*op)
202
+ end
203
+ operations.apply_to(table, *select_operations)
204
+
205
+ render_data.compact.join("\n")
206
+ end
207
+
208
+ # Select applicable operations for this table
209
+ #
210
+ # @api private
211
+ def select_operations
197
212
  ops = []
198
213
  ops << :escape unless multiline
199
214
  ops << :alignment
200
215
  ops << (multiline ? :wrapping : :truncation)
201
216
  ops << :padding
202
217
  ops << :filter
203
- @operations.run_operations(*ops)
204
-
205
- render_data.compact.join("\n")
206
218
  end
207
219
 
208
- # Initialize and add operations
220
+ # Initialize operations
221
+ #
222
+ # @return [Array[String, Operation]]
209
223
  #
210
224
  # @api private
211
- def add_operations(widths)
212
- @operations.add(:alignment, Operation::Alignment.new(alignments, widths))
213
- @operations.add(:filter, Operation::Filter.new(filter))
214
- @operations.add(:truncation, Operation::Truncation.new(widths))
215
- @operations.add(:wrapping, Operation::Wrapped.new(widths))
216
- @operations.add(:padding, Operation::Padding.new(padding))
225
+ def create_operations(widths)
226
+ [
227
+ [:alignment, Operation::Alignment.new(alignments, widths)],
228
+ [:filter, Operation::Filter.new(filter)],
229
+ [:truncation, Operation::Truncation.new(widths)],
230
+ [:wrapping, Operation::Wrapped.new(widths)],
231
+ [:padding, Operation::Padding.new(padding)]
232
+ ]
217
233
  end
218
234
 
219
235
  protected
@@ -225,33 +241,17 @@ module TTY
225
241
  # @api public
226
242
  attr_reader :table
227
243
 
228
- # Initializes indentation
229
- #
230
- # @return [TTY::Table::Indentation]
231
- #
232
- # @api private
233
- def indentation
234
- @indentation ||= TTY::Table::Indentation.new(indent)
235
- end
236
-
237
- # Delegate indentation insertion
238
- #
239
- # @api public
240
- def insert_indent(line)
241
- indentation.indent(line)
242
- end
243
-
244
244
  # Render table data
245
245
  #
246
246
  # @api private
247
247
  def render_data
248
248
  first_row = table.first
249
- data_border = border_class.new(column_widths, padding, border)
249
+ data_border = border_class.new(column_widths, border)
250
250
  header = render_header(first_row, data_border)
251
251
  rows_with_border = render_rows(data_border)
252
252
  bottom_line = data_border.bottom_line
253
253
 
254
- insert_indent(bottom_line) if bottom_line
254
+ Indentation.indent(bottom_line, @indent) if bottom_line
255
255
 
256
256
  [header, rows_with_border, bottom_line].compact
257
257
  end
@@ -271,7 +271,7 @@ module TTY
271
271
  top_line = data_border.top_line
272
272
  if row.is_a?(TTY::Table::Header)
273
273
  header = [top_line, data_border.row_line(row), data_border.separator]
274
- insert_indent(header.compact)
274
+ Indentation.indent(header.compact, @indent)
275
275
  else
276
276
  top_line
277
277
  end
@@ -309,10 +309,11 @@ module TTY
309
309
  row_line = data_border.row_line(row)
310
310
 
311
311
  if (border.separator == TTY::Table::Border::EACH_ROW) && is_last_row
312
- insert_indent([row_line, separator])
312
+ line = [row_line, separator]
313
313
  else
314
- insert_indent(row_line)
314
+ line = row_line
315
315
  end
316
+ Indentation.indent(line, @indent)
316
317
  end
317
318
  end # Basic
318
319
  end # Renderer