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
@@ -3,13 +3,46 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe TTY::Table::ColumnSet, '#extract_widths' 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.new table }
6
+ let(:color) { Pastel.new(enabled: true) }
11
7
 
12
8
  it 'extract widths' do
13
- expect(subject.extract_widths).to eql([2,2,2])
9
+ header = ['h1', 'h2', 'h3']
10
+ rows = [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']]
11
+ table = TTY::Table.new header, rows
12
+ column_set = TTY::Table::ColumnSet.new(table)
13
+ expect(column_set.extract_widths).to eql([2,2,2])
14
+ end
15
+
16
+ it "extracts widths from utf" do
17
+ header = ['h1', 'うなじ']
18
+ rows = [['こんにちは', 'a2'], ['b1','選択']]
19
+ table = TTY::Table.new header, rows
20
+ column_set = TTY::Table::ColumnSet.new(table)
21
+ expect(column_set.extract_widths).to eql([10,6])
22
+ end
23
+
24
+ it "extracts widths from multiline text" do
25
+ table = TTY::Table.new
26
+ table << ["Multi\nLine\nContent", "Text\nthat\nwraps"]
27
+ table << ["Some\nother\ntext", 'Simple']
28
+ column_set = TTY::Table::ColumnSet.new(table)
29
+ expect(column_set.extract_widths).to eq([7,6])
30
+ end
31
+
32
+ it "extracts widths from multiline text" do
33
+ table = TTY::Table.new
34
+ table << ["Multi\\nLine\\nContent", "Text\\nthat\\nwraps"]
35
+ table << ["Some\\nother\\ntext", 'Simple']
36
+ column_set = TTY::Table::ColumnSet.new(table)
37
+ expect(column_set.extract_widths).to eq([20, 17])
38
+ end
39
+
40
+ it "extracts widths from ANSI text" do
41
+ header = [color.green('h1'), 'h2']
42
+ table = TTY::Table.new header: header
43
+ table << [color.green.on_blue('a1'), 'a2']
44
+ table << ['b1', color.red.on_yellow('b2')]
45
+ column_set = TTY::Table::ColumnSet.new(table)
46
+ expect(column_set.extract_widths).to eq([2,2])
14
47
  end
15
48
  end
@@ -2,13 +2,11 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe TTY::Table, '#data' do
6
- let(:header) { ['h1', 'h2', 'h3'] }
7
- let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
-
9
- subject(:table) { described_class.new header, rows }
10
-
5
+ RSpec.describe TTY::Table, '.data' do
11
6
  it 'gets all table data' do
7
+ header = ['h1', 'h2', 'h3']
8
+ rows = [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']]
9
+ table = described_class.new header, rows
12
10
  expect(table.data).to eql([header] + rows)
13
11
  end
14
12
  end
@@ -3,39 +3,24 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe TTY::Table, '#each' do
6
- let(:table) { described_class.new header, rows }
7
6
  let(:header) { ['Header1'] }
8
7
  let(:rows) { [['a1'], ['b1']] }
9
- let(:field) { TTY::Table::Field }
10
8
 
11
- context 'with no block' do
12
- subject { table.each }
9
+ subject(:table) { described_class.new(header, rows) }
13
10
 
14
- it { is_expected.to be_instance_of(to_enum.class) }
11
+ context 'with no block' do
12
+ it { expect(table.each).to be_instance_of(to_enum.class) }
15
13
 
16
14
  it 'yields the expected values' do
17
- expect(subject.to_a).to eql(table.to_a)
15
+ expect(table.each.to_a).to eql(table.to_a)
18
16
  end
19
17
  end
20
18
 
21
19
  context 'with block' do
22
- let(:yields) { [] }
23
-
24
- subject { table.each { |row| yields << row } }
25
-
26
- it 'yields header and rows' do
27
- subject
28
- expect(yields.first).to be_instance_of(TTY::Table::Header)
29
- expect(yields.last).to be_instance_of(TTY::Table::Row)
30
- end
31
-
32
- it 'yields header and rows with expected attributes' do
33
- subject
34
- expect(yields).to eql(table.data)
35
- end
36
-
37
- xit 'yields each row' do
38
- expect { subject }.to change { yields }.from([]).to(table.data)
20
+ it 'yields each row' do
21
+ yields = []
22
+ table.each { |row| yields << row }
23
+ expect(yields).to eql(table.to_a)
39
24
  end
40
25
  end
41
26
  end
@@ -3,54 +3,48 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe TTY::Table, '.each_with_index' do
6
- let(:header) { ['Header1', 'Header2'] }
7
- let(:rows) { [['a1', 'a2'], ['b1', 'b2']] }
8
- let(:field) { TTY::Table::Field }
9
-
10
- let(:object) { described_class.new header, rows }
11
6
 
12
7
  context 'with no block' do
13
- subject { object.each_with_index }
14
-
15
- it { is_expected.to be_instance_of(to_enum.class) }
8
+ it 'returns enumerable' do
9
+ table = TTY::Table.new ['h1','h2'], [['a1','a2'],['b1','b2']]
10
+ expect(table.each_with_index).to be_instance_of(to_enum.class)
11
+ end
16
12
 
17
13
  it 'yields the expected values' do
18
- expect(subject.to_a).to eql(object.to_a)
14
+ table = TTY::Table.new ['h1','h2'], [['a1','a2'],['b1','b2']]
15
+ expect(table.each_with_index.to_a).to eql(table.to_a)
19
16
  end
20
17
  end
21
18
 
22
19
  context 'with block' do
23
- let(:yields) { [] }
24
-
25
- subject { object.each_with_index { |el, row, col| yields << [el, row, col]}}
26
-
27
20
  context 'without header' do
28
- let(:header) { nil }
29
-
30
- let(:expected) {
31
- [ [field.new('a1'), 0, 0], [field.new('a2'), 0, 1],
32
- [field.new('b1'), 1, 0], [field.new('b2'), 1, 1] ]
33
- }
34
-
35
21
  it "yields rows with expected data" do
36
- expect { subject }.to change { yields }.
37
- from( [] ).
38
- to( expected )
22
+ yields = []
23
+ table = TTY::Table.new [['a1','a2'],['b1','b2']]
24
+ expected = [
25
+ [['a1','a2'], 0],
26
+ [['b1','b2'], 1]
27
+ ]
28
+ expect {
29
+ table.each_with_index { |row, indx| yields << [row, indx] }
30
+ }.to change { yields }.from([]).to(expected)
39
31
  end
40
32
  end
41
33
 
42
34
  context 'with header' do
43
-
44
- let(:expected) {
45
- [ [field.new('Header1'), 0, 0], [field.new('Header2'), 0, 1],
46
- [field.new('a1'), 1, 0], [field.new('a2'), 1, 1],
47
- [field.new('b1'), 2, 0], [field.new('b2'), 2, 1] ]
48
- }
49
-
50
35
  it "yields header and rows with expected data" do
51
- expect { subject }.to change { yields }.
52
- from( [] ).
53
- to( expected )
36
+ yields = []
37
+ table = TTY::Table.new ['h1','h2'], [['a1','a2'],['b1','b2']]
38
+
39
+ expected = [
40
+ [['h1','h2'], 0],
41
+ [['a1','a2'], 1],
42
+ [['b1','b2'], 2]
43
+ ]
44
+
45
+ expect {
46
+ table.each_with_index { |row, indx| yields << [row, indx] }
47
+ }.to change { yields }.from( [] ).to( expected )
54
48
  end
55
49
  end
56
50
  end
@@ -2,20 +2,34 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe TTY::Table::Field, '#length' do
6
- let(:object) { described_class.new value }
5
+ RSpec.describe TTY::Table::Field, '.length' do
6
+ it "calculates length for nil string" do
7
+ field = described_class.new(nil)
8
+ expect(field.length).to eq(0)
9
+ end
7
10
 
8
- subject { object.length }
11
+ it "calculates length for empty string" do
12
+ field = described_class.new('')
13
+ expect(field.length).to eq(0)
14
+ end
9
15
 
10
- context 'with escaped value' do
11
- let(:value) { "Multi\nLine" }
16
+ it "calculates maximum length for multiline string" do
17
+ field = described_class.new("Multi\nLine\nContent")
18
+ expect(field.length).to eq(7)
19
+ end
12
20
 
13
- it { is_expected.to eql(5) }
21
+ it "calculates length for unicode string" do
22
+ field = described_class.new('こんにちは')
23
+ expect(field.length).to eq(10)
14
24
  end
15
25
 
16
- context 'with unescaped value' do
17
- let(:value) { "Multi\\nLine" }
26
+ it "calculates length for escaped string" do
27
+ field = described_class.new("Multi\\nLine")
28
+ expect(field.length).to eq(11)
29
+ end
18
30
 
19
- it { is_expected.to eql(11) }
31
+ it "calculates length for colored string" do
32
+ field = described_class.new("\e[32;41mgreen on red\e[0m")
33
+ expect(field.length).to eq(12)
20
34
  end
21
35
  end
@@ -18,6 +18,6 @@ RSpec.describe TTY::Table::Field, '#width' do
18
18
  context 'with hash value' do
19
19
  let(:value) { "foo\nbaar" }
20
20
 
21
- it { is_expected.to eql(8) }
21
+ it { is_expected.to eql(7) }
22
22
  end
23
23
  end
@@ -5,16 +5,15 @@ require 'spec_helper'
5
5
  RSpec.describe TTY::Table, '#filter' do
6
6
  let(:header) { ['h1', 'h2', 'h3'] }
7
7
  let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
8
- let(:table) { described_class.new(header, rows) }
9
- let(:filter) { Proc.new { |val, row, col|
10
- (col == 1 and row > 0) ? val.capitalize : val
11
- }
12
- }
13
8
 
14
- it 'filters rows' do
9
+ subject(:table) { described_class.new(header, rows) }
10
+
11
+ it 'filters fields' do
15
12
  expect(table.render do |renderer|
16
- renderer.filter = filter
17
- end).to eq <<-EOS.normalize
13
+ renderer.filter = proc do |val, row, col|
14
+ (col == 1 && row > 0) ? val.capitalize : val
15
+ end
16
+ end).to eq unindent(<<-EOS)
18
17
  h1 h2 h3
19
18
  a1 A2 a3
20
19
  b1 B2 b3
@@ -3,23 +3,14 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe TTY::Table::Header, '#new' do
6
- let(:object) { described_class }
7
6
 
8
- context 'with no arguments' do
9
- subject { object.new }
10
-
11
- it { is_expected.to be_instance_of(object) }
12
-
13
- it { is_expected.to be_empty }
7
+ it "is empty without arguments" do
8
+ header = TTY::Table::Header.new
9
+ expect(header).to be_empty
14
10
  end
15
11
 
16
- context 'with attributes' do
17
- subject { object.new(attributes) }
18
-
19
- let(:attributes) { ['id', 'name', 'age'] }
20
-
21
- it { is_expected.to be_instance_of(object) }
22
-
23
- it { is_expected == attributes }
12
+ it "isn't empty with attributes" do
13
+ header = TTY::Table::Header.new [:id, :name, :age]
14
+ expect(header.to_a).to eq([:id, :name, :age])
24
15
  end
25
16
  end
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::Table::Indentation, '.indent' do
6
+ let(:indent) { 2 }
7
+
8
+ subject(:indentation) { described_class.new(indent) }
9
+
10
+ context 'when enumerable' do
11
+ it 'inserts indentation for each element' do
12
+ expect(indentation.indent(['line1'])).to eql([' line1'])
13
+ end
14
+ end
15
+
16
+ context 'when string' do
17
+ it 'inserts indentation' do
18
+ expect(indentation.indent('line1')).to eql(' line1')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,73 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::Table, '#new' do
6
+ it { is_expected.to be_kind_of(Enumerable) }
7
+
8
+ it { is_expected.to be_kind_of(Comparable) }
9
+
10
+ context 'with rows only' do
11
+ it 'allows hash like syntax for rows' do
12
+ table = TTY::Table[['a1','a2'], ['b1', 'b2']]
13
+ expect(table.to_a).to eql([['a1','a2'], ['b1', 'b2']])
14
+ end
15
+
16
+ it 'allows for array' do
17
+ table = TTY::Table.new [['a1','a2'], ['b1','b2']]
18
+ expect(table.to_a).to eql([['a1','a2'], ['b1','b2']])
19
+ end
20
+
21
+ it 'allows for :rows key' do
22
+ table = TTY::Table.new rows: [['a1','a2'], ['b1','b2']]
23
+ expect(table.to_a).to eql([['a1','a2'], ['b1','b2']])
24
+ end
25
+
26
+ it 'allows for rows in a block' do
27
+ table = TTY::Table.new do |t|
28
+ t << ['a1', 'a2']
29
+ t << ['b1', 'b2']
30
+ end
31
+ expect(table.to_a).to eql([['a1','a2'],['b1','b2']])
32
+ end
33
+
34
+ it 'allows to add rows after initialization' do
35
+ table = TTY::Table.new
36
+ table << ['a1','a2']
37
+ table << ['b1','b2']
38
+ expect(table.to_a).to eql([['a1','a2'],['b1','b2']])
39
+ end
40
+
41
+ it 'allows for chaining rows' do
42
+ table = TTY::Table.new
43
+ table << ['a1','a2'] << ['b1','b2']
44
+ expect(table.to_a).to eql([['a1','a2'],['b1','b2']])
45
+ end
46
+ end
47
+
48
+ context 'with header and rows' do
49
+ it 'permits header and rows' do
50
+ table = TTY::Table.new ['h1','h2'], [['a1','a2'],['b1','b2']]
51
+ expect(table.to_a).to eql([['h1','h2'], ['a1','a2'], ['b1','b2']])
52
+ end
53
+
54
+ it 'permits only header with :header key' do
55
+ table = TTY::Table.new header: ['h1','h2']
56
+ expect(table.to_a).to eql([['h1','h2']])
57
+ end
58
+ end
59
+
60
+ context 'with header and rows as hash' do
61
+ it 'permits header as key and rows as hash values' do
62
+ table = TTY::Table.new [{'h1' => ['a1','a2'], 'h2' => ['b1','b2']}]
63
+ expect(table.to_a).to eql([['h1','h2'], ['a1','a2'], ['b1','b2']])
64
+ end
65
+ end
66
+
67
+ context 'coercion' do
68
+ it 'converts row arguments from hash to array' do
69
+ table = TTY::Table.new rows: {a: 1, b: 2}
70
+ expect(table.to_a).to eql([[:a,1],[:b,2]])
71
+ end
72
+ end
73
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- RSpec.describe TTY::Table::Operation::AlignmentSet, '#call' do
5
+ RSpec.describe TTY::Table::Operation::Alignment, '#call' do
6
6
  let(:object) { described_class.new alignments, widths }
7
7
  let(:value) { 'a1' }
8
8
  let(:field) { TTY::Table::Field.new(value)}
@@ -7,10 +7,9 @@ RSpec.describe TTY::Table::Operation::Escape, '#call' do
7
7
  let(:text) { "太丸\nゴシ\tック体\r" }
8
8
  let(:field) { TTY::Table::Field.new(text) }
9
9
 
10
- subject { object.new }
10
+ subject(:operation) { object.new }
11
11
 
12
12
  it 'changes field value' do
13
- subject.call(field, 0, 0)
14
- expect(field.value).to eql("太丸\\nゴシ\\tック体\\r")
13
+ expect(operation.call(field, 0, 0)).to eql("太丸\\nゴシ\\tック体\\r")
15
14
  end
16
15
  end
@@ -8,10 +8,9 @@ RSpec.describe TTY::Table::Operation::Filter, '#call' do
8
8
  let(:filter) { Proc.new { |val, row, col| 'new' } }
9
9
  let(:value) { 'new' }
10
10
 
11
- subject { object.new(filter) }
11
+ subject(:operation) { object.new(filter) }
12
12
 
13
13
  it 'changes field value' do
14
- subject.call(field, 0, 0)
15
- expect(field.value).to eql(value)
14
+ expect(operation.call(field, 0, 0)).to eql(value)
16
15
  end
17
16
  end