tty 0.0.10 → 0.0.11

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 (56) hide show
  1. data/README.md +75 -19
  2. data/lib/tty.rb +7 -0
  3. data/lib/tty/shell/question.rb +3 -3
  4. data/lib/tty/shell/response.rb +5 -5
  5. data/lib/tty/table.rb +51 -19
  6. data/lib/tty/table/column_set.rb +42 -1
  7. data/lib/tty/table/columns.rb +167 -0
  8. data/lib/tty/table/field.rb +2 -2
  9. data/lib/tty/table/indentation.rb +54 -0
  10. data/lib/tty/table/operation/escape.rb +1 -1
  11. data/lib/tty/table/operation/filter.rb +0 -1
  12. data/lib/tty/table/operation/padding.rb +95 -0
  13. data/lib/tty/table/operation/wrapped.rb +6 -3
  14. data/lib/tty/table/operations.rb +3 -2
  15. data/lib/tty/table/orientation/horizontal.rb +27 -1
  16. data/lib/tty/table/orientation/vertical.rb +17 -1
  17. data/lib/tty/table/padder.rb +142 -0
  18. data/lib/tty/table/renderer/basic.rb +101 -31
  19. data/lib/tty/table/validatable.rb +0 -7
  20. data/lib/tty/terminal/color.rb +36 -20
  21. data/lib/tty/text/truncation.rb +16 -1
  22. data/lib/tty/text/wrapping.rb +31 -10
  23. data/lib/tty/version.rb +1 -1
  24. data/spec/tty/shell/question/argument_spec.rb +1 -1
  25. data/spec/tty/shell/question/modify_spec.rb +2 -2
  26. data/spec/tty/shell/response/read_email_spec.rb +0 -1
  27. data/spec/tty/table/border/ascii/rendering_spec.rb +34 -7
  28. data/spec/tty/table/border/null/rendering_spec.rb +34 -7
  29. data/spec/tty/table/column_set/extract_widths_spec.rb +1 -1
  30. data/spec/tty/table/column_set/widths_from_spec.rb +52 -0
  31. data/spec/tty/table/columns/enforce_spec.rb +68 -0
  32. data/spec/tty/table/columns/widths_spec.rb +33 -0
  33. data/spec/tty/table/indentation/insert_indent_spec.rb +27 -0
  34. data/spec/tty/table/operation/wrapped/call_spec.rb +2 -1
  35. data/spec/tty/table/operation/wrapped/wrap_spec.rb +3 -2
  36. data/spec/tty/table/operations/new_spec.rb +3 -5
  37. data/spec/tty/table/orientation_spec.rb +68 -22
  38. data/spec/tty/table/padder/parse_spec.rb +45 -0
  39. data/spec/tty/table/padding_spec.rb +120 -0
  40. data/spec/tty/table/renderer/ascii/indentation_spec.rb +41 -0
  41. data/spec/tty/table/renderer/ascii/padding_spec.rb +61 -0
  42. data/spec/tty/table/renderer/ascii/resizing_spec.rb +114 -0
  43. data/spec/tty/table/renderer/basic/alignment_spec.rb +18 -19
  44. data/spec/tty/table/renderer/basic/coloring_spec.rb +45 -0
  45. data/spec/tty/table/renderer/basic/indentation_spec.rb +46 -0
  46. data/spec/tty/table/renderer/basic/options_spec.rb +2 -2
  47. data/spec/tty/table/renderer/basic/padding_spec.rb +52 -0
  48. data/spec/tty/table/renderer/basic/resizing_spec.rb +96 -0
  49. data/spec/tty/table/renderer/render_spec.rb +36 -0
  50. data/spec/tty/table/renderer/unicode/indentation_spec.rb +41 -0
  51. data/spec/tty/table/renderer/unicode/padding_spec.rb +61 -0
  52. data/spec/tty/table/renderer_spec.rb +19 -0
  53. data/spec/tty/table/rotate_spec.rb +20 -6
  54. data/spec/tty/text/truncation/truncate_spec.rb +18 -3
  55. data/spec/tty/text/wrapping/wrap_spec.rb +24 -7
  56. metadata +56 -18
@@ -3,21 +3,20 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe TTY::Table::Renderer::Basic, 'alignment' do
6
- let(:header) { ['h1', 'h2', 'h3'] }
7
- let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
- let(:options) { { :renderer => :basic, :column_aligns => column_aligns }}
9
-
10
- let(:table) { TTY::Table.new(header, rows) }
6
+ let(:header) { ['h1', 'h2', 'h3'] }
7
+ let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
+ let(:options) { { column_aligns: column_aligns } }
9
+ let(:table) { TTY::Table.new(header, rows) }
11
10
 
