tty 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|