tty 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +78 -12
- data/benchmarks/shell.rb +26 -0
- data/benchmarks/table.rb +35 -0
- data/lib/tty.rb +23 -1
- data/lib/tty/coercer.rb +13 -0
- data/lib/tty/coercer/boolean.rb +39 -0
- data/lib/tty/coercer/float.rb +23 -0
- data/lib/tty/coercer/integer.rb +23 -0
- data/lib/tty/coercer/range.rb +33 -0
- data/lib/tty/shell.rb +6 -2
- data/lib/tty/shell/question.rb +158 -138
- data/lib/tty/shell/reader.rb +92 -0
- data/lib/tty/shell/response.rb +219 -0
- data/lib/tty/shell/response_delegation.rb +53 -0
- data/lib/tty/table.rb +90 -16
- data/lib/tty/table/border.rb +34 -8
- data/lib/tty/table/border/ascii.rb +16 -25
- data/lib/tty/table/border/null.rb +0 -6
- data/lib/tty/table/border/unicode.rb +16 -25
- data/lib/tty/table/column_set.rb +1 -1
- data/lib/tty/table/error.rb +10 -0
- data/lib/tty/table/operation/wrapped.rb +0 -6
- data/lib/tty/table/orientation.rb +57 -0
- data/lib/tty/table/orientation/horizontal.rb +19 -0
- data/lib/tty/table/orientation/vertical.rb +19 -0
- data/lib/tty/table/renderer.rb +7 -0
- data/lib/tty/table/renderer/ascii.rb +1 -1
- data/lib/tty/table/renderer/basic.rb +2 -2
- data/lib/tty/table/renderer/unicode.rb +1 -1
- data/lib/tty/table/validatable.rb +20 -0
- data/lib/tty/terminal.rb +15 -14
- data/lib/tty/terminal/color.rb +1 -1
- data/lib/tty/terminal/echo.rb +41 -0
- data/lib/tty/terminal/home.rb +31 -0
- data/lib/tty/text.rb +85 -0
- data/lib/tty/text/truncation.rb +83 -0
- data/lib/tty/text/wrapping.rb +96 -0
- data/lib/tty/version.rb +1 -1
- data/spec/tty/coercer/boolean/coerce_spec.rb +113 -0
- data/spec/tty/coercer/float/coerce_spec.rb +32 -0
- data/spec/tty/coercer/integer/coerce_spec.rb +39 -0
- data/spec/tty/coercer/range/coerce_spec.rb +73 -0
- data/spec/tty/shell/ask_spec.rb +14 -1
- data/spec/tty/shell/question/argument_spec.rb +30 -0
- data/spec/tty/shell/question/character_spec.rb +16 -0
- data/spec/tty/shell/question/default_spec.rb +25 -0
- data/spec/tty/shell/question/in_spec.rb +23 -0
- data/spec/tty/shell/question/initialize_spec.rb +11 -211
- data/spec/tty/shell/question/modifier/whitespace_spec.rb +1 -1
- data/spec/tty/shell/question/modify_spec.rb +44 -0
- data/spec/tty/shell/question/valid_spec.rb +46 -0
- data/spec/tty/shell/question/validate_spec.rb +30 -0
- data/spec/tty/shell/reader/getc_spec.rb +40 -0
- data/spec/tty/shell/response/read_bool_spec.rb +41 -0
- data/spec/tty/shell/response/read_char_spec.rb +17 -0
- data/spec/tty/shell/response/read_date_spec.rb +20 -0
- data/spec/tty/shell/response/read_email_spec.rb +43 -0
- data/spec/tty/shell/response/read_multiple_spec.rb +24 -0
- data/spec/tty/shell/response/read_number_spec.rb +29 -0
- data/spec/tty/shell/response/read_range_spec.rb +29 -0
- data/spec/tty/shell/response/read_spec.rb +68 -0
- data/spec/tty/shell/response/read_string_spec.rb +19 -0
- data/spec/tty/table/access_spec.rb +6 -0
- data/spec/tty/table/border/new_spec.rb +3 -3
- data/spec/tty/table/initialize_spec.rb +17 -1
- data/spec/tty/table/options_spec.rb +7 -1
- data/spec/tty/table/orientation_spec.rb +98 -0
- data/spec/tty/table/renders_with_spec.rb +76 -0
- data/spec/tty/table/rotate_spec.rb +72 -0
- data/spec/tty/table/to_s_spec.rb +13 -1
- data/spec/tty/table/validatable/validate_options_spec.rb +34 -0
- data/spec/tty/terminal/color/remove_spec.rb +34 -1
- data/spec/tty/terminal/echo_spec.rb +22 -0
- data/spec/tty/text/truncate_spec.rb +13 -0
- data/spec/tty/text/truncation/initialize_spec.rb +29 -0
- data/spec/tty/text/truncation/truncate_spec.rb +73 -0
- data/spec/tty/text/wrap_spec.rb +14 -0
- data/spec/tty/text/wrapping/initialize_spec.rb +25 -0
- data/spec/tty/text/wrapping/wrap_spec.rb +80 -0
- data/tty.gemspec +1 -0
- metadata +101 -8
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#modify' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
it 'preserves answer for unkown modification' do
|
11
|
+
input << 'piotr'
|
12
|
+
input.rewind
|
13
|
+
q = shell.ask("What is your name?").modify(:none)
|
14
|
+
expect(q.read_string).to eql 'piotr'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'converts to upper case' do
|
18
|
+
input << 'piotr'
|
19
|
+
input.rewind
|
20
|
+
q = shell.ask("What is your name?").modify(:upcase)
|
21
|
+
expect(q.read_string).to eql 'PIOTR'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'trims whitespace' do
|
25
|
+
input << " Some white\t space\t \there! \n"
|
26
|
+
input.rewind
|
27
|
+
q = shell.ask("Enter some text: ").modify(:trim)
|
28
|
+
expect(q.read_string).to eql "Some white\t space\t \there!"
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'collapses whitespace' do
|
32
|
+
input << " Some white\t space\t \there! \n"
|
33
|
+
input.rewind
|
34
|
+
q = shell.ask("Enter some text: ").modify(:collapse)
|
35
|
+
expect(q.read_string).to eql " Some white space here! "
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'strips and collapses whitespace' do
|
39
|
+
input << " Some white\t space\t \there! \n"
|
40
|
+
input.rewind
|
41
|
+
q = shell.ask("Enter some text: ").modify(:strip, :collapse)
|
42
|
+
expect(q.read_string).to eql "Some white space here!"
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#valid' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
let(:cards) { %w[ club diamond spade heart ] }
|
11
|
+
|
12
|
+
it 'reads valid optios with helper' do
|
13
|
+
input << 'club'
|
14
|
+
input.rewind
|
15
|
+
q = shell.ask("What is your card suit sir?").valid(cards)
|
16
|
+
expect(q.read_choice).to eql 'club'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'reads valid options with option hash' do
|
20
|
+
input << 'club'
|
21
|
+
input.rewind
|
22
|
+
q = shell.ask("What is your card suit sir?", :valid => cards)
|
23
|
+
expect(q.read_choice).to eql 'club'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'reads invalid option' do
|
27
|
+
input << 'clover'
|
28
|
+
input.rewind
|
29
|
+
q = shell.ask("What is your card suit sir?").valid(cards)
|
30
|
+
expect { q.read_choice }.to raise_error(TTY::InvalidArgument)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'needs argument' do
|
34
|
+
input << ''
|
35
|
+
input.rewind
|
36
|
+
q = shell.ask("What is your card suit sir?").valid(cards)
|
37
|
+
expect { q.read_choice }.to raise_error(TTY::ArgumentRequired)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'reads with default' do
|
41
|
+
input << ''
|
42
|
+
input.rewind
|
43
|
+
q = shell.ask("What is your card suit sir?").valid(cards).default('club')
|
44
|
+
expect(q.read_choice).to eql 'club'
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#validate' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
it 'fails to validate input' do
|
11
|
+
input << 'piotrmurach'
|
12
|
+
input.rewind
|
13
|
+
q = shell.ask("What is your username?").validate(/^[^\.]+\.[^\.]+/)
|
14
|
+
expect { q.read_string }.to raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'validates input with regex' do
|
18
|
+
input << 'piotr.murach'
|
19
|
+
input.rewind
|
20
|
+
q = shell.ask("What is your username?").validate(/^[^\.]+\.[^\.]+/)
|
21
|
+
expect(q.read_string).to eql 'piotr.murach'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'validates input in block' do
|
25
|
+
input << 'piotr.murach'
|
26
|
+
input.rewind
|
27
|
+
q = shell.ask("What is your username?").validate { |arg| arg =~ /^[^\.]+\.[^\.]+/ }
|
28
|
+
expect(q.read_string).to eql 'piotr.murach'
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Reader, '#getc' do
|
6
|
+
let(:instance) { described_class.new(shell) }
|
7
|
+
|
8
|
+
let(:input) { StringIO.new }
|
9
|
+
let(:output) { StringIO.new }
|
10
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
11
|
+
let(:mask) { '*'}
|
12
|
+
|
13
|
+
subject(:reader) { instance.getc mask }
|
14
|
+
|
15
|
+
it 'masks characters' do
|
16
|
+
input << "password\n"
|
17
|
+
input.rewind
|
18
|
+
expect(reader).to eql "password"
|
19
|
+
expect(output.string).to eql("********")
|
20
|
+
end
|
21
|
+
|
22
|
+
context "without mask" do
|
23
|
+
let(:mask) { }
|
24
|
+
|
25
|
+
it 'masks characters' do
|
26
|
+
input << "password\n"
|
27
|
+
input.rewind
|
28
|
+
expect(reader).to eql "password"
|
29
|
+
expect(output.string).to eql("password")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'deletes characters when backspace pressed' do
|
35
|
+
input << "\b\b"
|
36
|
+
input.rewind
|
37
|
+
expect(reader).to eql ''
|
38
|
+
expect(output.string).to eql('')
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#read_bool' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
it 'fails to read boolean' do
|
11
|
+
input << 'invalid'
|
12
|
+
input.rewind
|
13
|
+
q = shell.ask("Do you read books?")
|
14
|
+
expect { q.read_bool }.to raise_error(TTY::TypeError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'reads negative boolean' do
|
18
|
+
input << 'No'
|
19
|
+
input.rewind
|
20
|
+
q = shell.ask("Do you read books?")
|
21
|
+
answer = q.read_bool
|
22
|
+
expect(answer).to eql false
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'reads positive boolean' do
|
26
|
+
input << 'Yes'
|
27
|
+
input.rewind
|
28
|
+
q = shell.ask("Do you read books?")
|
29
|
+
answer = q.read_bool
|
30
|
+
expect(answer).to eql true
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'reads single positive boolean' do
|
34
|
+
input << 'y'
|
35
|
+
input.rewind
|
36
|
+
q = shell.ask("Do you read books?")
|
37
|
+
answer = q.read_bool
|
38
|
+
expect(answer).to eql true
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#read_char' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads single character' do
|
11
|
+
input << "abcde"
|
12
|
+
input.rewind
|
13
|
+
q = shell.ask("What is your favourite letter?")
|
14
|
+
expect(q.read_char).to eql "a"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#read_date' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads date' do
|
11
|
+
input << "20th April 1887"
|
12
|
+
input.rewind
|
13
|
+
q = shell.ask("When were your born?")
|
14
|
+
answer = q.read_date
|
15
|
+
expect(answer).to be_kind_of Date
|
16
|
+
expect(answer.day).to eql 20
|
17
|
+
expect(answer.month).to eql 4
|
18
|
+
expect(answer.year).to eql 1887
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#read_email' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
context 'with valid email' do
|
11
|
+
it 'reads empty' do
|
12
|
+
input << ""
|
13
|
+
input.rewind
|
14
|
+
q = shell.ask("What is your email?")
|
15
|
+
expect { q.read_email }.to raise_error(TTY::InvalidArgument)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'reads valid email' do
|
19
|
+
input << "piotr@example.com"
|
20
|
+
input.rewind
|
21
|
+
q = shell.ask("What is your email?")
|
22
|
+
expect(q.read_email).to eql "piotr@example.com"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with invalid email' do
|
27
|
+
it 'fails to read invalid email' do
|
28
|
+
input << "this will@neverwork"
|
29
|
+
input.rewind
|
30
|
+
q = shell.ask("What is your email?")
|
31
|
+
expect { q.read_email }.to raise_error(TTY::InvalidArgument)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'reads invalid and asks again' do
|
35
|
+
input << "this will@neverwork\nthis.will@example.com"
|
36
|
+
input.rewind
|
37
|
+
q = shell.ask("What is your email?").on_error(:retry)
|
38
|
+
expect(q.read_email).to eql "this.will@example.com"
|
39
|
+
expect(output.string).to eql "What is your email?\nWhat is your email?\n"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#read_multiple' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads multiple lines' do
|
11
|
+
input << "First line\nSecond line\nThird line"
|
12
|
+
input.rewind
|
13
|
+
q = shell.ask("Provide description?")
|
14
|
+
expect(q.read_multiple).to eql "First line\nSecond line\nThird line"
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'skips empty lines' do
|
18
|
+
input << "First line\n\nSecond line"
|
19
|
+
input.rewind
|
20
|
+
q = shell.ask("Provide description?")
|
21
|
+
expect(q.read_multiple).to eql "First line\nSecond line"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
# -*- encoding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe TTY::Shell::Question, '#read_numbers' do
|
7
|
+
let(:input) { StringIO.new }
|
8
|
+
let(:output) { StringIO.new }
|
9
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
10
|
+
|
11
|
+
it 'reads integer' do
|
12
|
+
input << 35
|
13
|
+
input.rewind
|
14
|
+
q = shell.ask("What temperature?")
|
15
|
+
answer = q.read_int
|
16
|
+
expect(answer).to be_kind_of Integer
|
17
|
+
expect(answer).to eql 35
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'reads float' do
|
21
|
+
number = 6.666
|
22
|
+
input << number
|
23
|
+
input.rewind
|
24
|
+
q = shell.ask("How tall are you?")
|
25
|
+
answer = q.read_float
|
26
|
+
expect(answer).to be_kind_of Float
|
27
|
+
expect(answer).to eql number
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#read_range' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
subject {
|
11
|
+
input << value
|
12
|
+
input.rewind
|
13
|
+
shell.ask("Which age group?").read_range
|
14
|
+
}
|
15
|
+
|
16
|
+
context 'with valid range' do
|
17
|
+
let(:value) { "20-30" }
|
18
|
+
|
19
|
+
it { expect(subject).to be_kind_of Range }
|
20
|
+
|
21
|
+
it { expect(subject).to eql (20..30) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with invalid range' do
|
25
|
+
let(:value) { "abcd" }
|
26
|
+
|
27
|
+
it { expect { subject }.to raise_error(ArgumentError) }
|
28
|
+
end
|
29
|
+
end # read_range
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe TTY::Shell::Question, '#read_password' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Shell.new(input, output) }
|
9
|
+
|
10
|
+
context 'with no mask' do
|
11
|
+
it 'asks with echo on' do
|
12
|
+
input << "password"
|
13
|
+
input.rewind
|
14
|
+
q = shell.ask("What is your password: ").echo(true)
|
15
|
+
expect(q.read).to eql("password")
|
16
|
+
expect(output.string).to eql('What is your password: ')
|
17
|
+
expect(q.mask?).to be_false
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'asks with echo off' do
|
21
|
+
input << "password"
|
22
|
+
input.rewind
|
23
|
+
q = shell.ask("What is your password: ").echo(false)
|
24
|
+
expect(q.read).to eql("password")
|
25
|
+
expect(output.string).to eql('What is your password: ')
|
26
|
+
expect(q.mask?).to be_false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with mask' do
|
31
|
+
it 'masks output with character' do
|
32
|
+
input << "password\n"
|
33
|
+
input.rewind
|
34
|
+
q = shell.ask("What is your password: ").mask('*')
|
35
|
+
expect(q.read).to eql("password")
|
36
|
+
expect(output.string).to eql('What is your password: ********')
|
37
|
+
expect(q.mask?).to be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'ignores mask if echo is off' do
|
41
|
+
input << "password"
|
42
|
+
input.rewind
|
43
|
+
q = shell.ask("What is your password: ").echo(false).mask('*')
|
44
|
+
expect(q.read).to eql("password")
|
45
|
+
expect(output.string).to eql('What is your password: ')
|
46
|
+
expect(q.mask?).to be_true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with mask and echo as options' do
|
51
|
+
it 'asks with options' do
|
52
|
+
input << "password"
|
53
|
+
input.rewind
|
54
|
+
q = shell.ask("What is your password: ", :echo => false, :mask => '*')
|
55
|
+
expect(q.read_password).to eql("password")
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'asks with block' do
|
59
|
+
input << "password"
|
60
|
+
input.rewind
|
61
|
+
q = shell.ask "What is your password: " do
|
62
|
+
echo false
|
63
|
+
mask '*'
|
64
|
+
end
|
65
|
+
expect(q.read_password).to eql("password")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|