tty-prompt 0.11.0 → 0.12.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/README.md +66 -7
  4. data/examples/key_events.rb +11 -0
  5. data/examples/keypress.rb +3 -5
  6. data/examples/multiline.rb +9 -0
  7. data/examples/pause.rb +7 -0
  8. data/lib/tty/prompt.rb +82 -44
  9. data/lib/tty/prompt/confirm_question.rb +20 -36
  10. data/lib/tty/prompt/enum_list.rb +32 -23
  11. data/lib/tty/prompt/expander.rb +35 -31
  12. data/lib/tty/prompt/keypress.rb +91 -0
  13. data/lib/tty/prompt/list.rb +38 -23
  14. data/lib/tty/prompt/mask_question.rb +4 -7
  15. data/lib/tty/prompt/multi_list.rb +3 -1
  16. data/lib/tty/prompt/multiline.rb +71 -0
  17. data/lib/tty/prompt/question.rb +33 -35
  18. data/lib/tty/prompt/reader.rb +154 -38
  19. data/lib/tty/prompt/reader/codes.rb +4 -4
  20. data/lib/tty/prompt/reader/console.rb +1 -1
  21. data/lib/tty/prompt/reader/history.rb +145 -0
  22. data/lib/tty/prompt/reader/key_event.rb +4 -0
  23. data/lib/tty/prompt/reader/line.rb +162 -0
  24. data/lib/tty/prompt/reader/mode.rb +2 -2
  25. data/lib/tty/prompt/reader/win_console.rb +5 -1
  26. data/lib/tty/prompt/slider.rb +18 -12
  27. data/lib/tty/prompt/timeout.rb +48 -0
  28. data/lib/tty/prompt/version.rb +1 -1
  29. data/spec/unit/ask_spec.rb +15 -0
  30. data/spec/unit/converters/convert_bool_spec.rb +1 -0
  31. data/spec/unit/keypress_spec.rb +35 -6
  32. data/spec/unit/multi_select_spec.rb +18 -0
  33. data/spec/unit/multiline_spec.rb +67 -9
  34. data/spec/unit/question/default_spec.rb +1 -0
  35. data/spec/unit/question/echo_spec.rb +8 -0
  36. data/spec/unit/question/in_spec.rb +13 -0
  37. data/spec/unit/question/required_spec.rb +31 -2
  38. data/spec/unit/question/validate_spec.rb +39 -9
  39. data/spec/unit/reader/history_spec.rb +172 -0
  40. data/spec/unit/reader/key_event_spec.rb +12 -8
  41. data/spec/unit/reader/line_spec.rb +110 -0
  42. data/spec/unit/reader/publish_keypress_event_spec.rb +11 -0
  43. data/spec/unit/reader/read_line_spec.rb +32 -2
  44. data/spec/unit/reader/read_multiline_spec.rb +21 -7
  45. data/spec/unit/select_spec.rb +40 -1
  46. data/spec/unit/yes_no_spec.rb +48 -4
  47. metadata +14 -3
  48. data/lib/tty/prompt/history.rb +0 -16
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ module TTY
4
+ class Prompt
5
+ class Timeout
6
+ Error = Class.new(RuntimeError)
7
+
8
+ TIMEOUT_HANDLER = proc { |t| t.raise Error, 'timeout expired' }
9
+
10
+ def initialize(options = {})
11
+ @timeout_handler = options.fetch(:timeout_handler) { TIMEOUT_HANDLER }
12
+ @interval_handler = options.fetch(:interval_handler) { proc { } }
13
+ @lock = Mutex.new
14
+ end
15
+
16
+ def self.timeout(secs, interval, &block)
17
+ (@scheduler ||= new).timeout(secs, interval, &block)
18
+ end
19
+
20
+ def timeout(secs, interval, &block)
21
+ return block.() if secs.nil? || secs.to_i.zero?
22
+ @lock.synchronize do
23
+ @runner = Thread.new {
24
+ run_in(secs, interval)
25
+ }
26
+ end
27
+ block.()
28
+ end
29
+
30
+ def run_in(secs, interval)
31
+ Thread.current.abort_on_exception = true
32
+ start = Time.now
33
+
34
+ loop do
35
+ sleep(interval)
36
+ runtime = Time.now - start
37
+ delta = secs - runtime
38
+ @interval_handler.(delta.round)
39
+
40
+ if delta < 0.0
41
+ @timeout_handler.(Thread.current)
42
+ break
43
+ end
44
+ end
45
+ end
46
+ end # Scheduler
47
+ end # Prompt
48
+ end # TTY
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TTY
4
4
  class Prompt
