tty 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/.travis.yml +1 -1
  2. data/README.md +19 -7
  3. data/lib/tty.rb +10 -0
  4. data/lib/tty/support/equatable.rb +1 -0
  5. data/lib/tty/support/unicode.rb +36 -0
  6. data/lib/tty/table.rb +3 -3
  7. data/lib/tty/table/border.rb +104 -0
  8. data/lib/tty/table/border/ascii.rb +41 -0
  9. data/lib/tty/table/border/null.rb +49 -0
  10. data/lib/tty/table/border/unicode.rb +41 -0
  11. data/lib/tty/table/column_set.rb +77 -0
  12. data/lib/tty/table/operation/alignment.rb +2 -0
  13. data/lib/tty/table/operation/alignment_set.rb +4 -58
  14. data/lib/tty/table/operation/truncation.rb +15 -19
  15. data/lib/tty/table/operation/wrapped.rb +34 -0
  16. data/lib/tty/table/renderer.rb +8 -11
  17. data/lib/tty/table/renderer/ascii.rb +15 -0
  18. data/lib/tty/table/renderer/basic.rb +21 -34
  19. data/lib/tty/table/renderer/unicode.rb +2 -2
  20. data/lib/tty/vector.rb +117 -0
  21. data/lib/tty/version.rb +1 -1
  22. data/spec/tty/table/border/ascii/rendering_spec.rb +49 -0
  23. data/spec/tty/table/border/new_spec.rb +21 -0
  24. data/spec/tty/table/border/null/rendering_spec.rb +49 -0
  25. data/spec/tty/table/border/unicode/rendering_spec.rb +49 -0
  26. data/spec/tty/table/column_set/extract_widths_spec.rb +26 -0
  27. data/spec/tty/table/operation/alignment_set/align_rows_spec.rb +4 -4
  28. data/spec/tty/table/operation/alignment_set/new_spec.rb +1 -1
  29. data/spec/tty/table/operation/wrapped/wrap_spec.rb +22 -0
  30. data/spec/tty/table/properties_spec.rb +3 -0
  31. data/spec/tty/table/renderer/basic/render_spec.rb +144 -33
  32. data/spec/tty/table/renderer/pick_renderer_spec.rb +25 -0
  33. data/spec/tty/table/to_s_spec.rb +51 -0
  34. data/spec/tty/vector/new_spec.rb +47 -0
  35. metadata +35 -8
@@ -17,4 +17,4 @@ matrix:
17
17
  - rvm: ruby-head
18
18
  - rvm: jruby-head
19
19
  - rvm: jruby-19mode
20
- - rvm: rbx-18mode
20
+ - rvm: rbx-19mode
data/README.md CHANGED
@@ -10,8 +10,7 @@ Toolbox for developing CLI clients in Ruby.
10
10
 
11
11
  Jump-start development of your command line app:
12
12
 
13
- * Fully customizable table rendering with an easy-to-use API.
14
- (status: In Progress)
13
+ * Fully customizable table rendering with an easy-to-use API. (status: In Progress)
15
14
  * Terminal output colorization. (status: TODO)
16
15
  * Terminal & System detection utilities. (status: In Progress)
17
16
  * Text alignment/padding and diffs. (status: TODO)
@@ -85,15 +84,24 @@ or pass your rows in a block
85
84
  And then to print do
86
85
 
87
86
  ```ruby
88
- table.to_s # => a1 a2 a3
89
- # b1 b2 b3
87
+ table.to_s
88
+
89
+ a1 a2 a3
90
+ b1 b2 b3
90
91
  ```
91
92
 
92
- To print `unicode` table
93
+ To print border around data table you need to specify `renderer` type out of `basic`, `ascii`, `unicode`. For instance to output unicode border:
93
94
 
