tty-prompt 0.1.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.
- 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
|