5
- VERSION = "0.11.0"
5
+ VERSION = "0.12.0"
6
6
  end # Prompt
7
7
  end # TTY
@@ -34,6 +34,7 @@ RSpec.describe TTY::Prompt, '#ask' do
34
34
  expect(answer).to eq(nil)
35
35
  expect(prompt.output.string).to eq([
36
36
  "[?] Are you Polish? ",
37
+ "\e[2K\e[1G[?] Are you Polish? \n",
37
38
  "\e[1A\e[2K\e[1G",
38
39
  "[?] Are you Polish? \n"
39
40
  ].join)
@@ -74,6 +75,7 @@ RSpec.describe TTY::Prompt, '#ask' do
74
75
  expect(answer).to eq('')
75
76
  expect(prompt.output.string).to eq([
76
77
  "What is your name? ",
78
+ "\e[2K\e[1GWhat is your name? \n",
77
79
  "\e[1A\e[2K\e[1G",
78
80
  "What is your name? \n"
79
81
  ].join)
@@ -87,6 +89,7 @@ RSpec.describe TTY::Prompt, '#ask' do
87
89
  expect(answer).to eq(nil)
88
90
  expect(prompt.output.string).to eq([
89
91
  "What is your name? ",
92
+ "\e[2K\e[1GWhat is your name? \n",
90
93
  "\e[1A\e[2K\e[1G",
91
94
  "What is your name? \n"
92
95
  ].join)
@@ -107,9 +110,21 @@ RSpec.describe TTY::Prompt, '#ask' do
107
110
 
108
111
  expect(prompt.output.string).to eq([
109
112
  "[?] What is your name? ",
113
+ "\e[2K\e[1G[?] What is your name? P",
114
+ "\e[2K\e[1G[?] What is your name? Pi",
115
+ "\e[2K\e[1G[?] What is your name? Pio",
116
+ "\e[2K\e[1G[?] What is your name? Piot",
117
+ "\e[2K\e[1G[?] What is your name? Piotr",
118
+ "\e[2K\e[1G[?] What is your name? Piotr\n",
110
119
  "\e[1A\e[2K\e[1G",
111
120
  "[?] What is your name? \e[36mPiotr\e[0m\n",
112
121
  ":-) What is your name? ",
122
+ "\e[2K\e[1G:-) What is your name? P",
123
+ "\e[2K\e[1G:-) What is your name? Pi",
124
+ "\e[2K\e[1G:-) What is your name? Pio",
125
+ "\e[2K\e[1G:-) What is your name? Piot",
126
+ "\e[2K\e[1G:-) What is your name? Piotr",
127
+ "\e[2K\e[1G:-) What is your name? Piotr\n",
113
128
  "\e[1A\e[2K\e[1G",
114
129
  ":-) What is your name? \e[34mPiotr\e[0m\n"
115
130
  ].join)
@@ -19,6 +19,7 @@ RSpec.describe TTY::Prompt::Question, 'convert bool' do
19
19
  expect(response).to eql(true)
20
20
  expect(prompt.output.string).to eq([
21
21
  "Do you read books? \e[90m(true)\e[0m ",
22
+ "\e[2K\e[1GDo you read books? \e[90m(true)\e[0m \n",
22
23
  "\e[1A\e[2K\e[1G",
23
24
  "Do you read books? \e[32mtrue\e[0m\n"
24
25
  ].join)
@@ -1,20 +1,49 @@
1
1
  # encoding: utf-8
2
2
 
3
- RSpec.describe TTY::Prompt::Question, 'ask keypress' do
4
- it 'asks for a keypress with :read option' do
3
+ RSpec.describe TTY::Prompt::Question, '#keypress' do
4
+ it 'receives line feed with echo on' do
5
+ prompt = TTY::TestPrompt.new
6
+ prompt.input << "\n"
7
+ prompt.input.rewind
8
+
9
+ answer = prompt.keypress("Press key:", echo: true)
10
+
11
+ expect(answer).to eq("\n")
12
+ expect(prompt.output.string).to eq([
13
+ "Press key: ",
14
+ "\e[2K\e[1G",
15
+ "Press key: \e[32m\n\e[0m\n",
16
+ ].join)
17
+ end
18
+
19
+ it 'asks for a keypress with echo on' do
5
20
  prompt = TTY::TestPrompt.new