12
11
  subject(:renderer) { described_class.new table, options }
13
12
 
14
13
  context 'with default' do
15
- let(:header) { ['h1', 'h2'] }
16
- let(:rows) { [['aaaaa', 'a'], ['b', 'bbbbb']] }
14
+ let(:header) { ['h1', 'h2'] }
15
+ let(:rows) { [['aaaaa', 'a'], ['b', 'bbbbb']] }
17
16
  let(:column_aligns) { nil }
18
17
 
19
18
  it 'aligns left by default' do
20
- renderer.render.should == <<-EOS.normalize
19
+ expect(renderer.render).to eql <<-EOS.normalize
21
20
  h1 h2
22
21
  aaaaa a
23
22
  b bbbbb
@@ -26,11 +25,11 @@ describe TTY::Table::Renderer::Basic, 'alignment' do
26
25
  end
27
26
 
28
27
  context 'with different headers' do
29
- let(:header) { ['header1', 'head2', 'h3'] }
28
+ let(:header) { ['header1', 'head2', 'h3'] }
30
29
  let(:column_aligns) { [:left, :center, :right] }
31
30
 
32
31
  it 'aligns headers' do
33
- renderer.render.should == <<-EOS.normalize
32
+ expect(renderer.render).to eql <<-EOS.normalize
34
33
  header1 head2 h3
35
34
  a1 a2 a3
36
35
  b1 b2 b3
@@ -39,12 +38,12 @@ describe TTY::Table::Renderer::Basic, 'alignment' do
39
38
  end
40
39
 
41
40
  context 'with different aligns' do
42
- let(:header) { nil }
43
- let(:rows) { [['aaaaa', 'a'], ['b', 'bbbbb']] }
41
+ let(:header) { nil }
42
+ let(:rows) { [['aaaaa', 'a'], ['b', 'bbbbb']] }
44
43
  let(:column_aligns) { [:left, :right] }
45
44
 
46
45
  it 'aligns table rows' do
47
- renderer.render.to_s.should == <<-EOS.normalize
46
+ expect(renderer.render.to_s).to eql <<-EOS.normalize
48
47
  aaaaa a
49
48
  b bbbbb
50
49
  EOS
@@ -52,11 +51,11 @@ describe TTY::Table::Renderer::Basic, 'alignment' do
52
51
  end
53
52
 
54
53
  context 'with individual field aligns' do
55
- let(:header) { ['header1', 'header2', 'header3'] }
54
+ let(:header) { ['header1', 'header2', 'header3'] }
56
55
  let(:column_aligns) { [:left, :center, :right] }
