tty-prompt 0.16.1 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/tty/prompt/messages.rb +49 -0
  4. data/lib/tty/prompt/version.rb +1 -3
  5. data/spec/spec_helper.rb +45 -0
  6. data/spec/unit/ask_spec.rb +132 -0
  7. data/spec/unit/choice/eql_spec.rb +22 -0
  8. data/spec/unit/choice/from_spec.rb +96 -0
  9. data/spec/unit/choices/add_spec.rb +12 -0
  10. data/spec/unit/choices/each_spec.rb +13 -0
  11. data/spec/unit/choices/find_by_spec.rb +10 -0
  12. data/spec/unit/choices/new_spec.rb +10 -0
  13. data/spec/unit/choices/pluck_spec.rb +9 -0
  14. data/spec/unit/collect_spec.rb +96 -0
  15. data/spec/unit/converters/convert_bool_spec.rb +58 -0
  16. data/spec/unit/converters/convert_char_spec.rb +11 -0
  17. data/spec/unit/converters/convert_custom_spec.rb +14 -0
  18. data/spec/unit/converters/convert_date_spec.rb +34 -0
  19. data/spec/unit/converters/convert_file_spec.rb +18 -0
  20. data/spec/unit/converters/convert_number_spec.rb +39 -0
  21. data/spec/unit/converters/convert_path_spec.rb +15 -0
  22. data/spec/unit/converters/convert_range_spec.rb +22 -0
  23. data/spec/unit/converters/convert_regex_spec.rb +12 -0
  24. data/spec/unit/converters/convert_string_spec.rb +21 -0
  25. data/spec/unit/converters/on_error_spec.rb +9 -0
  26. data/spec/unit/distance/distance_spec.rb +73 -0
  27. data/spec/unit/enum_paginator_spec.rb +75 -0
  28. data/spec/unit/enum_select_spec.rb +446 -0
  29. data/spec/unit/error_spec.rb +20 -0
  30. data/spec/unit/evaluator_spec.rb +67 -0
  31. data/spec/unit/expand_spec.rb +198 -0
  32. data/spec/unit/keypress_spec.rb +72 -0
  33. data/spec/unit/mask_spec.rb +132 -0
  34. data/spec/unit/multi_select_spec.rb +495 -0
  35. data/spec/unit/multiline_spec.rb +77 -0
  36. data/spec/unit/new_spec.rb +20 -0
  37. data/spec/unit/ok_spec.rb +10 -0
  38. data/spec/unit/paginator_spec.rb +73 -0
  39. data/spec/unit/question/checks_spec.rb +97 -0
  40. data/spec/unit/question/default_spec.rb +31 -0
  41. data/spec/unit/question/echo_spec.rb +38 -0
  42. data/spec/unit/question/in_spec.rb +115 -0
  43. data/spec/unit/question/initialize_spec.rb +12 -0
  44. data/spec/unit/question/modifier/apply_to_spec.rb +24 -0
  45. data/spec/unit/question/modifier/letter_case_spec.rb +41 -0
  46. data/spec/unit/question/modifier/whitespace_spec.rb +51 -0
  47. data/spec/unit/question/modify_spec.rb +41 -0
  48. data/spec/unit/question/required_spec.rb +92 -0
  49. data/spec/unit/question/validate_spec.rb +115 -0
  50. data/spec/unit/question/validation/call_spec.rb +31 -0
  51. data/spec/unit/question/validation/coerce_spec.rb +30 -0
  52. data/spec/unit/result_spec.rb +40 -0
  53. data/spec/unit/say_spec.rb +67 -0
  54. data/spec/unit/select_spec.rb +624 -0
  55. data/spec/unit/slider_spec.rb +100 -0
  56. data/spec/unit/statement/initialize_spec.rb +15 -0
  57. data/spec/unit/subscribe_spec.rb +20 -0
  58. data/spec/unit/suggest_spec.rb +28 -0
  59. data/spec/unit/warn_spec.rb +21 -0
  60. data/spec/unit/yes_no_spec.rb +235 -0
  61. data/tty-prompt.gemspec +4 -6
  62. metadata +120 -15
  63. data/.gitignore +0 -16
  64. data/.rspec +0 -3
  65. data/.travis.yml +0 -27
  66. data/CHANGELOG.md +0 -289
  67. data/CODE_OF_CONDUCT.md +0 -49
  68. data/Gemfile +0 -21
  69. data/appveyor.yml +0 -22
  70. data/benchmarks/speed.rb +0 -27
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question, '#initialize' do
4
+
5
+ subject(:question) { described_class.new(TTY::TestPrompt.new)}
6
+
7
+ it { expect(question.echo).to eq(true) }
8
+
9
+ it { expect(question.modifier).to eq([]) }
10
+
11
+ it { expect(question.validation).to eq(TTY::Prompt::Question::UndefinedSetting) }
12
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question::Modifier, '#apply_to' do
4
+ let(:string) { "text to be modified"}
5
+
6
+ it "doesn't apply modifiers" do
7
+ modifier = described_class.new([])
8
+ expect(modifier.apply_to(string)).to eq(string)
9
+ end
10
+
11
+ it 'combines whitespace & letter case modifications' do
12
+ modifiers = [:collapse, :capitalize]
13
+ modifier = described_class.new(modifiers)
14
+ modified = modifier.apply_to(string)
15
+ expect(modified).to eq('Text to be modified')
16
+ end
17
+
18
+ it 'combines letter case & whitespace modifications' do
19
+ modifiers = [:up, :collapse]
20
+ modifier = described_class.new(modifiers)
21
+ modified = modifier.apply_to(string)
22
+ expect(modified).to eq('TEXT TO BE MODIFIED')
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question::Modifier, '#letter_case' do
4
+ context "string" do
5
+ let(:string) { 'text to modify' }
6
+
7
+ it "changes to uppercase" do
8
+ modified = described_class.letter_case(:up, string)
9
+ expect(modified).to eq('TEXT TO MODIFY')
10
+ end
11
+
12
+ it "changes to lower case" do
13
+ modified = described_class.letter_case(:down, string)
14
+ expect(modified).to eq('text to modify')
15
+ end
16
+
17
+ it "capitalizes text" do
18
+ modified = described_class.letter_case(:capitalize, string)
19
+ expect(modified).to eq('Text to modify')
20
+ end
21
+ end
22
+
23
+ context "nil (empty user input)" do
24
+ let(:string) { nil }
25
+
26
+ example "up returns nil" do
27
+ modified = described_class.letter_case(:up, string)
28
+ expect(modified).to be_nil
29
+ end
30
+
31
+ example "down returns nil" do
32
+ modified = described_class.letter_case(:down, string)
33
+ expect(modified).to be_nil
34
+ end
35
+
36
+ example "capitalize returns nil" do
37
+ modified = described_class.letter_case(:capitalize, string)
38
+ expect(modified).to be_nil
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question::Modifier, '#whitespace' do
4
+ context "string with whitespaces" do
5
+ let(:string) { " text\t \n to\t modify\r\n" }
6
+
7
+ it "trims whitespace" do
8
+ modified = described_class.whitespace(:trim, string)
9
+ expect(modified).to eq("text\t \n to\t modify")
10
+ end
11
+
12
+ it "chomps whitespace" do
13
+ modified = described_class.whitespace(:chomp, string)
14
+ expect(modified).to eq(" text\t \n to\t modify")
15
+ end
16
+
17
+ it "collapses text" do
18
+ modified = described_class.whitespace(:collapse, string)
19
+ expect(modified).to eq(" text to modify ")
20
+ end
21
+
22
+ it "removes whitespace" do
23
+ modified = described_class.whitespace(:remove, string)
24
+ expect(modified).to eq("texttomodify")
25
+ end
26
+ end
27
+
28
+ context "nil (empty user input)" do
29
+ let(:string) { nil }
30
+
31
+ example "trim returns nil" do
32
+ modified = described_class.whitespace(:trim, string)
33
+ expect(modified).to be_nil
34
+ end
35
+
36
+ example "chomp returns nil" do
37
+ modified = described_class.whitespace(:chomp, string)
38
+ expect(modified).to be_nil
39
+ end
40
+
41
+ example "collapse returns nil" do
42
+ modified = described_class.whitespace(:collapse, string)
43
+ expect(modified).to be_nil
44
+ end
45
+
46
+ example "remove returns nil" do
47
+ modified = described_class.whitespace(:remove, string)
48
+ expect(modified).to be_nil
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question, '#modify' do
4
+
5
+ subject(:prompt) { TTY::TestPrompt.new }
6
+
7
+ it 'preserves answer for unkown modification' do
8
+ prompt.input << 'piotr'
9
+ prompt.input.rewind
10
+ answer = prompt.ask("What is your name?") { |q| q.modify(:none) }
11
+ expect(answer).to eq('piotr')
12
+ end
13
+
14
+ it 'converts to upper case' do
15
+ prompt.input << 'piotr'
16
+ prompt.input.rewind
17
+ answer = prompt.ask("What is your name?") { |q| q.modify(:upcase) }
18
+ expect(answer).to eq('PIOTR')
19
+ end
20
+
21
+ it 'trims whitespace' do
22
+ prompt.input << " Some white\t space\t \there! \n"
23
+ prompt.input.rewind
24
+ answer = prompt.ask('Enter some text: ') { |q| q.modify(:trim) }
25
+ expect(answer).to eq("Some white\t space\t \there!")
26
+ end
27
+
28
+ it 'collapses whitespace' do
29
+ prompt.input << " Some white\t space\t \there! \n"
30
+ prompt.input.rewind
31
+ answer = prompt.ask('Enter some text: ') { |q| q.modify(:collapse) }
32
+ expect(answer).to eq(' Some white space here! ')
33
+ end
34
+
35
+ it 'strips and collapses whitespace' do
36
+ prompt.input << " Some white\t space\t \there! \n"
37
+ prompt.input.rewind
38
+ answer = prompt.ask('Enter some text: ') { |q| q.modify(:strip, :collapse) }
39
+ expect(answer).to eq('Some white space here!')
40
+ end
41
+ end
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question, '#required' do
4
+
5
+ subject(:prompt) { TTY::TestPrompt.new }
6
+
7
+ it 'requires value to be present' do
8
+ prompt.input << "Piotr"
9
+ prompt.input.rewind
10
+ prompt.ask('What is your name?') { |q| q.required(true) }
11
+ expect(prompt.output.string).to eq([
12
+ "What is your name? ",
13
+ "\e[2K\e[1GWhat is your name? P",
14
+ "\e[2K\e[1GWhat is your name? Pi",
15
+ "\e[2K\e[1GWhat is your name? Pio",
16
+ "\e[2K\e[1GWhat is your name? Piot",
17
+ "\e[2K\e[1GWhat is your name? Piotr",
18
+ "\e[1A\e[2K\e[1G",
19
+ "What is your name? \e[32mPiotr\e[0m\n"
20
+ ].join)
21
+ end
22
+
23
+ it 'requires value to be present with option' do
24
+ prompt.input << " \nPiotr"
25
+ prompt.input.rewind
26
+ prompt.ask('What is your name?', required: true)
27
+ expect(prompt.output.string).to eq([
28
+ "What is your name? ",
29
+ "\e[2K\e[1GWhat is your name? ",
30
+ "\e[2K\e[1GWhat is your name? ",
31
+ "\e[2K\e[1GWhat is your name? \n",
32
+ "\e[31m>>\e[0m Value must be provided\e[1A",
33
+ "\e[2K\e[1G",
34
+ "What is your name? ",
35
+ "\e[2K\e[1GWhat is your name? P",
36
+ "\e[2K\e[1GWhat is your name? Pi",
37
+ "\e[2K\e[1GWhat is your name? Pio",
38
+ "\e[2K\e[1GWhat is your name? Piot",
39
+ "\e[2K\e[1GWhat is your name? Piotr",
40
+ "\e[2K\e[1G",
41
+ "\e[1A\e[2K\e[1G",
42
+ "What is your name? \e[32mPiotr\e[0m\n"
43
+ ].join)
44
+ end
45
+
46
+ it "doesn't require value to be present" do
47
+ prompt.input << ''
48
+ prompt.input.rewind
49
+ answer = prompt.ask('What is your name?') { |q| q.required(false) }
50
+ expect(answer).to be_nil
51
+ end
52
+
53
+ it "uses required in validation check" do
54
+ prompt.input << " \nexists\ntest\n"
55
+ prompt.input.rewind
56
+ answer = prompt.ask('File name?') do |q|
57
+ q.required(true)
58
+ q.validate { |v| !(v =~ /exists/) }
59
+ q.messages[:required?] = 'File name must not be empty!'
60
+ q.messages[:valid?] = 'File already exists!'
61
+ end
62
+ expect(answer).to eq('test')
63
+ expect(prompt.output.string).to eq([
64
+ "File name? ",
65
+ "\e[2K\e[1GFile name? ",
66
+ "\e[2K\e[1GFile name? ",
67
+ "\e[2K\e[1GFile name? \n",
68
+ "\e[31m>>\e[0m File name must not be empty!",
69
+ "\e[1A\e[2K\e[1G",
70
+ "File name? ",
71
+ "\e[2K\e[1GFile name? e",
72
+ "\e[2K\e[1GFile name? ex",
73
+ "\e[2K\e[1GFile name? exi",
74
+ "\e[2K\e[1GFile name? exis",
75
+ "\e[2K\e[1GFile name? exist",
76
+ "\e[2K\e[1GFile name? exists",
77
+ "\e[2K\e[1GFile name? exists\n",
78
+ "\e[31m>>\e[0m File already exists!",
79
+ "\e[1A\e[2K\e[1G",
80
+ "File name? ",
81
+ "\e[2K\e[1GFile name? t",
82
+ "\e[2K\e[1GFile name? te",
83
+ "\e[2K\e[1GFile name? tes",
84
+ "\e[2K\e[1GFile name? test",
85
+ "\e[2K\e[1GFile name? test\n",
86
+ "\e[2K\e[1G",
87
+ "\e[1A\e[2K\e[1G",
88
+ "File name? \e[32mtest\e[0m\n",
89
+ ].join)
90
+ expect(answer).to eq('test')
91
+ end
92
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question, '#validate' do
4
+
5
+ subject(:prompt) { TTY::TestPrompt.new }
6
+
7
+ it 'validates input with regex' do
8
+ prompt.input << 'p.m'
9
+ prompt.input.rewind
10
+
11
+ answer = prompt.ask('What is your username?') do |q|
12
+ q.validate(/^[^\.]+\.[^\.]+/)
13
+ end
14
+
15
+ expect(answer).to eq('p.m')
16
+ expect(prompt.output.string).to eq([
17
+ "What is your username? ",
18
+ "\e[2K\e[1GWhat is your username? p",
19
+ "\e[2K\e[1GWhat is your username? p.",
20
+ "\e[2K\e[1GWhat is your username? p.m",
21
+ "\e[1A\e[2K\e[1G",
22
+ "What is your username? \e[32mp.m\e[0m\n"
23
+ ].join)
24
+ end
25
+
26
+ it 'validates input with proc' do
27
+ prompt.input << 'piotr.murach'
28
+ prompt.input.rewind
29
+
30
+ answer = prompt.ask('What is your username?') do |q|
31
+ q.validate { |input| input =~ /^[^\.]+\.[^\.]+/ }
32
+ end
33
+
34
+ expect(answer).to eq('piotr.murach')
35
+ end
36
+
37
+ it 'understands custom validation like :email' do
38
+ prompt.input << 'piotr@example.com'
39
+ prompt.input.rewind
40
+
41
+ answer = prompt.ask('What is your email?') do |q|
42
+ q.validate :email
43
+ end
44
+
45
+ expect(answer).to eq('piotr@example.com')
46
+ end
47
+
48
+ it "provides default error message for wrong input" do
49
+ prompt.input << "wrong\np@m.com\n"
50
+ prompt.input.rewind
51
+
52
+ answer = prompt.ask('What is your email?') do |q|
53
+ q.validate :email
54
+ end
55
+
56
+ expect(answer).to eq('p@m.com')
57
+ expect(prompt.output.string).to eq([
58
+ "What is your email? ",
59
+ "\e[2K\e[1GWhat is your email? w",
60
+ "\e[2K\e[1GWhat is your email? wr",
61
+ "\e[2K\e[1GWhat is your email? wro",
62
+ "\e[2K\e[1GWhat is your email? wron",
63
+ "\e[2K\e[1GWhat is your email? wrong",
64
+ "\e[2K\e[1GWhat is your email? wrong\n",
65
+ "\e[31m>>\e[0m Your answer is invalid (must match :email)\e[1A",
66
+ "\e[2K\e[1G",
67
+ "What is your email? ",
68
+ "\e[2K\e[1GWhat is your email? p",
69
+ "\e[2K\e[1GWhat is your email? p@",
70
+ "\e[2K\e[1GWhat is your email? p@m",
71
+ "\e[2K\e[1GWhat is your email? p@m.",
72
+ "\e[2K\e[1GWhat is your email? p@m.c",
73
+ "\e[2K\e[1GWhat is your email? p@m.co",
74
+ "\e[2K\e[1GWhat is your email? p@m.com",
75
+ "\e[2K\e[1GWhat is your email? p@m.com\n",
76
+ "\e[2K\e[1G",
77
+ "\e[1A\e[2K\e[1G",
78
+ "What is your email? \e[32mp@m.com\e[0m\n"
79
+ ].join)
80
+ end
81
+
82
+ it "provides custom error message for wrong input" do
83
+ prompt.input << "wrong\np@m.com"
84
+ prompt.input.rewind
85
+
86
+ answer = prompt.ask('What is your email?') do |q|
87
+ q.validate :email
88
+ q.messages[:valid?] = 'Not an email!'
89
+ end
90
+
91
+ expect(answer).to eq('p@m.com')
92
+ expect(prompt.output.string).to eq([
93
+ "What is your email? ",
94
+ "\e[2K\e[1GWhat is your email? w",
95
+ "\e[2K\e[1GWhat is your email? wr",
96
+ "\e[2K\e[1GWhat is your email? wro",
97
+ "\e[2K\e[1GWhat is your email? wron",
98
+ "\e[2K\e[1GWhat is your email? wrong",
99
+ "\e[2K\e[1GWhat is your email? wrong\n",
100
+ "\e[31m>>\e[0m Not an email!\e[1A",
101
+ "\e[2K\e[1G",
102
+ "What is your email? ",
103
+ "\e[2K\e[1GWhat is your email? p",
104
+ "\e[2K\e[1GWhat is your email? p@",
105
+ "\e[2K\e[1GWhat is your email? p@m",
106
+ "\e[2K\e[1GWhat is your email? p@m.",
107
+ "\e[2K\e[1GWhat is your email? p@m.c",
108
+ "\e[2K\e[1GWhat is your email? p@m.co",
109
+ "\e[2K\e[1GWhat is your email? p@m.com",
110
+ "\e[2K\e[1G",
111
+ "\e[1A\e[2K\e[1G",
112
+ "What is your email? \e[32mp@m.com\e[0m\n"
113
+ ].join)
114
+ end
115
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question::Validation, '#call' do
4
+ let(:pattern) { /^[^\.]+\.[^\.]+/ }
5
+
6
+ it "validates nil input" do
7
+ validation = described_class.new(pattern)
8
+ expect(validation.(nil)).to eq(false)
9
+ end
10
+
11
+ it "validates successfully when the value matches pattern" do
12
+ validation = described_class.new(pattern)
13
+ expect(validation.('piotr.murach')).to eq(true)
14
+ end
15
+
16
+ it "validates with a proc" do
17
+ pat = proc { |input| !pattern.match(input).nil? }
18
+ validation = described_class.new(pat)
19
+ expect(validation.call('piotr.murach')).to eq(true)
20
+ end
21
+
22
+ it "validates with custom name" do
23
+ validation = described_class.new(:email)
24
+ expect(validation.call('piotr@example.com')).to eq(true)
25
+ end
26
+
27
+ it "fails validation when not maching pattern" do
28
+ validation = described_class.new(pattern)
29
+ expect(validation.('piotrmurach')).to eq(false)
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Question::Validation, '#coerce' do
4
+ let(:instance) { described_class.new }
5
+
6
+ it "coerces lambda into proc" do
7
+ pattern = lambda { "^[^\.]+\.[^\.]+" }
8
+ validation = described_class.new(pattern)
9
+ expect(validation.pattern).to be_a(Proc)
10
+ end
11
+
12
+ it "doesn't coerce symbols" do
13
+ pattern = :email
14
+ validation =described_class.new(pattern)
15
+ expect(validation.pattern).to eq(:email)
16
+ end
17
+
18
+ it "coerces into regex" do
19
+ pattern = /^[^\.]+\.[^\.]+/
20
+ validation = described_class.new(pattern)
21
+ expect(validation.pattern).to be_a(Regexp)
22
+ end
23
+
24
+ it "fails to coerce pattern into validation" do
25
+ pattern = Object.new
26
+ expect {
27
+ described_class.new(pattern)
28
+ }.to raise_error(TTY::Prompt::ValidationCoercion)
29
+ end
30
+ end