6
21
  prompt.input << "abcd"
7
22
  prompt.input.rewind
8
- answer = prompt.ask("Which one do you prefer a, b, c or d?", read: :keypress)
23
+
24
+ answer = prompt.keypress("Press key:", echo: true)
25
+
9
26
  expect(answer).to eq("a")
27
+ expect(prompt.output.string).to eq([
28
+ "Press key: ",
29
+ "\e[2K\e[1G",
30
+ "Press key: \e[32ma\e[0m\n",
31
+ ].join)
10
32
  end
11
33
 
12
- it 'asks for a keypress with method' do
34
+ it 'asks for a keypress with echo off' do
13
35
  prompt = TTY::TestPrompt.new
14
36
  prompt.input << "abcd"
15
37
  prompt.input.rewind
16
- answer = prompt.keypress("Which one do you prefer a, b, c or d?")
38
+
39
+ answer = prompt.keypress("Press key:")
40
+
17
41
  expect(answer).to eq("a")
42
+ expect(prompt.output.string).to eq([
43
+ "Press key: ",
44
+ "\e[2K\e[1G",
45
+ "Press key: \n",
46
+ ].join)
18
47
  end
19
48
 
20
49
  it "interrupts input" do
@@ -23,7 +52,7 @@ RSpec.describe TTY::Prompt::Question, 'ask keypress' do
23
52
  prompt.input.rewind
24
53
 
25
54
  expect {
26
- prompt.keypress("Which one do you prefer a, b, c or d?")
55
+ prompt.keypress("Press key:")
27
56
  }.to raise_error(SystemExit)
28
57
  end
29
58
  end
@@ -257,6 +257,24 @@ RSpec.describe TTY::Prompt do
257
257
  ].join)
258
258
  end
259
259
 
260
+ it "paginates choices as hash object" do
261
+ prompt = TTY::TestPrompt.new
262
+ choices = {A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7, H: 8}
263
+ prompt.input << "\r"
264
+ prompt.input.rewind
265
+ value = prompt.multi_select("What letter?", choices, default: 4, per_page: 3)
266
+ expect(value).to eq([4])
267
+ expect(prompt.output.string).to eq([
268
+ "\e[?25lWhat letter? D \e[90m(Use arrow keys, press Space to select and Enter to finish)\e[0m\n",
269
+ "#{symbols[:pointer]} \e[32m#{symbols[:radio_on]}\e[0m D\n",
270
+ " #{symbols[:radio_off]} E\n",
271
+ " #{symbols[:radio_off]} F\n",
272
+ "\e[90m(Move up or down to reveal more choices)\e[0m",
273
+ "\e[2K\e[1G\e[1A" * 4, "\e[2K\e[1G",
274
+ "What letter? \e[32mD\e[0m\n\e[?25h",
275
+ ].join)
276
+ end
277
+
260
278
  it "paginates long selections through DSL" do
261
279
  prompt = TTY::TestPrompt.new
262
280
  choices = %w(A B C D E F G H)
@@ -1,19 +1,77 @@
1
1
  # encoding: utf-8
2
2
 
3
- RSpec.describe TTY::Prompt::Question, 'ask multiline' do
4
- it 'reads multiple lines with :read option' do
3
+ RSpec.describe TTY::Prompt::Question, '#multiline' do
4
+ it 'reads no lines' do
5
5
  prompt = TTY::TestPrompt.new
6
- prompt.input << "First line\nSecond line\nThird line"
6
+ prompt.input << "\C-d"
7
7
  prompt.input.rewind
8
- answer = prompt.ask("Provide description?", read: :multiline)
9
- expect(answer).to eq(['First line', 'Second line', 'Third line'])
8
+
9
+ answer = prompt.multiline("Description?")
10
+
11
+ expect(answer).to eq([])
12
+ expect(prompt.output.string).to eq([
13
+ "Description? \e[90m(Press CTRL-D or CTRL-Z to finish)\e[0m\n",
14
+ "\e[2K\e[1G\e[1A\e[2K\e[1G",
15
+ "Description? \n"
16
+ ].join)
17
+ end
18
+
19
+ it "uses defualt when no input" do
20
+ prompt = TTY::TestPrompt.new
21
+ prompt.input << "\C-d"
22
+ prompt.input.rewind
23
+
24
+ answer = prompt.multiline("Description?", default: 'A super sweet prompt')
25
+
26
+ expect(answer).to eq([])
27
+ expect(prompt.output.string).to eq([
28
+ "Description? \e[90m(Press CTRL-D or CTRL-Z to finish)\e[0m\n",
29
+ "\e[2K\e[1G\e[1A\e[2K\e[1G",
30
+ "Description? \e[32mA super sweet prompt\e[0m\n"
31
+ ].join)
10
32
  end
