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,67 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt::Evaluator do
4
+ it "checks chained validation procs" do
5
+ question = double(:question)
6
+ evaluator = TTY::Prompt::Evaluator.new(question)
7
+
8
+ evaluator.check { |quest, value|
9
+ if value < 21
10
+ [value, ["#{value} is not bigger than 21"]]
11
+ else
12
+ value
13
+ end
14
+ }
15
+
16
+ evaluator.check { |quest, value|
17
+ if value < 42
18
+ [value, ["#{value} is not bigger than 42"]]
19
+ else
20
+ value
21
+ end
22
+ }
23
+
24
+ answer = evaluator.call(2)
25
+ expect(answer.errors.count).to eq(2)
26
+ expect(answer.value).to eq(2)
27
+ expect(answer.success?).to eq(false)
28
+ expect(answer.failure?).to eq(true)
29
+ end
30
+
31
+ it "checks chained validation objects" do
32
+ question = double(:question)
33
+ evaluator = TTY::Prompt::Evaluator.new(question)
34
+
35
+ LessThan21 = Class.new do
36
+ def self.call(quest, value)
37
+ if value < 21
38
+ [value, ["#{value} is not bigger than 21"]]
39
+ else
40
+ value
41
+ end
42
+ end
43
+ end
44
+
45
+ LessThan42 = Class.new do
46
+ def self.call(quest, value)
47
+ if value < 42
48
+ [value, ["#{value} is not bigger than 42"]]
49
+ else
50
+ value
51
+ end
52
+ end
53
+ end
54
+
55
+ evaluator.check(LessThan21)
56
+ evaluator.check(LessThan42)
57
+
58
+ answer = evaluator.call(2)
59
+ expect(answer.errors).to match_array([
60
+ "2 is not bigger than 21",
61
+ "2 is not bigger than 42"
62
+ ])
63
+ expect(answer.value).to eq(2)
64
+ expect(answer.success?).to eq(false)
65
+ expect(answer.failure?).to eq(true)
66
+ end
67
+ end
@@ -0,0 +1,198 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt, '#expand' do
4
+
5
+ subject(:prompt) { TTY::TestPrompt.new }
6
+
7
+ let(:choices) {
8
+ [{
9
+ key: 'y',
10
+ name: 'Overwrite',
11
+ value: :yes
12
+ }, {
13
+ key: 'n',
14
+ name: 'Skip',
15
+ value: :no
16
+ }, {
17
+ key: 'a',
18
+ name: 'Overwrite all',
19
+ value: :all
20
+ }, {
21
+ key: 'd',
22
+ name: 'Show diff',
23
+ value: :diff
24
+ }, {
25
+ key: 'q',
26
+ name: 'Quit',
27
+ value: :quit
28
+ }]
29
+ }
30
+
31
+ it "expands default option" do
32
+ prompt.input << "\n"
33
+ prompt.input.rewind
34
+
35
+ result = prompt.expand('Overwrite Gemfile?', choices)
36
+ expect(result).to eq(:yes)
37
+
38
+ expect(prompt.output.string).to eq([
39
+ "Overwrite Gemfile? (enter \"h\" for help) [\e[32my\e[0m,n,a,d,q,h] ",
40
+ "\e[2K\e[1G",
41
+ "Overwrite Gemfile? \e[32mOverwrite\e[0m\n"
42
+ ].join)
43
+ end
44
+
45
+ it "changes default option" do
46
+ prompt.input << "\n"
47
+ prompt.input.rewind
48
+
49
+ result = prompt.expand('Overwrite Gemfile?', choices, default: 3)
50
+ expect(result).to eq(:all)
51
+
52
+ expect(prompt.output.string).to eq([
53
+ "Overwrite Gemfile? (enter \"h\" for help) [y,n,\e[32ma\e[0m,d,q,h] ",
54
+ "\e[2K\e[1G",
55
+ "Overwrite Gemfile? \e[32mOverwrite all\e[0m\n"
56
+ ].join)
57
+ end
58
+
59
+ it "expands chosen option with extra information" do
60
+ prompt.input << "a\n"
61
+ prompt.input.rewind
62
+
63
+ result = prompt.expand('Overwrite Gemfile?', choices)
64
+ expect(result).to eq(:all)
65
+
66
+ expect(prompt.output.string).to eq([
67
+ "Overwrite Gemfile? (enter \"h\" for help) [\e[32my\e[0m,n,a,d,q,h] ",
68
+ "\e[2K\e[1G",
69
+ "Overwrite Gemfile? (enter \"h\" for help) [y,n,\e[32ma\e[0m,d,q,h] ",
70
+ "a\n",
71
+ "\e[32m>> \e[0mOverwrite all",
72
+ "\e[A\e[1G\e[55C",
73
+ "\e[2K\e[1G",
74
+ "\e[1B",
75
+ "\e[2K\e[1G",
76
+ "\e[A\e[1G",
77
+ "Overwrite Gemfile? \e[32mOverwrite all\e[0m\n"
78
+ ].join)
79
+ end
80
+
81
+ it "expands help option and then defaults" do
82
+ prompt.input << "h\nd\n"
83
+ prompt.input.rewind
84
+
85
+ result = prompt.expand('Overwrite Gemfile?', choices)
86
+ expect(result).to eq(:diff)
87
+
88
+ expect(prompt.output.string).to eq([
89
+ "Overwrite Gemfile? (enter \"h\" for help) [\e[32my\e[0m,n,a,d,q,h] ",
90
+ "\e[2K\e[1G",
91
+ "Overwrite Gemfile? (enter \"h\" for help) [y,n,a,d,q,\e[32mh\e[0m] h\n",
92
+ "\e[32m>> \e[0mprint help",
93
+ "\e[A\e[1G\e[55C",
94
+ "\e[2K\e[1G",
95
+ "\e[1B",
96
+ "\e[2K\e[1G",
97
+ "\e[A\e[1G",
98
+ "Overwrite Gemfile? \n",
99
+ " y - Overwrite\n",
100
+ " n - Skip\n",
101
+ " a - Overwrite all\n",
102
+ " d - Show diff\n",
103
+ " q - Quit\n",
104
+ " h - print help\n",
105
+ " Choice [y]: ",
106
+ "\e[2K\e[1G\e[1A" * 7,
107
+ "\e[2K\e[1G",
108
+ "Overwrite Gemfile? \n",
109
+ " y - Overwrite\n",
110
+ " n - Skip\n",
111
+ " a - Overwrite all\n",
112
+ " \e[32md - Show diff\e[0m\n",
113
+ " q - Quit\n",
114
+ " h - print help\n",
115
+ " Choice [y]: d",
116
+ "\e[2K\e[1G\e[1A" * 7,
117
+ "\e[2K\e[1G",
118
+ "Overwrite Gemfile? \e[32mShow diff\e[0m\n",
119
+ ].join)
120
+ end
121
+
122
+ it "specifies options through DSL" do
123
+ prompt.input << "\n"
124
+ prompt.input.rewind
125
+
126
+ result = prompt.expand('Overwrite Gemfile?') do |q|
127
+ q.default 4
128
+
129
+ q.choice key: 'y', name: 'Overwrite', value: :yes
130
+ q.choice key: 'n', name: 'Skip', value: :no
131
+ q.choice key: 'a', name: 'Overwrite all', value: :all
132
+ q.choice key: 'd', name: 'Show diff', value: :diff
133
+ q.choice key: 'q', name: 'Quit', value: :quit
134
+ end
135
+
136
+ expect(result).to eq(:diff)
137
+
138
+ expect(prompt.output.string).to eq([
139
+ "Overwrite Gemfile? (enter \"h\" for help) [y,n,a,\e[32md\e[0m,q,h] ",
140
+ "\e[2K\e[1G",
141
+ "Overwrite Gemfile? \e[32mShow diff\e[0m\n"
142
+ ].join)
143
+ end
144
+
145
+ it "specifies options through DSL and executes value" do
146
+ prompt.input << "\n"
147
+ prompt.input.rewind
148
+
149
+ result = prompt.expand('Overwrite Gemfile?') do |q|
150
+ q.choice key: 'y', name: 'Overwrite' do :ok end
151
+ q.choice key: 'n', name: 'Skip', value: :no
152
+ q.choice key: 'a', name: 'Overwrite all', value: :all
153
+ q.choice key: 'd', name: 'Show diff', value: :diff
154
+ q.choice key: 'q', name: 'Quit', value: :quit
155
+ end
156
+
157
+ expect(result).to eq(:ok)
158
+
159
+ expect(prompt.output.string).to eq([
160
+ "Overwrite Gemfile? (enter \"h\" for help) [\e[32my\e[0m,n,a,d,q,h] ",
161
+ "\e[2K\e[1G",
162
+ "Overwrite Gemfile? \e[32mOverwrite\e[0m\n"
163
+ ].join)
164
+ end
165
+
166
+ it "fails to expand due to lack of key attribute" do
167
+ choices = [{ name: 'Overwrite', value: :yes }]
168
+
169
+ expect {
170
+ prompt.expand('Overwrite Gemfile?', choices)
171
+ }.to raise_error(TTY::Prompt::ConfigurationError, /Choice Overwrite is missing a :key attribute/)
172
+ end
173
+
174
+ it "fails to expand due to wrong key length" do
175
+ choices = [{ key: 'long', name: 'Overwrite', value: :yes }]
176
+
177
+ expect {
178
+ prompt.expand('Overwrite Gemfile?', choices)
179
+ }.to raise_error(TTY::Prompt::ConfigurationError, /Choice key `long` is more than one character long/)
180
+ end
181
+
182
+ it "fails to expand due to reserve key" do
183
+ choices = [{ key: 'h', name: 'Overwrite', value: :yes }]
184
+
185
+ expect {
186
+ prompt.expand('Overwrite Gemfile?', choices)
187
+ }.to raise_error(TTY::Prompt::ConfigurationError, /Choice key `h` is reserved for help menu/)
188
+ end
189
+
190
+ it "fails to expand due to duplicate key" do
191
+ choices = [{ key: 'y', name: 'Overwrite', value: :yes },
192
+ { key: 'y', name: 'Change', value: :yes }]
193
+
194
+ expect {
195
+ prompt.expand('Overwrite Gemfile?', choices)
196
+ }.to raise_error(TTY::Prompt::ConfigurationError, /Choice key `y` is a duplicate/)
197
+ end
198
+ end
@@ -0,0 +1,72 @@
1
+ # encoding: utf-8
2
+
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\e[1A\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
20
+ prompt = TTY::TestPrompt.new
21
+ prompt.input << "abcd"
22
+ prompt.input.rewind
23
+
24
+ answer = prompt.keypress("Press key:", echo: true)
25
+
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)
32
+ end
33
+
34
+ it 'asks for a keypress with echo off' do
35
+ prompt = TTY::TestPrompt.new
36
+ prompt.input << "abcd"
37
+ prompt.input.rewind
38
+
39
+ answer = prompt.keypress("Press key:")
40
+
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)
47
+ end
48
+
49
+ it "interrupts input" do
50
+ prompt = TTY::TestPrompt.new(interrupt: :exit)
51
+ prompt.input << "\x03"
52
+ prompt.input.rewind
53
+
54
+ expect {
55
+ prompt.keypress("Press key:")
56
+ }.to raise_error(SystemExit)
57
+ end
58
+
59
+ it "timeouts when no key provided" do
60
+ prompt = TTY::TestPrompt.new(interrupt: :exit)
61
+
62
+ prompt.keypress("Press any key or continue in :countdown", timeout: 0.1)
63
+
64
+ expect(prompt.output.string).to eq([
65
+ "Press any key or continue in 0.1 ",
66
+ "\e[2K\e[1G",
67
+ "Press any key or continue in 0 ",
68
+ "\e[2K\e[1G",
69
+ "Press any key or continue in 0 \n"
70
+ ].join)
71
+ end
72
+ end
@@ -0,0 +1,132 @@
1
+ # encoding: utf-8
2
+
3
+ RSpec.describe TTY::Prompt, '#mask' do
4
+
5
+ subject(:prompt) { TTY::TestPrompt.new }
6
+
7
+ let(:symbols) { TTY::Prompt::Symbols.symbols }
8
+
9
+ it "masks output by default" do
10
+ prompt.input << "pass\r"
11
+ prompt.input.rewind
12
+ answer = prompt.mask("What is your password?")
13
+ expect(answer).to eql("pass")
14
+ expect(prompt.output.string).to eq([
15
+ "What is your password? ",
16
+ "\e[2K\e[1G",
17
+ "What is your password? #{symbols[:dot]}",
18
+ "\e[2K\e[1G",
19
+ "What is your password? #{symbols[:dot] * 2}",
20
+ "\e[2K\e[1G",
21
+ "What is your password? #{symbols[:dot] * 3}",
22
+ "\e[2K\e[1G",
23
+ "What is your password? #{symbols[:dot] * 4}",
24
+ "\e[2K\e[1G",
25
+ "What is your password? \e[32m#{symbols[:dot] * 4}\e[0m\n",
26
+ "\e[1A\e[2K\e[1G",
27
+ "What is your password? \e[32m#{symbols[:dot] * 4}\e[0m\n"
28
+ ].join)
29
+ end
30
+
31
+ it 'masks output with custom character' do
32
+ prompt.input << "pass\r"
33
+ prompt.input.rewind
34
+ answer = prompt.mask("What is your password?") { |q| q.mask('*') }
35
+ expect(answer).to eql("pass")
36
+ expect(prompt.output.string).to eq([
37
+ "What is your password? ",
38
+ "\e[2K\e[1G",
39
+ "What is your password? *",
40
+ "\e[2K\e[1G",
41
+ "What is your password? **",
42
+ "\e[2K\e[1G",
43
+ "What is your password? ***",
44
+ "\e[2K\e[1G",
45
+ "What is your password? ****",
46
+ "\e[2K\e[1G",
47
+ "What is your password? \e[32m****\e[0m\n",
48
+ "\e[1A\e[2K\e[1G",
49
+ "What is your password? \e[32m****\e[0m\n",
50
+ ].join)
51
+ end
52
+
53
+ it "masks with unicode character" do
54
+ prompt.input << "lov\n"
55
+ prompt.input.rewind
56
+ answer = prompt.mask("What is your password?", mask: "\u2665")
57
+ expect(answer).to eql("lov")
58
+ expect(prompt.output.string).to eq([
59
+ "What is your password? ",
60
+ "\e[2K\e[1G",
61
+ "What is your password? ♥",
62
+ "\e[2K\e[1G",
63
+ "What is your password? ♥♥",
64
+ "\e[2K\e[1G",
65
+ "What is your password? ♥♥♥",
66
+ "\e[2K\e[1G",
67
+ "What is your password? \e[32m♥♥♥\e[0m\n",
68
+ "\e[1A\e[2K\e[1G",
69
+ "What is your password? \e[32m♥♥♥\e[0m\n",
70
+ ].join)
71
+ end
72
+
73
+ it 'ignores mask if echo is off' do
74
+ prompt.input << "pass\n"
75
+ prompt.input.rewind
76
+ answer = prompt.mask('What is your password?') do |q|
77
+ q.echo false
78
+ q.mask '*'
79
+ end
80
+ expect(answer).to eql("pass")
81
+ expect(prompt.output.string).to eq([
82
+ "What is your password? ",
83
+ "\e[2K\e[1G",
84
+ "What is your password? ",
85
+ "\e[2K\e[1G",
86
+ "What is your password? ",
87
+ "\e[2K\e[1G",
88
+ "What is your password? ",
89
+ "\e[2K\e[1G",
90
+ "What is your password? ",
91
+ "\e[2K\e[1G",
92
+ "What is your password? \n",
93
+ "\e[1A\e[2K\e[1G",
94
+ "What is your password? \n",
95
+ ].join)
96
+ end
97
+
98
+ it "validates input" do
99
+ prompt.input << "no\nyes\n"
100
+ prompt.input.rewind
101
+ answer = prompt.mask('What is your password?') do |q|
102
+ q.echo true
103
+ q.mask '*'
104
+ q.validate(/[a-z]{3,4}/)
105
+ q.messages[:valid?] = 'Not valid'
106
+ end
107
+ expect(answer).to eq('yes')
108
+ expect(prompt.output.string).to eq([
109
+ "What is your password? ",
110
+ "\e[2K\e[1G",
111
+ "What is your password? *",
112
+ "\e[2K\e[1G",
113
+ "What is your password? **",
114
+ "\e[2K\e[1G",
115
+ "What is your password? \e[32m**\e[0m\n",
116
+ "\e[31m>>\e[0m Not valid",
117
+ "\e[1A\e[2K\e[1G",
118
+ "What is your password? \e[31m**\e[0m",
119
+ "\e[2K\e[1G",
120
+ "What is your password? *",
121
+ "\e[2K\e[1G",
122
+ "What is your password? **",
123
+ "\e[2K\e[1G",
124
+ "What is your password? ***",
125
+ "\e[2K\e[1G",
126
+ "What is your password? \e[32m***\e[0m\n",
127
+ "\e[2K\e[1G",
128
+ "\e[1A\e[2K\e[1G",
129
+ "What is your password? \e[32m***\e[0m\n"
130
+ ].join)
131
+ end
132
+ end