94
- ```ruby
95
- table = TTY::Table.new renderer: 'unicode'
95
+ ```
96
+ table = TTY::Table.new ['header1', 'header2'], [['a1', 'a2'], ['b1', 'b2'], renderer: 'unicode'
96
97
  table.to_s
98
+
99
+ ┌───────┬───────┐
100
+ │header1│header2│
101
+ ├───────┼───────┤
102
+ │a1 │a2 │
103
+ │b1 │b2 │
104
+ └───────┴───────┘
97
105
  ```
98
106
 
99
107
  ### Terminal
@@ -105,6 +113,10 @@ To print `unicode` table
105
113
  term.color? # => true or false
106
114
  ```
107
115
 
116
+ ### Shell
117
+
118
+ Main responsibility is to interact with the prompt and provide convenience methods.
119
+
108
120
  ### System
109
121
 
110
122
  ```ruby
data/lib/tty.rb CHANGED
@@ -7,15 +7,25 @@ require 'tty/support/delegatable'
7
7
  require 'tty/support/conversion'
8
8
  require 'tty/support/coercion'
9
9
  require 'tty/support/equatable'
10
+ require 'tty/support/unicode'
10
11
 
11
12
  require 'tty/color'
12
13
  require 'tty/terminal'
13
14
  require 'tty/system'
14
15
  require 'tty/table'
16
+ require 'tty/vector'
17
+
18
+ require 'tty/table/border'
19
+ require 'tty/table/border/unicode'
20
+ require 'tty/table/border/ascii'
21
+ require 'tty/table/border/null'
22
+
23
+ require 'tty/table/column_set'
15
24
 
16
25
  require 'tty/table/operation/alignment_set'
17
26
  require 'tty/table/operation/alignment'
18
27
  require 'tty/table/operation/truncation'
28
+ require 'tty/table/operation/wrapped'
19
29
 
20
30
  module TTY
21
31
 
@@ -8,6 +8,7 @@ module TTY
8
8
  # Hook into module inclusion.
9
9
  #
10
10
  # @param [Module] base
11
+ # the module or class including Equatable
11
12
  #
12
13
  # @return [self]
13
14
  #
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ # A mixin to provide unicode support.
5
+ module Unicode
6
+
7
+ def utf8?(string)
8
+ string.unpack('U*') rescue return false
9
+ true
10
+ end
11
+
12
+ def clean_utf8(string)
13
+ require 'iconv'
14
+ if defined? ::Iconv
15
+ converter = Iconv.new('UTF-8//IGNORE', 'UTF-8')
16
+ converter.iconv(string)
17
+ end
18
+ rescue Exception
19
+ string
20
+ end
21
+
22
+ if "".respond_to?(:encode)
23
+ def as_unicode
24
+ yield
25
+ end
26
+ else
27
+ def as_unicode
28
+ old, $KCODE = $KCODE, "U"
29
+ yield
30
+ ensure
31
+ $KCODE = old
32
+ end
33
+ end
34
+
35
+ end # Unicode
36
+ end # TTY
@@ -111,8 +111,9 @@ module TTY
111
111
  @rows = coerce(options.fetch :rows, [])
112
112
  @renderer = pick_renderer options[:renderer]
113
113
  # TODO: assert that row_size is the same as column widths & aligns
114
+ # TODO: this is where column extraction should happen!
114
115
  @column_widths = options.fetch :column_widths, []
115
- @alignments = Operation::AlignmentSet.new options[:column_aligns]
116
+ @alignments = Operation::AlignmentSet.new options[:column_aligns] || []
116
117
 
117
118
  assert_row_sizes @rows
118
119
  yield_or_eval &block if block_given?
@@ -267,8 +268,7 @@ module TTY
267
268
  #
268
269
  # @api public
269
270
  def width
270
- render(self)
271
- total_width
271
+ ColumnSet.new(self).extract_widths!.total_width
272
272
  end
273
273
 
274
274
  # Return true if this is an empty table, i.e. if the number of
@@ -0,0 +1,104 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+
6
+ # Abstract base class that is responsible for building the table border.
7
+ class Border
8
+ include Unicode
9
+
10
+ NEWLINE = "\n"
11
+
12
+ # The row cell widths
13
+ #
14
+ # @api private
15
+ attr_reader :widths
16
+ private :widths
17
+
18
+ # The table row
19
+ #
20
+ # @api private
21
+ attr_reader :row
22
+ private :row
23
+
24
+ # Instantiate a new object
25
+ #
26
+ # @return [Object]
27
+ #
28
+ # @api private
29
+ def initialize(*)
30
+ if self.class == Border
31
+ raise NotImplementedError, "#{self} is an abstract class"
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ # A line spanning all columns marking top of a table.
38
+ #
39
+ # @return [String]
40
+ #
41
+ # @api private
42
+ def top_line
43
+ render :top
44
+ end
45
+
46
+ # A line spanning all columns delemeting rows in a table.
47
+ #
48
+ # @return [String]
49
+ #
50
+ # @api private
51
+ def separator
52
+ render :mid
53
+ end
54
+
55
+ # A line spanning all columns delemeting cells in a row.
56
+ #
57
+ # @return [String]
58
+ #
59
+ # @api private
60
+ def row_line
61
+ self['left'] + row.join(self['right']) + self['right']
62
+ end
63
+
64
+ # A line spannig all columns marking bottom of a table.
65
+ #
66
+ # @return [String]
67
+ #
68
+ # @api private
69
+ def bottom_line
70
+ render :bottom
71
+ end
72
+
73
+ protected
74
+
75
+ # Generate particular border type
76
+ #
77
+ # @param [String] type
78
+ # border type one of [:top, :bottom, :mid]
79
+ #
80
+ # @api private
81
+ def render(type)
82
+ type = type.to_s
83
+ render_line self[type],
84
+ self["#{type}_left"] || self[type],
85
+ self["#{type}_right"] || self[type],
86
+ self["#{type}_mid"]
87
+ end
88
+
89
+ # Generate a border string
90
+ #
91
+ # @param [String] line
92
+ #
93
+ # @return [String]
94
+ #
95
+ # @api private
96
+ def render_line(line, left, right, intersection)
97
+ as_unicode do
98
+ left + widths.map { |width| line * width }.join(intersection) + right
99
+ end
100
+ end
101
+
102
+ end # Border
103
+ end # Table
104
+ end # TTY
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+ class Border
6
+
7
+ # A class that represents an ascii border.
8
+ class ASCII < Border
9
+
10
+ BORDER_TYPE = {
11
+ 'top' => '-',
12
+ 'top_mid' => '+',
13
+ 'top_left' => '+',
14
+ 'top_right' => '+',
15
+ 'bottom' => '-',
16
+ 'bottom_mid' => '+',
17
+ 'bottom_left' => '+',
18
+ 'bottom_right' => '+',
19
+ 'mid' => '-',
20
+ 'mid_mid' => '+',
21
+ 'mid_left' => '+',
22
+ 'mid_right' => '+',
23
+ 'left' => '|',
24
+ 'right' => '|'
25
+ }
26
+
27
+ # @api private
28
+ def [](type)
29
+ BORDER_TYPE[type]
30
+ end
31
+
32
+ # @api private
33
+ def initialize(row)
34
+ @row = row
35
+ @widths = row.map { |cell| cell.chars.to_a.size }
36
+ end
37
+
38
+ end # ASCII
39
+ end # Border
40
+ end # Table
41
+ end # TTY
@@ -0,0 +1,49 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+ class Border
6
+
7
+ # A class that represents no border.
8
+ class Null < Border
9
+
10
+ # @api private
11
+ def initialize(row)
12
+ @row = row
13
+ @widths = row.map { |cell| cell.chars.to_a.size }
14
+ end
15
+
16
+ # A stub top line
17
+ #
18
+ # @api private
19
+ def top_line
20
+ nil
21
+ end
22
+
23
+ # A stub separator line
24
+ #
25
+ # @api private
26
+ def separator
27
+ nil
28
+ end
29
+
30
+ # A line spanning all columns delemited by space character.
31
+ #
32
+ # @return [String]
33
+ #
34
+ # @api private
35
+ def row_line
36
+ row.join(' ')
37
+ end
38
+
39
+ # A stub bottom line
40
+ #
41
+ # @api private
42
+ def bottom_line
43
+ nil
44
+ end
45
+
46
+ end # Null
47
+ end # Border
48
+ end # Table
49
+ end # TTY
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+ class Border
6
+
7
+ # A class that represents a unicode border.
8
+ class Unicode < Border
9
+
10
+ BORDER_TYPE = {
11
+ 'top' => '─',
12
+ 'top_mid' => '┬',
13
+ 'top_left' => '┌',
14
+ 'top_right' => '┐',
15
+ 'bottom' => '─',
16
+ 'bottom_mid' => '┴',
17
+ 'bottom_left' => '└',
18
+ 'bottom_right' => '┘',
19
+ 'mid' => '─',
20
+ 'mid_mid' => '┼',
21
+ 'mid_left' => '├',
22
+ 'mid_right' => '┤',
23
+ 'left' => '│',
24
+ 'right' => '│'
25
+ }
26
+
27
+ # @api private
28
+ def [](type)
29
+ BORDER_TYPE[type]
30
+ end
31
+
32
+ # @api private
33
+ def initialize(row)
34
+ @row = row
35
+ @widths = row.map { |cell| cell.chars.to_a.size }
36
+ end
37
+
38
+ end # Unicode
39
+ end # Border
40
+ end # Table
41
+ end # TTY
@@ -0,0 +1,77 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ class Table
5
+
6
+ # A class that represents table columns properties.
7
+ class ColumnSet
8
+ include Equatable
9
+ extend Delegatable
10
+
11
+ attr_reader :table
12
+
13
+ delegatable_method :table, :column_widths
14
+
15
+ def initialize(table)
16
+ @table = table
17
+ end
18
+
19
+ # Calculate total table width
20
+ #
21
+ # @return [Integer]
22
+ #
23
+ # @api public
24
+ def total_width
25
+ column_widths.reduce(:+)
26
+ end
27
+
28
+ # Calcualte maximum column widths
29
+ #
30
+ # @return [Array] column widths
31
+ #
32
+ # @api private
33
+ def extract_widths!
34
+ return column_widths unless column_widths.empty?
35
+
36
+ rows = table.to_a
37
+ data = table.header ? rows + [table.header] : rows
38
+ colcount = data.max { |row_a, row_b| row_a.size <=> row_b.size }.size
39
+
40
+ table.column_widths = find_maximas colcount, data
41
+ self
42
+ end
43
+
44
+ private
45
+
46
+ # Find maximum widths for each row and header if present.
47
+ #
48
+ # @param [Integer] colcount
49
+ # number of columns
50
+ # @param [Array[Array]] data
51
+ # the table's header and rows
52
+ #
53
+ # @api private
54
+ def find_maximas(colcount, data)
55
+ maximas = []
56
+ start = 0
57
+
58
+ start.upto(colcount - 1) do |index|
59
+ maximas << find_maximum(data, index)
60
+ end
61
+ maximas
62
+ end
63
+
64
+ # Find a maximum column width.
65
+ #
66
+ # @param [Array] data
67
+ #
68
+ # @param [Integer] index
69
+ #
70
+ # @api private
71
+ def find_maximum(data, index)
72
+ data.map { |row| row[index] ? (row[index].to_s.size) : 0 }.max
73
+ end
74
+
75
+ end # ColumnSet
76
+ end # Table
77
+ end # TTY