11
33
 
12
- it 'reads multiple lines with method' do
34
+ it "changes help text" do
13
35
  prompt = TTY::TestPrompt.new
14
- prompt.input << "First\nSecond\nThird"
36
+ prompt.input << "\C-d"
15
37
  prompt.input.rewind
16
- answer = prompt.multiline("Provide description?")
17
- expect(answer).to eq(['First', 'Second', 'Third'])
38
+
39
+ answer = prompt.multiline("Description?") do |q|
40
+ q.default 'A super sweet prompt'
41
+ q.help '(Press thy ctrl-d to end)'
42
+ end
43
+
44
+ expect(answer).to eq([])
45
+ expect(prompt.output.string).to eq([
46
+ "Description? \e[90m(Press thy ctrl-d to end)\e[0m\n",
47
+ "\e[2K\e[1G\e[1A\e[2K\e[1G",
48
+ "Description? \e[32mA super sweet prompt\e[0m\n"
49
+ ].join)
50
+ end
51
+
52
+ it 'reads multiple lines with empty lines' do
53
+ prompt = TTY::TestPrompt.new
54
+ prompt.input << "aa\n\nbb\n\n\ncc\C-d"
55
+ prompt.input.rewind
56
+
57
+ answer = prompt.multiline("Description?")
58
+ expect(answer).to eq(["aa\n", "bb\n", "cc"])
59
+ expect(prompt.output.string).to eq([
60
+ "Description? \e[90m(Press CTRL-D or CTRL-Z to finish)\e[0m\n",
61
+ "\e[2K\e[1Ga",
62
+ "\e[2K\e[1Gaa",
63
+ "\e[2K\e[1Gaa\n",
64
+ "\e[2K\e[1G\n",
65
+ "\e[2K\e[1Gb",
66
+ "\e[2K\e[1Gbb",
67
+ "\e[2K\e[1Gbb\n",
68
+ "\e[2K\e[1G\n",
69
+ "\e[2K\e[1G\n",
70
+ "\e[2K\e[1Gc",
71
+ "\e[2K\e[1Gcc",
72
+ "\e[2K\e[1G\e[1A" * 6,
73
+ "\e[2K\e[1G",
74
+ "Description? \e[32maa ...\e[0m\n"
75
+ ].join)
18
76
  end
19
77
  end
@@ -12,6 +12,7 @@ RSpec.describe TTY::Prompt::Question, '#default' do
12
12
  expect(answer).to eq(name)
13
13
  expect(prompt.output.string).to eq([
14
14
  "What is your name? \e[90m(Anonymous)\e[0m ",
15
+ "\e[2K\e[1GWhat is your name? \e[90m(Anonymous)\e[0m \n",
15
16
  "\e[1A\e[2K\e[1G",
16
17
  "What is your name? \e[32mAnonymous\e[0m\n"
17
18
  ].join)
@@ -11,6 +11,14 @@ RSpec.describe TTY::Prompt::Question, '#echo' do
11
11
  expect(answer).to eql("password")
12
12
  expect(prompt.output.string).to eq([
13
13
  "What is your password? ",
14
+ "\e[2K\e[1GWhat is your password? p",
15
+ "\e[2K\e[1GWhat is your password? pa",
16
+ "\e[2K\e[1GWhat is your password? pas",
17
+ "\e[2K\e[1GWhat is your password? pass",
18
+ "\e[2K\e[1GWhat is your password? passw",
19
+ "\e[2K\e[1GWhat is your password? passwo",
20
+ "\e[2K\e[1GWhat is your password? passwor",
21
+ "\e[2K\e[1GWhat is your password? password",
14
22
  "\e[1A\e[2K\e[1G",
15
23
  "What is your password? \e[32mpassword\e[0m\n"
16
24
  ].join)
@@ -24,6 +24,7 @@ RSpec.describe TTY::Prompt::Question, '#in' do
24
24
  expect(answer).to eq('8')
25
25
  expect(prompt.output.string).to eq([
26
26
  "How do you like it on scale 1-10? ",
27
+ "\e[2K\e[1GHow do you like it on scale 1-10? 8",
27
28
  "\e[1A\e[2K\e[1G",
28
29
  "How do you like it on scale 1-10? \e[32m8\e[0m\n",
29
30
  ].join)
