tty-prompt 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.travis.yml +24 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +22 -0
- data/README.md +199 -0
- data/Rakefile +8 -0
- data/lib/tty-prompt.rb +15 -0
- data/lib/tty/prompt.rb +206 -0
- data/lib/tty/prompt/distance.rb +49 -0
- data/lib/tty/prompt/error.rb +26 -0
- data/lib/tty/prompt/history.rb +16 -0
- data/lib/tty/prompt/mode.rb +64 -0
- data/lib/tty/prompt/mode/echo.rb +40 -0
- data/lib/tty/prompt/mode/raw.rb +40 -0
- data/lib/tty/prompt/question.rb +338 -0
- data/lib/tty/prompt/question/modifier.rb +93 -0
- data/lib/tty/prompt/question/validation.rb +92 -0
- data/lib/tty/prompt/reader.rb +113 -0
- data/lib/tty/prompt/response.rb +252 -0
- data/lib/tty/prompt/response_delegation.rb +41 -0
- data/lib/tty/prompt/statement.rb +60 -0
- data/lib/tty/prompt/suggestion.rb +113 -0
- data/lib/tty/prompt/utils.rb +16 -0
- data/lib/tty/prompt/version.rb +7 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/unit/ask_spec.rb +77 -0
- data/spec/unit/distance/distance_spec.rb +75 -0
- data/spec/unit/error_spec.rb +30 -0
- data/spec/unit/question/argument_spec.rb +30 -0
- data/spec/unit/question/character_spec.rb +24 -0
- data/spec/unit/question/default_spec.rb +25 -0
- data/spec/unit/question/in_spec.rb +23 -0
- data/spec/unit/question/initialize_spec.rb +24 -0
- data/spec/unit/question/modifier/apply_to_spec.rb +31 -0
- data/spec/unit/question/modifier/letter_case_spec.rb +22 -0
- data/spec/unit/question/modifier/whitespace_spec.rb +33 -0
- data/spec/unit/question/modify_spec.rb +44 -0
- data/spec/unit/question/valid_spec.rb +46 -0
- data/spec/unit/question/validate_spec.rb +30 -0
- data/spec/unit/question/validation/coerce_spec.rb +24 -0
- data/spec/unit/question/validation/valid_value_spec.rb +22 -0
- data/spec/unit/reader/getc_spec.rb +42 -0
- data/spec/unit/response/read_bool_spec.rb +47 -0
- data/spec/unit/response/read_char_spec.rb +16 -0
- data/spec/unit/response/read_date_spec.rb +20 -0
- data/spec/unit/response/read_email_spec.rb +42 -0
- data/spec/unit/response/read_multiple_spec.rb +23 -0
- data/spec/unit/response/read_number_spec.rb +28 -0
- data/spec/unit/response/read_range_spec.rb +26 -0
- data/spec/unit/response/read_spec.rb +68 -0
- data/spec/unit/response/read_string_spec.rb +19 -0
- data/spec/unit/say_spec.rb +66 -0
- data/spec/unit/statement/initialize_spec.rb +19 -0
- data/spec/unit/suggest_spec.rb +33 -0
- data/spec/unit/warn_spec.rb +30 -0
- data/tasks/console.rake +10 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +29 -0
- data/tty-prompt.gemspec +26 -0
- metadata +194 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#read_char' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads single character' do
|
11
|
+
input << "abcde"
|
12
|
+
input.rewind
|
13
|
+
q = prompt.ask("What is your favourite letter?")
|
14
|
+
expect(q.read_char).to eql "a"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#read_date' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads date' do
|
11
|
+
input << "20th April 1887"
|
12
|
+
input.rewind
|
13
|
+
q = prompt.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,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#read_email' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
context 'with valid email' do
|
11
|
+
it 'reads empty' do
|
12
|
+
input << ""
|
13
|
+
input.rewind
|
14
|
+
q = prompt.ask("What is your email?")
|
15
|
+
expect(q.read_email).to eql(nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'reads valid email' do
|
19
|
+
input << "piotr@example.com"
|
20
|
+
input.rewind
|
21
|
+
q = prompt.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 = prompt.ask("What is your email?")
|
31
|
+
expect { q.read_email }.to raise_error(TTY::Prompt::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 = prompt.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
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#read_multiple' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads multiple lines' do
|
11
|
+
input << "First line\nSecond line\nThird line"
|
12
|
+
input.rewind
|
13
|
+
q = prompt.ask("Provide description?")
|
14
|
+
expect(q.read_multiple).to eq("First line\nSecond line\nThird line")
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'terminates on empty lines' do
|
18
|
+
input << "First line\n\nSecond line"
|
19
|
+
input.rewind
|
20
|
+
q = prompt.ask("Provide description?")
|
21
|
+
expect(q.read_multiple).to eq("First line\n")
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#read_numbers' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads integer' do
|
11
|
+
input << 35
|
12
|
+
input.rewind
|
13
|
+
q = prompt.ask("What temperature?")
|
14
|
+
answer = q.read_int
|
15
|
+
expect(answer).to be_kind_of Integer
|
16
|
+
expect(answer).to eql 35
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'reads float' do
|
20
|
+
number = 6.666
|
21
|
+
input << number
|
22
|
+
input.rewind
|
23
|
+
q = prompt.ask("How tall are you?")
|
24
|
+
answer = q.read_float
|
25
|
+
expect(answer).to be_kind_of Float
|
26
|
+
expect(answer).to eql number
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#read_range' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
it 'converts with valid range' do
|
11
|
+
input << "20-30"
|
12
|
+
input.rewind
|
13
|
+
response = prompt.ask("Which age group?").read_range
|
14
|
+
|
15
|
+
expect(response).to be_kind_of Range
|
16
|
+
expect(response).to eql (20..30)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "fails to convert to range" do
|
20
|
+
input << "abcd"
|
21
|
+
input.rewind
|
22
|
+
expect {
|
23
|
+
prompt.ask("Which age group?").read_range
|
24
|
+
}.to raise_error(Necromancer::ConversionTypeError)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#read' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.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 = prompt.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 eq(false)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'asks with echo off' do
|
21
|
+
input << "password"
|
22
|
+
input.rewind
|
23
|
+
q = prompt.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 eq(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 = prompt.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 eq(true)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'ignores mask if echo is off' do
|
41
|
+
input << "password"
|
42
|
+
input.rewind
|
43
|
+
q = prompt.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 eq(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 = prompt.ask("What is your password: ", echo: false, mask: '*')
|
55
|
+
expect(q.read).to eq("password")
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'asks with block' do
|
59
|
+
input << "password"
|
60
|
+
input.rewind
|
61
|
+
q = prompt.ask "What is your password: " do
|
62
|
+
echo false
|
63
|
+
mask '*'
|
64
|
+
end
|
65
|
+
expect(q.read).to eq("password")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Question, '#initialize' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:prompt) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
it 'reads string' do
|
11
|
+
name = "Piotr"
|
12
|
+
input << name
|
13
|
+
input.rewind
|
14
|
+
q = prompt.ask("What is your name?")
|
15
|
+
answer = q.read_string
|
16
|
+
expect(answer).to be_kind_of String
|
17
|
+
expect(answer).to eql name
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt, '#say' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:color) { Pastel.new(enabled: true) }
|
9
|
+
|
10
|
+
subject(:prompt) { described_class.new(input, output) }
|
11
|
+
|
12
|
+
before { allow(Pastel).to receive(:new).and_return(color) }
|
13
|
+
|
14
|
+
after { output.rewind }
|
15
|
+
|
16
|
+
it 'prints an empty message' do
|
17
|
+
prompt.say ""
|
18
|
+
expect(output.string).to eql ""
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with new line' do
|
22
|
+
it 'prints a message with newline' do
|
23
|
+
prompt.say "Hell yeah!\n"
|
24
|
+
expect(output.string).to eql "Hell yeah!\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'prints a message with implicit newline' do
|
28
|
+
prompt.say "Hell yeah!\n"
|
29
|
+
expect(output.string).to eql "Hell yeah!\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'prints a message with newline within text' do
|
33
|
+
prompt.say "Hell\n yeah!"
|
34
|
+
expect(output.string).to eql "Hell\n yeah!\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'prints a message with newline within text and blank space' do
|
38
|
+
prompt.say "Hell\n yeah! "
|
39
|
+
expect(output.string).to eql "Hell\n yeah! "
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'prints a message without newline' do
|
43
|
+
prompt.say "Hell yeah!", newline: false
|
44
|
+
expect(output.string).to eql "Hell yeah!"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'with tab or space' do
|
49
|
+
it 'prints ' do
|
50
|
+
prompt.say "Hell yeah!\t"
|
51
|
+
expect(output.string).to eql "Hell yeah!\t"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with color' do
|
56
|
+
it 'prints message with ansi color' do
|
57
|
+
prompt.say "Hell yeah!", color: :green
|
58
|
+
expect(output.string).to eql "\e[32mHell yeah!\e[0m\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'prints message with ansi color without newline' do
|
62
|
+
prompt.say "Hell yeah! ", color: :green
|
63
|
+
expect(output.string).to eql "\e[32mHell yeah! \e[0m"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt::Statement, '#new' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:shell) { TTY::Prompt.new(input, output) }
|
9
|
+
|
10
|
+
it "forces newline after the prompt message" do
|
11
|
+
statement = described_class.new
|
12
|
+
expect(statement.newline).to eq(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "displays prompt message in color" do
|
16
|
+
statement = described_class.new
|
17
|
+
expect(statement.color).to eq(false)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt, '#suggest' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:possible) { %w(status stage stash commit branch blame) }
|
9
|
+
|
10
|
+
subject(:prompt) { described_class.new(input, output) }
|
11
|
+
|
12
|
+
after { output.rewind }
|
13
|
+
|
14
|
+
it 'suggests few matches' do
|
15
|
+
prompt.suggest('sta', possible)
|
16
|
+
expect(output.string).to eql("Did you mean one of these?\n stage\n stash\n")
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'suggests a single match for one character' do
|
20
|
+
prompt.suggest('b', possible)
|
21
|
+
expect(output.string).to eql("Did you mean this?\n blame\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'suggests a single match for two characters' do
|
25
|
+
prompt.suggest('co', possible)
|
26
|
+
expect(output.string).to eql("Did you mean this?\n commit\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'suggests with different text and indentation' do
|
30
|
+
prompt.suggest('b', possible, indent: 4, single_text: 'Perhaps you meant?')
|
31
|
+
expect(output.string).to eql("Perhaps you meant?\n blame\n")
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe TTY::Prompt, '#warn' do
|
6
|
+
let(:input) { StringIO.new }
|
7
|
+
let(:output) { StringIO.new }
|
8
|
+
let(:color) { Pastel.new(enabled: true) }
|
9
|
+
|
10
|
+
subject(:prompt) { TTY::Prompt.new(input, output) }
|
11
|
+
|
12
|
+
before { allow(Pastel).to receive(:new).and_return(color) }
|
13
|
+
|
14
|
+
after { output.rewind }
|
15
|
+
|
16
|
+
it 'displays one message' do
|
17
|
+
prompt.warn "Careful young apprentice!"
|
18
|
+
expect(output.string).to eql "\e[33mCareful young apprentice!\e[0m\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'displays many messages' do
|
22
|
+
prompt.warn "Careful there!", "It's dangerous!"
|
23
|
+
expect(output.string).to eql "\e[33mCareful there!\e[0m\n\e[33mIt's dangerous!\e[0m\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'displays message with option' do
|
27
|
+
prompt.warn "Careful young apprentice!", newline: false
|
28
|
+
expect(output.string).to eql "\e[33mCareful young apprentice!\e[0m"
|
29
|
+
end
|
30
|
+
end
|
data/tasks/console.rake
ADDED
data/tasks/coverage.rake
ADDED
data/tasks/spec.rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
desc 'Run all specs'
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :spec do
|
12
|
+
desc 'Run unit specs'
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
+
task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run integration specs'
|
18
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
+
task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
rescue LoadError
|
24
|
+
%w[spec spec:unit spec:integration].each do |name|
|
25
|
+
task name do
|
26
|
+
$stderr.puts "In order to run #{name}, do `gem install rspec`"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|