57
- let(:options) { { :column_aligns => column_aligns, :renderer => :basic } }
56
+ let(:options) { {column_aligns: column_aligns} }
58
57
  let(:table) {
59
- TTY::Table.new :header => header do |t|
58
+ TTY::Table.new header: header do |t|
60
59
  t << ['a1', 'a2', 'a3']
61
60
  t << ['b1', {:value => 'b2', :align => :right}, 'b3']
62
61
  t << ['c1', 'c2', {:value => 'c3', :align => :center}]
@@ -74,9 +73,9 @@ describe TTY::Table::Renderer::Basic, 'alignment' do
74
73
  end
75
74
 
76
75
  context 'with aligned header' do
77
- let(:rows) { [['aaaaa1', 'a2', 'aaa3'], ['b1', 'bbbb2', 'bb3']] }
78
- let(:header) {['h1', {:value => 'h2', :align => :right}, {:value => 'h3', :align => :center}] }
79
- let(:options) { { :renderer => :basic } }
76
+ let(:rows) { [['aaaaa1', 'a2', 'aaa3'], ['b1', 'bbbb2', 'bb3']] }
77
+ let(:header) {['h1', {:value => 'h2', :align => :right}, {:value => 'h3', :align => :center}] }
78
+ let(:options) { { renderer: :basic } }
80
79
 
81
80
  it "aligns headres" do
82
81
  renderer.render.should == <<-EOS.normalize
@@ -0,0 +1,45 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Table::Renderer::Basic, 'coloring' do
6
+ let(:header) { ['h1', 'h2'] }
7
+ let(:rows) { [['a1', 'a2'], ['b1', 'b2']] }
8
+ let(:blue) { "\e[34m" }
9
+ let(:clear) { "\e[0m" }
10
+ let(:on_green) { "\e[42m"}
11
+ let(:options) { {filter: filter } }
12
+ let(:table) { TTY::Table.new(header, rows) }
13
+
14
+ subject(:renderer) { described_class.new(table, options) }
15
+
16
+ context 'with filter on all fields' do
17
+ let(:filter) {
18
+ proc { |val, row, col| TTY.terminal.color.set val, :blue, :on_green }
19
+ }
20
+
21
+ it 'colors all elements' do
22
+ expect(renderer.render).to eql <<-EOS.normalize
23
+ #{blue}#{on_green}h1#{clear} #{blue}#{on_green}h2#{clear}
24
+ #{blue}#{on_green}a1#{clear} #{blue}#{on_green}a2#{clear}
25
+ #{blue}#{on_green}b1#{clear} #{blue}#{on_green}b2#{clear}
26
+ EOS
27
+ end
28
+ end
29
+
30
+ context 'with filter only on header' do
31
+ let(:filter) {
32
+ proc { |val, row, col|
33
+ row.zero? ? TTY.terminal.color.set(val, :blue, :on_green) : val
34
+ }
35
+ }
36
+
37
+ it 'colors only header' do
38
+ expect(renderer.render).to eql <<-EOS.normalize
39
+ #{blue}#{on_green}h1#{clear} #{blue}#{on_green}h2#{clear}
40
+ a1 a2
41
+ b1 b2
42
+ EOS
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Table::Renderer::Basic, 'indentation' do
6
+ let(:header) { ['h1', 'h2', 'h3'] }
7
+ let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
+ let(:table) { TTY::Table.new(header, rows) }
9
+ let(:indent) { 2 }
10
+ let(:options) { {indent: indent } }
11
+
12
+ subject(:renderer) { described_class.new(table, options)}
13
+
14
+ context 'when default' do
15
+ let(:options) { { } }
16
+
17
+ it 'indents by value' do
18
+ expect(renderer.render).to eql <<-EOS.chomp
19
+ h1 h2 h3
20
+ a1 a2 a3
21
+ b1 b2 b3
22
+ EOS
23
+ end
24
+ end
25
+
26
+ context 'when custom' do
27
+ it 'indents by value' do
28
+ expect(renderer.render).to eql <<-EOS.chomp
29
+ h1 h2 h3
30
+ a1 a2 a3
31
+ b1 b2 b3
32
+ EOS
33
+ end
34
+ end
35
+
36
+ context 'when changed' do
37
+ let(:header) { ['h1', 'h2'] }
38
+ let(:rows) { [['a1', 'a2']] }
39
+
40
+ it 'changes indentation and reuses renderer' do
41
+ expect(renderer.render).to eq(" h1 h2\n a1 a2")
42
+ renderer.indent = 1
43
+ expect(renderer.render).to eq(" h1 h2\n a1 a2")
44
+ end
45
+ end
46
+ end
@@ -20,7 +20,7 @@ describe TTY::Table::Renderer::Basic, 'options' do
20
20
 
21
21
  its(:border) { should be_kind_of TTY::Table::BorderOptions }
22
22
 
23
- its(:column_widths) { should be_empty }
23
+ its(:column_widths) { should eql([2,2]) }
24
24
 
25
25
  its(:column_aligns) { should eql(aligns) }
26
26
 
@@ -35,7 +35,7 @@ describe TTY::Table::Renderer::Basic, 'options' do
35
35
  context '#column_widths empty' do
36
36
  let(:widths) { [] }
37
37
 
38
- it { expect { subject }.to raise_error(TTY::InvalidArgument) }
38
+ it { expect { subject.column_widths }.to raise_error(TTY::InvalidArgument) }
39
39
  end
40
40
 
41
41
  context '#column_aligns' do
@@ -0,0 +1,52 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Table::Renderer::Basic, 'padding' do
6
+ let(:header) { ['Field', 'Type', 'Null', 'Key', 'Default', 'Extra'] }
7
+ let(:rows) { [['id', 'int(11)', 'YES', 'nil', 'NULL', '']] }
8
+ let(:table) { TTY::Table.new(header, rows) }
9
+
10
+ subject(:renderer) { described_class.new(table, options) }
11
+
12
+ context 'with left & right padding' do
13
+ let(:options) { {padding: [0,1,0,1]} }
14
+
15
+ it 'pads each field' do
16
+ expect(renderer.render).to eql <<-EOS.chomp
17
+ Field Type Null Key Default Extra
18
+ id int(11) YES nil NULL
19
+ EOS
20
+ end
21
+ end
22
+
23
+ context 'with top & bottom padding' do
24
+ let(:options) { {padding: [1,0,1,0], multiline: true} }
25
+
26
+ it 'pads each field' do
27
+ expect(renderer.render).to eql <<-EOS.chomp
28
+
29
+ Field Type Null Key Default Extra
30
+
31
+
32
+ id int(11) YES nil NULL
33
+
34
+ EOS
35
+ end
36
+ end
37
+
38
+ context 'with full padding' do
39
+ let(:options) { {padding: [1,1,1,1], multiline: true} }
40
+
41
+ it 'pads each field' do
42
+ expect(renderer.render).to eql <<-EOS.chomp
43
+
44
+ Field Type Null Key Default Extra
45
+
46
+
47
+ id int(11) YES nil NULL
48
+
49
+ EOS
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,96 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Table::Renderer::Basic, 'resizing' do
6
+ let(:header) { ['h1', 'h2', 'h3'] }
7
+ let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
+ let(:table) { TTY::Table.new(header, rows) }
9
+
10
+ subject(:renderer) { described_class.new(table, options) }
11
+
12
+ context 'when expanding' do
13
+ context 'even columns' do
14
+ let(:options) { {width: 16, resize: true} }
15
+
16
+ it 'resizes each column' do
17
+ expect(renderer.render).to eql <<-EOS.normalize
18
+ h1 h2 h3
19
+ a1 a2 a3
20
+ b1 b2 b3
21
+ EOS
22
+ end
23
+ end
24
+
25
+ context 'even columns with extra width' do
26
+ let(:header) { ['h1', 'h2', 'h3', 'h4'] }
27
+ let(:rows) { [['a1','a2','a3','a4'], ['b1','b2','b3','b4']] }
28
+ let(:options) { {width: 21, resize: true} }
29
+
30
+ it 'resizes each column' do
31
+ expect(renderer.render).to eql <<-EOS.normalize
32
+ h1 h2 h3 h4
33
+ a1 a2 a3 a4
34
+ b1 b2 b3 b4
35
+ EOS
36
+ end
37
+ end
38
+
39
+ context 'uneven columns' do
40
+ let(:header) { ['h1', 'h2', 'h3'] }
41
+ let(:rows) { [['aaa1', 'aa2', 'aaaaaaa3'], ['b1', 'b2', 'b3']] }
42
+ let(:options) { {width: 32, resize: true} }
43
+
44
+ it 'resizes each column' do
45
+ expect(renderer.render).to eql <<-EOS.normalize
46
+ h1 h2 h3
47
+ aaa1 aa2 aaaaaaa3
48
+ b1 b2 b3
49
+ EOS
50
+ end
51
+ end
52
+ end
53
+
54
+ context 'when shrinking' do
55
+ let(:header) { ['head1', 'head2'] }
56
+ let(:rows) { [['aaaa1','aaaa2',], ['bbbb1','bbbb2']] }
57
+
58
+ context 'even columns' do
59
+ let(:options) { {width: 7, resize: true} }
60
+
61
+ it 'resizes each column' do
62
+ expect(renderer.render).to eql <<-EOS.normalize
63
+ he… he…
64
+ aa… aa…
65
+ bb… bb…
66
+ EOS
67
+ end
68
+ end
69
+
70
+ context 'even columns with extra width' do
71
+ let(:options) { {width: 8, resize: true} }
72
+
73
+ it 'resizes each column' do
74
+ expect(renderer.render).to eql <<-EOS.normalize
75
+ hea… he…
76
+ aaa… aa…
77
+ bbb… bb…
78
+ EOS
79
+ end
80
+ end
81
+
82
+ context 'uneven columns' do
83
+ let(:header) { ['head1', 'head2', 'head3'] }
84
+ let(:rows) { [['aaa1', 'aa2', 'aaaaaaa3'], ['b1', 'b2', 'b3']] }
85
+ let(:options) { {width: 15, resize: true} }
86
+
87
+ it 'resizes each column' do
88
+ expect(renderer.render).to eql <<-EOS.normalize
89
+ hea… he… head3
90
+ aaa1 aa2 aaaaa…
91
+ b1 b2 b3
92
+ EOS
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Table::Renderer, '#render' do
6
+ let(:header) { ['h1', 'h2', 'h3'] }
7
+ let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
+ let(:table) { TTY::Table.new(header, rows) }
9
+
10
+ subject { described_class.render(table, {}, &block) }
11
+
12
+ context 'when default' do
13
+ let(:renderer) { double(:renderer).as_null_object }
14
+ let(:renderer_class) { double(:renderer_class) }
15
+ let(:yielded) { [] }
16
+ let(:block) { proc { |render| yielded << render } }
17
+
18
+ before { described_class.stub(:select).and_return(renderer_class) }
19
+
20
+ it 'creates renderer' do
21
+ expect(renderer_class).to receive(:new).with(table, {}).and_return(renderer)
22
+ subject
23
+ end
24
+
25
+ it 'yields renderer' do
26
+ renderer_class.stub(:new).and_return(renderer)
27
+ expect { subject }.to change { yielded}.from([]).to([renderer])
28
+ end
29
+
30
+ it 'calls render' do
31
+ renderer_class.stub(:new).and_return(renderer)
32
+ expect(renderer).to receive(:render)
33
+ subject
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,41 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Table::Renderer::Unicode, 'indentation' do
6
+ let(:header) { ['h1', 'h2', 'h3'] }
7
+ let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
+ let(:table) { TTY::Table.new(header, rows) }
9
+ let(:indent) { 2 }
10
+ let(:options) { {indent: indent } }
11
+
12
+ subject(:renderer) { described_class.new(table, options)}
13
+
14
+ context 'when default' do
15
+ it 'indents by value' do
16
+ expect(renderer.render).to eql <<-EOS.chomp
17
+ ┌──┬──┬──┐
18
+ │h1│h2│h3│
19
+ ├──┼──┼──┤
20
+ │a1│a2│a3│
21
+ │b1│b2│b3│
22
+ └──┴──┴──┘
23
+ EOS
24
+ end
25
+ end
26
+
27
+ context 'when each row' do
28
+ it 'indents by value' do
29
+ renderer.border.separator = :each_row
30
+ expect(renderer.render).to eql <<-EOS.chomp
31
+ ┌──┬──┬──┐
32
+ │h1│h2│h3│
33
+ ├──┼──┼──┤
34
+ │a1│a2│a3│
35
+ ├──┼──┼──┤
36
+ │b1│b2│b3│
37
+ └──┴──┴──┘
38
+ EOS
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ describe TTY::Table::Renderer::Unicode, 'padding' do
6
+ let(:header) { ['Field', 'Type', 'Null', 'Key', 'Default', 'Extra'] }
7
+ let(:rows) { [['id', 'int(11)', 'YES', 'nil', 'NULL', '']] }
8
+ let(:table) { TTY::Table.new(header, rows) }
9
+
10
+ subject(:renderer) { described_class.new(table, options) }
11
+
12
+ context 'with left & right padding' do
13
+ let(:options) { {padding: [0,1,0,1]} }
14
+
15
+ it 'pads each field' do
16
+ expect(renderer.render).to eql <<-EOS.chomp
17
+ ┌───────┬─────────┬──────┬─────┬─────────┬───────┐
18
+ │ Field │ Type │ Null │ Key │ Default │ Extra │
19
+ ├───────┼─────────┼──────┼─────┼─────────┼───────┤
20
+ │ id │ int(11) │ YES │ nil │ NULL │ │
21
+ └───────┴─────────┴──────┴─────┴─────────┴───────┘
22
+ EOS
23
+ end
24
+ end
25
+
26
+ context 'with top & bottom padding' do
27
+ let(:options) { {padding: [1,0,1,0], multiline: true} }
28
+
29
+ it 'pads each field' do
30
+ expect(renderer.render).to eql <<-EOS.chomp
31
+ ┌─────┬───────┬────┬───┬───────┬─────┐
32
+ │ │ │ │ │ │ │
33
+ │Field│Type │Null│Key│Default│Extra│
34
+ │ │ │ │ │ │ │
35
+ ├─────┼───────┼────┼───┼───────┼─────┤
36
+ │ │ │ │ │ │ │
37
+ │id │int(11)│YES │nil│NULL │ │
38
+ │ │ │ │ │ │ │
39
+ └─────┴───────┴────┴───┴───────┴─────┘
40
+ EOS
41
+ end
42
+ end
43
+
44
+ context 'with full padding' do
45
+ let(:options) { {padding: [1,1,1,1], multiline: true} }
46
+
47
+ it 'pads each field' do
48
+ expect(renderer.render).to eql <<-EOS.chomp
49
+ ┌───────┬─────────┬──────┬─────┬─────────┬───────┐
50
+ │ │ │ │ │ │ │
51
+ │ Field │ Type │ Null │ Key │ Default │ Extra │
52
+ │ │ │ │ │ │ │
53
+ ├───────┼─────────┼──────┼─────┼─────────┼───────┤
54
+ │ │ │ │ │ │ │
55
+ │ id │ int(11) │ YES │ nil │ NULL │ │
56
+ │ │ │ │ │ │ │
57
+ └───────┴─────────┴──────┴─────┴─────────┴───────┘
58
+ EOS
59
+ end
60
+ end
61
+ end