@@ -40,6 +41,9 @@ RSpec.describe TTY::Prompt::Question, '#in' do
40
41
  expect(answer).to eq('8.1')
41
42
  expect(prompt.output.string).to eq([
42
43
  "How do you like it on scale 1-10? ",
44
+ "\e[2K\e[1GHow do you like it on scale 1-10? 8",
45
+ "\e[2K\e[1GHow do you like it on scale 1-10? 8.",
46
+ "\e[2K\e[1GHow do you like it on scale 1-10? 8.1",
43
47
  "\e[1A\e[2K\e[1G",
44
48
  "How do you like it on scale 1-10? \e[32m8.1\e[0m\n",
45
49
  ].join)
@@ -56,6 +60,7 @@ RSpec.describe TTY::Prompt::Question, '#in' do
56
60
  expect(answer).to eq('E')
57
61
  expect(prompt.output.string).to eq([
58
62
  "Your favourite vitamin? (A-K) ",
63
+ "\e[2K\e[1GYour favourite vitamin? (A-K) E",
59
64
  "\e[1A\e[2K\e[1G",
60
65
  "Your favourite vitamin? (A-K) \e[32mE\e[0m\n"
61
66
  ].join)
@@ -70,9 +75,13 @@ RSpec.describe TTY::Prompt::Question, '#in' do
70
75
  expect(answer).to eq('2')
