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.
- data/README.md +75 -19
- data/lib/tty.rb +7 -0
- data/lib/tty/shell/question.rb +3 -3
- data/lib/tty/shell/response.rb +5 -5
- data/lib/tty/table.rb +51 -19
- data/lib/tty/table/column_set.rb +42 -1
- data/lib/tty/table/columns.rb +167 -0
- data/lib/tty/table/field.rb +2 -2
- data/lib/tty/table/indentation.rb +54 -0
- data/lib/tty/table/operation/escape.rb +1 -1
- data/lib/tty/table/operation/filter.rb +0 -1
- data/lib/tty/table/operation/padding.rb +95 -0
- data/lib/tty/table/operation/wrapped.rb +6 -3
- data/lib/tty/table/operations.rb +3 -2
- data/lib/tty/table/orientation/horizontal.rb +27 -1
- data/lib/tty/table/orientation/vertical.rb +17 -1
- data/lib/tty/table/padder.rb +142 -0
- data/lib/tty/table/renderer/basic.rb +101 -31
- data/lib/tty/table/validatable.rb +0 -7
- data/lib/tty/terminal/color.rb +36 -20
- data/lib/tty/text/truncation.rb +16 -1
- data/lib/tty/text/wrapping.rb +31 -10
- data/lib/tty/version.rb +1 -1
- data/spec/tty/shell/question/argument_spec.rb +1 -1
- data/spec/tty/shell/question/modify_spec.rb +2 -2
- data/spec/tty/shell/response/read_email_spec.rb +0 -1
- data/spec/tty/table/border/ascii/rendering_spec.rb +34 -7
- data/spec/tty/table/border/null/rendering_spec.rb +34 -7
- data/spec/tty/table/column_set/extract_widths_spec.rb +1 -1
- data/spec/tty/table/column_set/widths_from_spec.rb +52 -0
- data/spec/tty/table/columns/enforce_spec.rb +68 -0
- data/spec/tty/table/columns/widths_spec.rb +33 -0
- data/spec/tty/table/indentation/insert_indent_spec.rb +27 -0
- data/spec/tty/table/operation/wrapped/call_spec.rb +2 -1
- data/spec/tty/table/operation/wrapped/wrap_spec.rb +3 -2
- data/spec/tty/table/operations/new_spec.rb +3 -5
- data/spec/tty/table/orientation_spec.rb +68 -22
- data/spec/tty/table/padder/parse_spec.rb +45 -0
- data/spec/tty/table/padding_spec.rb +120 -0
- data/spec/tty/table/renderer/ascii/indentation_spec.rb +41 -0
- data/spec/tty/table/renderer/ascii/padding_spec.rb +61 -0
- data/spec/tty/table/renderer/ascii/resizing_spec.rb +114 -0
- data/spec/tty/table/renderer/basic/alignment_spec.rb +18 -19
- data/spec/tty/table/renderer/basic/coloring_spec.rb +45 -0
- data/spec/tty/table/renderer/basic/indentation_spec.rb +46 -0
- data/spec/tty/table/renderer/basic/options_spec.rb +2 -2
- data/spec/tty/table/renderer/basic/padding_spec.rb +52 -0
- data/spec/tty/table/renderer/basic/resizing_spec.rb +96 -0
- data/spec/tty/table/renderer/render_spec.rb +36 -0
- data/spec/tty/table/renderer/unicode/indentation_spec.rb +41 -0
- data/spec/tty/table/renderer/unicode/padding_spec.rb +61 -0
- data/spec/tty/table/renderer_spec.rb +19 -0
- data/spec/tty/table/rotate_spec.rb +20 -6
- data/spec/tty/text/truncation/truncate_spec.rb +18 -3
- data/spec/tty/text/wrapping/wrap_spec.rb +24 -7
- metadata +56 -18
data/lib/tty/text/wrapping.rb
CHANGED
@@ -13,6 +13,8 @@ module TTY
|
|
13
13
|
|
14
14
|
attr_reader :indent
|
15
15
|
|
16
|
+
attr_reader :padding
|
17
|
+
|
16
18
|
# Initialize a Wrapping
|
17
19
|
#
|
18
20
|
# @param [String] text
|
@@ -31,11 +33,12 @@ module TTY
|
|
31
33
|
#
|
32
34
|
# @api private
|
33
35
|
def initialize(text, *args)
|
34
|
-
options
|
35
|
-
@text
|
36
|
-
@length
|
37
|
-
@indent
|
38
|
-
@
|
36
|
+
options = Utils.extract_options!(args)
|
37
|
+
@text = text
|
38
|
+
@length = options.fetch(:length) { DEFAULT_WIDTH }
|
39
|
+
@indent = options.fetch(:indent) { 0 }
|
40
|
+
@padding = options.fetch(:padding) { [] }
|
41
|
+
@length = args[0] unless args.empty?
|
39
42
|
end
|
40
43
|
|
41
44
|
# Wrap a text into lines no longer than length
|
@@ -47,9 +50,8 @@ module TTY
|
|
47
50
|
return text unless length && length > 0
|
48
51
|
|
49
52
|
as_unicode do
|
50
|
-
text.split(NEWLINE).map do |line|
|
51
|
-
|
52
|
-
indent_line modified_line
|
53
|
+
text.split(NEWLINE, -1).map do |line|
|
54
|
+
pad_line(indent_line(wrap_line(line)))
|
53
55
|
end * NEWLINE
|
54
56
|
end
|
55
57
|
end
|
@@ -74,8 +76,9 @@ module TTY
|
|
74
76
|
# @api private
|
75
77
|
def wrap_line(line)
|
76
78
|
wrap_at = actual_length line
|
77
|
-
line.strip.gsub(/\n/,' ').squeeze(' ')
|
78
|
-
gsub(/(.{1,#{wrap_at}})(?:\s+|$\n?)|(.{1,#{wrap_at}})/, "\\1\\2\n")
|
79
|
+
line.strip.gsub(/\n/, ' ').squeeze(' ')
|
80
|
+
.gsub(/(.{1,#{wrap_at}})(?:\s+|$\n?)|(.{1,#{wrap_at}})/, "\\1\\2\n")
|
81
|
+
.strip
|
79
82
|
end
|
80
83
|
|
81
84
|
# Indent string by given value
|
@@ -91,6 +94,24 @@ module TTY
|
|
91
94
|
end
|
92
95
|
end
|
93
96
|
|
97
|
+
# Add padding to each line in wrapped text
|
98
|
+
#
|
99
|
+
# @param [String] text
|
100
|
+
# the wrapped text
|
101
|
+
#
|
102
|
+
# @return [String]
|
103
|
+
#
|
104
|
+
# @api private
|
105
|
+
def pad_line(text)
|
106
|
+
return text if text.empty? || padding.empty?
|
107
|
+
|
108
|
+
padding_left = ' ' * padding[3].to_i
|
109
|
+
padding_right = ' ' * padding[1].to_i
|
110
|
+
text.map! do |part|
|
111
|
+
part.insert(0, padding_left).insert(-1, padding_right)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
94
115
|
end # Wrapping
|
95
116
|
end # Text
|
96
117
|
end # TTY
|
data/lib/tty/version.rb
CHANGED
@@ -5,7 +5,7 @@ require 'spec_helper'
|
|
5
5
|
describe TTY::Shell::Question, '#argument' do
|
6
6
|
let(:input) { StringIO.new }
|
7
7
|
let(:output) { StringIO.new }
|
8
|
-
let(:shell)
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
9
|
|
10
10
|
it 'requires value to be present with helper' do
|
11
11
|
input << ''
|
@@ -5,7 +5,7 @@ require 'spec_helper'
|
|
5
5
|
describe TTY::Shell::Question, '#modify' do
|
6
6
|
let(:input) { StringIO.new }
|
7
7
|
let(:output) { StringIO.new }
|
8
|
-
let(:shell)
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
9
|
|
10
10
|
it 'preserves answer for unkown modification' do
|
11
11
|
input << 'piotr'
|
@@ -32,7 +32,7 @@ describe TTY::Shell::Question, '#modify' do
|
|
32
32
|
input << " Some white\t space\t \there! \n"
|
33
33
|
input.rewind
|
34
34
|
q = shell.ask("Enter some text: ").modify(:collapse)
|
35
|
-
expect(q.read_string).to eql "
|
35
|
+
expect(q.read_string).to eql "Some white space here!"
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'strips and collapses whitespace' do
|
@@ -49,15 +49,42 @@ describe TTY::Table::Border::ASCII, '#rendering' do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
context 'with multiline row' do
|
52
|
-
let(:row) { TTY::Table::Row.new(["a1\nb1\nc1", 'a2', 'a3']) }
|
53
52
|
let(:column_widths) { [2,2,2]}
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
context 'with mixed data' do
|
55
|
+
let(:row) { TTY::Table::Row.new(["a1\nb1\nc1", 'a2', 'a3']) }
|
56
|
+
|
57
|
+
it 'draws row line' do
|
58
|
+
subject.row_line(row).should == <<-EOS.normalize
|
59
|
+
|a1|a2|a3|
|
60
|
+
|b1| | |
|
61
|
+
|c1| | |
|
62
|
+
EOS
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'with sparse data' do
|
67
|
+
let(:row) { TTY::Table::Row.new(["a1\n\n", "\na2\n", "\n\na3"]) }
|
68
|
+
|
69
|
+
it 'draws row line' do
|
70
|
+
subject.row_line(row).should == <<-EOS.normalize
|
71
|
+
|a1| | |
|
72
|
+
| |a2| |
|
73
|
+
| | |a3|
|
74
|
+
EOS
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with empty data' do
|
79
|
+
let(:row) { TTY::Table::Row.new(["\na1\n", "\na2\n", "\na3\n"]) }
|
80
|
+
|
81
|
+
it 'draws row line' do
|
82
|
+
subject.row_line(row).should == <<-EOS.normalize
|
83
|
+
| | | |
|
84
|
+
|a1|a2|a3|
|
85
|
+
| | | |
|
86
|
+
EOS
|
87
|
+
end
|
61
88
|
end
|
62
89
|
end
|
63
90
|
end
|
@@ -50,15 +50,42 @@ describe TTY::Table::Border::Null, '#rendering' do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
context 'with multiline row' do
|
53
|
-
let(:row) { TTY::Table::Row.new(["a1\nb1\nc1", 'a2', 'a3']) }
|
54
53
|
let(:column_widths) { [2,2,2] }
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
context 'with mixed data' do
|
56
|
+
let(:row) { TTY::Table::Row.new(["a1\nb1\nc1", 'a2', 'a3']) }
|
57
|
+
|
58
|
+
it 'draws row line' do
|
59
|
+
subject.row_line(row).should == <<-EOS.normalize
|
60
|
+
a1 a2 a3
|
61
|
+
b1
|
62
|
+
c1
|
63
|
+
EOS
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with sparse data' do
|
68
|
+
let(:row) { TTY::Table::Row.new(["a1\n\n", "\na2\n", "\n\na3"]) }
|
69
|
+
|
70
|
+
it 'draws row line' do
|
71
|
+
subject.row_line(row).should == <<-EOS.chomp
|
72
|
+
a1
|
73
|
+
a2
|
74
|
+
a3
|
75
|
+
EOS
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with empty data' do
|
80
|
+
let(:row) { TTY::Table::Row.new(["\na1\n", "\na2\n", "\na3\n"]) }
|
81
|
+
|
82
|
+
it 'draws row line' do
|
83
|
+
subject.row_line(row).should == <<-EOS.chomp
|
84
|
+
|
85
|
+
a1 a2 a3
|
86
|
+
|
87
|
+
EOS
|
88
|
+
end
|
62
89
|
end
|
63
90
|
end
|
64
91
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe TTY::Table::ColumnSet, '#extract_widths
|
5
|
+
describe TTY::Table::ColumnSet, '#extract_widths' do
|
6
6
|
let(:header) { ['h1', 'h2', 'h3'] }
|
7
7
|
let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
|
8
8
|
let(:table) { TTY::Table.new header, rows }
|
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe TTY::Table::ColumnSet, '#widths_from' do
|
7
|
+
let(:header) { ['h1', 'h2', 'h3'] }
|
8
|
+
let(:rows) { [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3']] }
|
9
|
+
let(:table) { TTY::Table.new header, rows }
|
10
|
+
|
11
|
+
subject { described_class.widths_from(table, column_widths) }
|
12
|
+
|
13
|
+
context 'when empty array' do
|
14
|
+
let(:column_widths) { [] }
|
15
|
+
|
16
|
+
it 'raises an error' do
|
17
|
+
expect { subject }.to raise_error(TTY::InvalidArgument)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when invalid size array' do
|
22
|
+
let(:column_widths) { [3,3] }
|
23
|
+
|
24
|
+
it 'raises an error' do
|
25
|
+
expect { subject }.to raise_error(TTY::InvalidArgument)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when valid array' do
|
30
|
+
let(:column_widths) { [3,3,3] }
|
31
|
+
|
32
|
+
it 'converts into numbers' do
|
33
|
+
expect(subject).to eql(column_widths)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when nil' do
|
38
|
+
let(:column_widths) { nil }
|
39
|
+
|
40
|
+
it 'extracts widths' do
|
41
|
+
expect(subject).to eql([2,2,2])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when numeric' do
|
46
|
+
let(:column_widths) { 5 }
|
47
|
+
|
48
|
+
it 'generates widths' do
|
49
|
+
expect(subject).to eql([5,5,5])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Table::Columns, '#enforce' do
|
6
|
+
let(:header) { ['h1', 'h2', 'h3', 'h4'] }
|
7
|
+
let(:rows) { [['a1', 'a2', 'a3', 'a4'], ['b1', 'b2', 'b3', 'b4']] }
|
8
|
+
let(:table) { TTY::Table.new(header, rows) }
|
9
|
+
let(:object) { described_class.new(renderer) }
|
10
|
+
|
11
|
+
subject { object.enforce }
|
12
|
+
|
13
|
+
context 'with width contraint' do
|
14
|
+
let(:renderer) { TTY::Table::Renderer::Basic.new(table, options) }
|
15
|
+
let(:options) { { width: 5 }}
|
16
|
+
|
17
|
+
it 'raises error when table width is too small' do
|
18
|
+
expect { subject }.to raise_error(TTY::ResizeError)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with width contraint matching natural width' do
|
23
|
+
let(:renderer) { TTY::Table::Renderer::Basic.new(table, options) }
|
24
|
+
let(:options) { { width: 11, resize: true }}
|
25
|
+
|
26
|
+
it 'raises error when table width is too small' do
|
27
|
+
expect(object).to receive(:expand)
|
28
|
+
subject
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with table larger than allowed width' do
|
33
|
+
let(:renderer) { TTY::Table::Renderer::Basic.new(table, options) }
|
34
|
+
|
35
|
+
context 'with resize' do
|
36
|
+
let(:options) { { width: 8, resize: true } }
|
37
|
+
|
38
|
+
it 'calls shrink' do
|
39
|
+
expect(object).to receive(:shrink)
|
40
|
+
subject
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'without resize' do
|
45
|
+
let(:options) { { width: 8, resize: false }}
|
46
|
+
|
47
|
+
it 'changes table orientation to vertical' do
|
48
|
+
TTY.shell.should_receive(:warn)
|
49
|
+
expect(renderer.column_widths).to eql([2,2,2,2])
|
50
|
+
expect(renderer.table.orientation.name).to eql(:horizontal)
|
51
|
+
subject
|
52
|
+
expect(renderer.column_widths).to eq([2,2])
|
53
|
+
expect(renderer.table.orientation.name).to eql(:vertical)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with table less than allowed width' do
|
59
|
+
let(:renderer) { TTY::Table::Renderer::Basic.new(table, options) }
|
60
|
+
let(:options) { { width: 15 }}
|
61
|
+
|
62
|
+
before { TTY.shell.stub(:warn) }
|
63
|
+
|
64
|
+
it "doesn't change original widths" do
|
65
|
+
expect(renderer.column_widths).to eq([2,2,2,2])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TTY::Table::Columns, 'column widths' do
|
4
|
+
let(:header) { ['h1', 'h2', 'h3', 'h4'] }
|
5
|
+
let(:rows) { [['a1', 'a2', 'a3', 'a4'], ['b1', 'b2', 'b3', 'b4']] }
|
6
|
+
let(:table) { TTY::Table.new(header, rows) }
|
7
|
+
|
8
|
+
subject { described_class.new(renderer) }
|
9
|
+
|
10
|
+
context 'with basic renderer' do
|
11
|
+
let(:renderer) { TTY::Table::Renderer::Basic.new(table) }
|
12
|
+
|
13
|
+
it 'calculates columns natural width' do
|
14
|
+
expect(subject.natural_width).to eq(11)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'calculates miminimum columns width' do
|
18
|
+
expect(subject.minimum_width).to eq(7)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with ascii renderer' do
|
23
|
+
let(:renderer) { TTY::Table::Renderer::ASCII.new(table) }
|
24
|
+
|
25
|
+
it 'calculates columns natural width' do
|
26
|
+
expect(subject.natural_width).to eq(13)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'calculates miminimum columns width' do
|
30
|
+
expect(subject.minimum_width).to eq(9)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Table::Indentation, '#insert_indent' do
|
6
|
+
let(:indent) { 2 }
|
7
|
+
let(:renderer) { double(:renderer, indent: indent) }
|
8
|
+
let(:object) { described_class.new(renderer) }
|
9
|
+
|
10
|
+
subject { object.insert_indent(part) }
|
11
|
+
|
12
|
+
context 'when enumerable' do
|
13
|
+
let(:part) { ['line1'] }
|
14
|
+
|
15
|
+
it 'inserts indentation for each element' do
|
16
|
+
expect(subject[0]).to eql(' line1')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when string' do
|
21
|
+
let(:part) { 'line1' }
|
22
|
+
|
23
|
+
it 'inserts indentation' do
|
24
|
+
expect(subject).to eql(' line1')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -3,7 +3,8 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe TTY::Table::Operation::Wrapped, '#call' do
|
6
|
-
let(:
|
6
|
+
let(:padding) { TTY::Table::Padder.parse }
|
7
|
+
let(:object) { described_class.new(column_widths, padding) }
|
7
8
|
let(:text) { 'ラドクリフ、マラソン五輪代表に1万m出場にも含み' }
|
8
9
|
let(:field) { TTY::Table::Field.new(text) }
|
9
10
|
|
@@ -3,8 +3,9 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe TTY::Table::Operation::Wrapped, '#wrap' do
|
6
|
-
let(:
|
7
|
-
let(:
|
6
|
+
let(:padding) { TTY::Table::Padder.parse }
|
7
|
+
let(:instance) { described_class.new([], padding) }
|
8
|
+
let(:text) { 'ラドクリフ、マラソン五輪代表に1万m出場にも含み' }
|
8
9
|
|
9
10
|
subject { instance.wrap(text, width) }
|
10
11
|
|
@@ -4,8 +4,8 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe TTY::Table::Operations, '#new' do
|
6
6
|
let(:object) { described_class }
|
7
|
-
let(:row)
|
8
|
-
let(:table)
|
7
|
+
let(:row) { [1,2,3] }
|
8
|
+
let(:table) { TTY::Table.new :rows => [row] }
|
9
9
|
let(:callable) {
|
10
10
|
Class.new do
|
11
11
|
def call(val, row, col)
|
@@ -17,9 +17,7 @@ describe TTY::Table::Operations, '#new' do
|
|
17
17
|
|
18
18
|
subject { object.new table }
|
19
19
|
|
20
|
-
before {
|
21
|
-
subject.add_operation(:alignment, instance)
|
22
|
-
}
|
20
|
+
before { subject.add(:alignment, instance) }
|
23
21
|
|
24
22
|
it 'stores away operations' do
|
25
23
|
expect(subject.operations[:alignment]).to include(instance)
|