71
76
  expect(prompt.output.string).to eq([
72
77
  "How spicy on scale? (1-5) ",
78
+ "\e[2K\e[1GHow spicy on scale? (1-5) A",
79
+ "\e[2K\e[1GHow spicy on scale? (1-5) A\n",
73
80
  "\e[31m>>\e[0m Value A must be within the range 1..5\e[1A",
74
81
  "\e[2K\e[1G",
75
82
  "How spicy on scale? (1-5) ",
83
+ "\e[2K\e[1GHow spicy on scale? (1-5) 2",
84
+ "\e[2K\e[1GHow spicy on scale? (1-5) 2\n",
76
85
  "\e[2K\e[1G",
77
86
  "\e[1A\e[2K\e[1G",
78
87
  "How spicy on scale? (1-5) \e[32m2\e[0m\n"
@@ -91,9 +100,13 @@ RSpec.describe TTY::Prompt::Question, '#in' do
91
100
  expect(answer).to eq('2')
92
101
  expect(prompt.output.string).to eq([
93
102
  "How spicy on scale? (1-5) ",
103
+ "\e[2K\e[1GHow spicy on scale? (1-5) A",
104
+ "\e[2K\e[1GHow spicy on scale? (1-5) A\n",
94
105
  "\e[31m>>\e[0m Ohh dear what is this A doing in 1..5?\e[1A",
95
106
  "\e[2K\e[1G",
96
107
  "How spicy on scale? (1-5) ",
108
+ "\e[2K\e[1GHow spicy on scale? (1-5) 2",
109
+ "\e[2K\e[1GHow spicy on scale? (1-5) 2\n",
97
110
  "\e[2K\e[1G",
98
111
  "\e[1A\e[2K\e[1G",
99
112
  "How spicy on scale? (1-5) \e[32m2\e[0m\n"
@@ -10,6 +10,11 @@ RSpec.describe TTY::Prompt::Question, '#required' do
10
10
  prompt.ask('What is your name?') { |q| q.required(true) }
11
11
  expect(prompt.output.string).to eq([
12
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",
13
18
  "\e[1A\e[2K\e[1G",
14
19
  "What is your name? \e[32mPiotr\e[0m\n"
15
20
  ].join)
@@ -21,9 +26,17 @@ RSpec.describe TTY::Prompt::Question, '#required' do
21
26
  prompt.ask('What is your name?', required: true)
22
27
  expect(prompt.output.string).to eq([
23
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",
24
32
  "\e[31m>>\e[0m Value must be provided\e[1A",
25
33
  "\e[2K\e[1G",
26
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",
27
40
  "\e[2K\e[1G",
28
41
  "\e[1A\e[2K\e[1G",
29
42
  "What is your name? \e[32mPiotr\e[0m\n"
@@ -38,22 +51,38 @@ RSpec.describe TTY::Prompt::Question, '#required' do
38
51
  end
39
52
 
40
53
  it "uses required in validation check" do
41
- prompt.input << " \n#{__FILE__}\ntest\n"
54
+ prompt.input << " \nexists\ntest\n"
42
55
  prompt.input.rewind
43
56
  answer = prompt.ask('File name?') do |q|
44
57
  q.required(true)
45
- q.validate { |v| !::File.exist?(v) }
58
+ q.validate { |v| !(v =~ /exists/) }
46
59
  q.messages[:required?] = 'File name must not be empty!'
47
60
  q.messages[:valid?] = 'File already exists!'
48
61
  end
62
+ expect(answer).to eq('test')
49
63
  expect(prompt.output.string).to eq([
50
64
  "File name? ",
65
+ "\e[2K\e[1GFile name? ",
66
+ "\e[2K\e[1GFile name? ",
67
+ "\e[2K\e[1GFile name? \n",
51
68
  "\e[31m>>\e[0m File name must not be empty!",
52
69
  "\e[1A\e[2K\e[1G",
53
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",
54
78
  "\e[31m>>\e[0m File already exists!",
55
79
  "\e[1A\e[2K\e[1G",
56
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",
57
86
  "\e[2K\e[1G",
58
87
  "\e[1A\e[2K\e[1G",
59
88
  "File name? \e[32mtest\e[0m\n",
@@ -5,18 +5,21 @@ RSpec.describe TTY::Prompt::Question, '#validate' do
5
5
  subject(:prompt) { TTY::TestPrompt.new }
6
6
 
7
7
  it 'validates input with regex' do
8
- prompt.input << 'piotr.murach'
8
+ prompt.input << 'p.m'
9
9
  prompt.input.rewind
10
10
 
11
11
  answer = prompt.ask('What is your username?') do |q|
12
12
  q.validate(/^[^\.]+\.[^\.]+/)
13
13
  end
14
14
 
15
- expect(answer).to eq('piotr.murach')
15
+ expect(answer).to eq('p.m')
16
16
  expect(prompt.output.string).to eq([
17
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",
18
21
  "\e[1A\e[2K\e[1G",
19
- "What is your username? \e[32mpiotr.murach\e[0m\n"
22
+ "What is your username? \e[32mp.m\e[0m\n"
20
23
  ].join)
21
24
  end
22
25
 
@@ -43,27 +46,41 @@ RSpec.describe TTY::Prompt::Question, '#validate' do
43
46
  end
44
47
 
45
48
  it "provides default error message for wrong input" do
46
- prompt.input << "invalid\npiotr@example.com"
49
+ prompt.input << "wrong\np@m.com\n"
47
50
  prompt.input.rewind
48
51
 
49
52
  answer = prompt.ask('What is your email?') do |q|
50
53
  q.validate :email
51
54
  end
52
55
 
53
- expect(answer).to eq('piotr@example.com')
56
+ expect(answer).to eq('p@m.com')
54
57
  expect(prompt.output.string).to eq([
55
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",
56
65
  "\e[31m>>\e[0m Your answer is invalid (must match :email)\e[1A",
57
66
  "\e[2K\e[1G",
58
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",
59
76
  "\e[2K\e[1G",
60
77
  "\e[1A\e[2K\e[1G",
61
- "What is your email? \e[32mpiotr@example.com\e[0m\n"
78
+ "What is your email? \e[32mp@m.com\e[0m\n"
62
79
  ].join)
63
80
  end
64
81
 
65
82
  it "provides custom error message for wrong input" do
66
- prompt.input << "invalid\npiotr@example.com"
83
+ prompt.input << "wrong\np@m.com"
67
84
  prompt.input.rewind
68
85
 
69
86
  answer = prompt.ask('What is your email?') do |q|
@@ -71,15 +88,28 @@ RSpec.describe TTY::Prompt::Question, '#validate' do
71
88
  q.messages[:valid?] = 'Not an email!'
72
89
  end
73
90
 
74
- expect(answer).to eq('piotr@example.com')
91
+ expect(answer).to eq('p@m.com')
75
92
  expect(prompt.output.string).to eq([
76
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",
77
100
  "\e[31m>>\e[0m Not an email!\e[1A",
78
101
  "\e[2K\e[1G",
79
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",
80
110
  "\e[2K\e[1G",
81
111
  "\e[1A\e[2K\e[1G",
82
- "What is your email? \e[32mpiotr@example.com\e[0m\n"
112
+ "What is your email? \e[32mp@m.com\e[0m\n"
83
113
  ].join)
84
114
  end
85
115
  end