command_kit 0.1.0.pre1 → 0.2.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 +4 -4
- data/.github/workflows/ruby.yml +15 -0
- data/.rubocop.yml +138 -0
- data/ChangeLog.md +34 -2
- data/Gemfile +3 -0
- data/README.md +135 -214
- data/Rakefile +3 -2
- data/command_kit.gemspec +4 -4
- data/examples/colors.rb +30 -0
- data/examples/command.rb +65 -0
- data/examples/pager.rb +30 -0
- data/gemspec.yml +10 -2
- data/lib/command_kit/arguments/argument.rb +16 -44
- data/lib/command_kit/arguments/argument_value.rb +3 -30
- data/lib/command_kit/arguments.rb +66 -20
- data/lib/command_kit/colors.rb +253 -45
- data/lib/command_kit/command.rb +50 -3
- data/lib/command_kit/command_name.rb +9 -0
- data/lib/command_kit/commands/auto_load/subcommand.rb +3 -0
- data/lib/command_kit/commands/auto_load.rb +16 -0
- data/lib/command_kit/commands/auto_require.rb +16 -0
- data/lib/command_kit/commands/command.rb +3 -0
- data/lib/command_kit/commands/help.rb +2 -0
- data/lib/command_kit/commands/parent_command.rb +7 -0
- data/lib/command_kit/commands/subcommand.rb +15 -0
- data/lib/command_kit/commands.rb +40 -4
- data/lib/command_kit/description.rb +15 -2
- data/lib/command_kit/env/home.rb +9 -0
- data/lib/command_kit/env/path.rb +15 -0
- data/lib/command_kit/env.rb +4 -0
- data/lib/command_kit/examples.rb +15 -2
- data/lib/command_kit/exception_handler.rb +4 -0
- data/lib/command_kit/help/man.rb +74 -47
- data/lib/command_kit/help.rb +10 -1
- data/lib/command_kit/inflector.rb +49 -17
- data/lib/command_kit/interactive.rb +239 -0
- data/lib/command_kit/main.rb +20 -9
- data/lib/command_kit/man.rb +44 -0
- data/lib/command_kit/open_app.rb +69 -0
- data/lib/command_kit/options/option.rb +36 -9
- data/lib/command_kit/options/option_value.rb +42 -3
- data/lib/command_kit/options/parser.rb +44 -17
- data/lib/command_kit/options/quiet.rb +3 -0
- data/lib/command_kit/options/verbose.rb +5 -0
- data/lib/command_kit/options/version.rb +6 -0
- data/lib/command_kit/options.rb +59 -10
- data/lib/command_kit/os/linux.rb +157 -0
- data/lib/command_kit/os.rb +165 -11
- data/lib/command_kit/package_manager.rb +200 -0
- data/lib/command_kit/pager.rb +84 -9
- data/lib/command_kit/printing/indent.rb +25 -2
- data/lib/command_kit/printing.rb +23 -0
- data/lib/command_kit/program_name.rb +7 -0
- data/lib/command_kit/stdio.rb +24 -0
- data/lib/command_kit/sudo.rb +40 -0
- data/lib/command_kit/terminal.rb +159 -0
- data/lib/command_kit/usage.rb +14 -0
- data/lib/command_kit/version.rb +1 -1
- data/lib/command_kit/xdg.rb +21 -1
- data/lib/command_kit.rb +1 -0
- data/spec/arguments/argument_spec.rb +5 -41
- data/spec/arguments/argument_value_spec.rb +1 -61
- data/spec/arguments_spec.rb +8 -25
- data/spec/colors_spec.rb +277 -13
- data/spec/command_name_spec.rb +1 -1
- data/spec/command_spec.rb +4 -1
- data/spec/commands/auto_load/subcommand_spec.rb +1 -1
- data/spec/commands/auto_load_spec.rb +1 -1
- data/spec/commands/auto_require_spec.rb +2 -2
- data/spec/commands/help_spec.rb +1 -1
- data/spec/commands/parent_command_spec.rb +1 -1
- data/spec/commands/subcommand_spec.rb +1 -1
- data/spec/commands_spec.rb +2 -2
- data/spec/description_spec.rb +1 -25
- data/spec/env/home_spec.rb +1 -1
- data/spec/env/path_spec.rb +1 -1
- data/spec/examples_spec.rb +1 -25
- data/spec/exception_handler_spec.rb +1 -1
- data/spec/help/man_spec.rb +316 -0
- data/spec/help_spec.rb +0 -25
- data/spec/inflector_spec.rb +71 -9
- data/spec/interactive_spec.rb +415 -0
- data/spec/main_spec.rb +7 -7
- data/spec/man_spec.rb +46 -0
- data/spec/open_app_spec.rb +85 -0
- data/spec/options/option_spec.rb +48 -9
- data/spec/options/option_value_spec.rb +53 -4
- data/spec/options_spec.rb +1 -1
- data/spec/os/linux_spec.rb +154 -0
- data/spec/os_spec.rb +201 -14
- data/spec/package_manager_spec.rb +806 -0
- data/spec/pager_spec.rb +78 -15
- data/spec/printing/indent_spec.rb +1 -1
- data/spec/printing_spec.rb +10 -2
- data/spec/program_name_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -3
- data/spec/sudo_spec.rb +51 -0
- data/spec/{console_spec.rb → terminal_spec.rb} +65 -35
- data/spec/usage_spec.rb +2 -2
- data/spec/xdg_spec.rb +1 -1
- metadata +32 -13
- data/lib/command_kit/arguments/usage.rb +0 -6
- data/lib/command_kit/console.rb +0 -141
- data/lib/command_kit/options/usage.rb +0 -6
data/spec/help_spec.rb
CHANGED
@@ -90,30 +90,5 @@ describe CommandKit::Help do
|
|
90
90
|
subject.help()
|
91
91
|
end
|
92
92
|
end
|
93
|
-
|
94
|
-
context "when the superclass defines it's own #help method" do
|
95
|
-
module TestHelp
|
96
|
-
class SuperclassWithHelp
|
97
|
-
|
98
|
-
def help
|
99
|
-
puts 'superclass'
|
100
|
-
end
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
class SubclassOfSuperclassWithHelp < SuperclassWithHelp
|
105
|
-
include CommandKit::Help
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
let(:command_superclass) { TestHelp::SuperclassWithHelp }
|
110
|
-
let(:command_class) { TestHelp::SubclassOfSuperclassWithHelp }
|
111
|
-
|
112
|
-
it "must call the superclass'es #help" do
|
113
|
-
expect_any_instance_of(command_superclass).to receive(:help)
|
114
|
-
|
115
|
-
subject.help()
|
116
|
-
end
|
117
|
-
end
|
118
93
|
end
|
119
94
|
end
|
data/spec/inflector_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/inflector'
|
3
3
|
|
4
|
-
describe Inflector do
|
4
|
+
describe CommandKit::Inflector do
|
5
5
|
describe ".demodularize" do
|
6
6
|
context "when given a single class or module name" do
|
7
7
|
let(:name) { 'Foo' }
|
@@ -28,6 +28,10 @@ describe Inflector do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
ascii = (0..255).map(&:chr)
|
32
|
+
alpha = ('a'..'z').to_a + ('A'..'Z').to_a
|
33
|
+
numeric = ('0'..'9').to_a
|
34
|
+
|
31
35
|
describe ".underscore" do
|
32
36
|
it "must convert CamelCase to camel_case" do
|
33
37
|
expect(subject.underscore('CamelCase')).to eq('camel_case')
|
@@ -37,18 +41,48 @@ describe Inflector do
|
|
37
41
|
expect(subject.underscore('camelCase')).to eq('camel_case')
|
38
42
|
end
|
39
43
|
|
40
|
-
it "must convert
|
41
|
-
expect(subject.underscore('
|
44
|
+
it "must convert Camelcase to camelcase" do
|
45
|
+
expect(subject.underscore('Camelcase')).to eq('camelcase')
|
42
46
|
end
|
43
47
|
|
44
|
-
it "must convert
|
45
|
-
expect(subject.underscore('
|
48
|
+
it "must convert CAMELCASE to camelcase" do
|
49
|
+
expect(subject.underscore('CAMELCASE')).to eq('camelcase')
|
46
50
|
end
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
it "must convert CAMELCase to camel_case" do
|
53
|
+
expect(subject.underscore('CAMELCase')).to eq('camel_case')
|
54
|
+
end
|
55
|
+
|
56
|
+
it "must convert CamelCASE to camel_case" do
|
57
|
+
expect(subject.underscore('CAMELCase')).to eq('camel_case')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "must convert FooBARBaz to foo_bar_baz" do
|
61
|
+
expect(subject.underscore('FooBARBaz')).to eq('foo_bar_baz')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "must convert foo_bar_baz to foo_bar_baz" do
|
65
|
+
expect(subject.underscore('foo_bar_baz')).to eq('foo_bar_baz')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "must convert foo___bar___baz to foo___bar___baz" do
|
69
|
+
expect(subject.underscore('foo___bar___baz')).to eq('foo___bar___baz')
|
70
|
+
end
|
71
|
+
|
72
|
+
it "must convert foo-bar-baz to foo_bar_baz" do
|
73
|
+
expect(subject.underscore('foo-bar-baz')).to eq('foo_bar_baz')
|
74
|
+
end
|
75
|
+
|
76
|
+
it "must convert foo---bar---baz to foo___bar___baz" do
|
77
|
+
expect(subject.underscore('foo---bar---baz')).to eq('foo___bar___baz')
|
78
|
+
end
|
79
|
+
|
80
|
+
it "must convert foo_BAR_baz to foo_bar_baz" do
|
81
|
+
expect(subject.underscore('foo_BAR_baz')).to eq('foo_bar_baz')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "must convert foo-BAR-baz to foo_bar_baz" do
|
85
|
+
expect(subject.underscore('foo-BAR-baz')).to eq('foo_bar_baz')
|
52
86
|
end
|
53
87
|
|
54
88
|
context "when given a non-String" do
|
@@ -56,6 +90,20 @@ describe Inflector do
|
|
56
90
|
expect(subject.underscore(:CamelCase)).to eq('camel_case')
|
57
91
|
end
|
58
92
|
end
|
93
|
+
|
94
|
+
separators = %w[_ -]
|
95
|
+
|
96
|
+
(ascii - alpha - numeric - separators).each do |char|
|
97
|
+
context "when the given String contains a #{char.inspect} character" do
|
98
|
+
let(:string) { "Foo#{char}Bar" }
|
99
|
+
|
100
|
+
it do
|
101
|
+
expect {
|
102
|
+
subject.underscore(string)
|
103
|
+
}.to raise_error(ArgumentError,"cannot convert string to underscored: #{string.inspect}")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
59
107
|
end
|
60
108
|
|
61
109
|
describe ".dasherize" do
|
@@ -100,5 +148,19 @@ describe Inflector do
|
|
100
148
|
expect(subject.camelize(:foo_bar)).to eq('FooBar')
|
101
149
|
end
|
102
150
|
end
|
151
|
+
|
152
|
+
separators = %w[_ - /]
|
153
|
+
|
154
|
+
(ascii - alpha - numeric - separators).each do |char|
|
155
|
+
context "when the given String contains a #{char.inspect} character" do
|
156
|
+
let(:string) { "foo#{char}bar" }
|
157
|
+
|
158
|
+
it do
|
159
|
+
expect {
|
160
|
+
subject.camelize(string)
|
161
|
+
}.to raise_error(ArgumentError,"cannot convert string to CamelCase: #{string.inspect}")
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
103
165
|
end
|
104
166
|
end
|
@@ -0,0 +1,415 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'command_kit/interactive'
|
3
|
+
|
4
|
+
describe CommandKit::Interactive do
|
5
|
+
module TestInteractive
|
6
|
+
class TestCommand
|
7
|
+
include CommandKit::Interactive
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:command_class) { TestInteractive::TestCommand }
|
12
|
+
|
13
|
+
describe "#included" do
|
14
|
+
subject { command_class }
|
15
|
+
|
16
|
+
it { expect(subject).to include(CommandKit::Stdio) }
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:stdout) { StringIO.new }
|
20
|
+
let(:stdin) { StringIO.new }
|
21
|
+
let(:stderr) { StringIO.new }
|
22
|
+
|
23
|
+
subject do
|
24
|
+
command_class.new(stdout: stdout, stdin: stdin, stderr: stderr)
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:prompt) { 'Prompt' }
|
28
|
+
|
29
|
+
describe "#ask" do
|
30
|
+
let(:input) { 'foo' }
|
31
|
+
|
32
|
+
it "must print a prompt, read input, and return the input" do
|
33
|
+
expect(stdout).to receive(:print).with("#{prompt}: ")
|
34
|
+
expect(stdin).to receive(:gets).and_return(input)
|
35
|
+
|
36
|
+
expect(subject.ask(prompt)).to eq(input)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "must accept empty user input by default" do
|
40
|
+
expect(stdin).to receive(:gets).and_return("")
|
41
|
+
|
42
|
+
expect(subject.ask(prompt)).to eq("")
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when Ctrl^C is entered" do
|
46
|
+
it "must return \"\"" do
|
47
|
+
expect(stdin).to receive(:gets).and_return(nil) # simulate Ctrl^C
|
48
|
+
|
49
|
+
expect(subject.ask(prompt)).to eq("")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when default: is given" do
|
54
|
+
let(:default) { 'bar' }
|
55
|
+
|
56
|
+
it "must include the default: value in the prompt" do
|
57
|
+
expect(stdout).to receive(:print).with("#{prompt} [#{default}]: ")
|
58
|
+
expect(stdin).to receive(:gets).and_return(input)
|
59
|
+
|
60
|
+
expect(subject.ask(prompt, default: default)).to eq(input)
|
61
|
+
end
|
62
|
+
|
63
|
+
context "and non-empty user input is given" do
|
64
|
+
it "must return the non-empty user input" do
|
65
|
+
expect(stdin).to receive(:gets).and_return(input)
|
66
|
+
|
67
|
+
expect(subject.ask(prompt, default: default)).to eq(input)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "and empty user input is given" do
|
72
|
+
it "must return the default value" do
|
73
|
+
expect(stdin).to receive(:gets).and_return("")
|
74
|
+
|
75
|
+
expect(subject.ask(prompt, default: default)).to eq(default)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when required: is given" do
|
81
|
+
context "and empty user input is given" do
|
82
|
+
it "must ask for input again, until non-empty input is given" do
|
83
|
+
expect(stdin).to receive(:gets).and_return("")
|
84
|
+
expect(stdin).to receive(:gets).and_return("")
|
85
|
+
expect(stdin).to receive(:gets).and_return(input)
|
86
|
+
|
87
|
+
expect(subject.ask(prompt, required: true)).to eq(input)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "and non-empty user input is given" do
|
92
|
+
it "must return the non-empty user input" do
|
93
|
+
expect(stdin).to receive(:gets).and_return(input)
|
94
|
+
|
95
|
+
expect(subject.ask(prompt, required: true)).to eq(input)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#ask_yes_or_no" do
|
102
|
+
let(:input) { 'Y' }
|
103
|
+
|
104
|
+
it "must print a prompt indicating Y/N, and then accept input" do
|
105
|
+
expect(stdout).to receive(:print).with("#{prompt} (Y/N): ")
|
106
|
+
expect(stdin).to receive(:gets).and_return(input)
|
107
|
+
|
108
|
+
subject.ask_yes_or_no(prompt)
|
109
|
+
end
|
110
|
+
|
111
|
+
context "when 'Y' is entered" do
|
112
|
+
let(:input) { 'Y' }
|
113
|
+
|
114
|
+
it "must return true" do
|
115
|
+
expect(stdin).to receive(:gets).and_return(input)
|
116
|
+
|
117
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(true)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when 'y' is entered" do
|
122
|
+
let(:input) { 'y' }
|
123
|
+
|
124
|
+
it "must return true" do
|
125
|
+
expect(stdin).to receive(:gets).and_return(input)
|
126
|
+
|
127
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(true)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "when 'YES' is entered" do
|
132
|
+
let(:input) { 'YES' }
|
133
|
+
|
134
|
+
it "must return true" do
|
135
|
+
expect(stdin).to receive(:gets).and_return(input)
|
136
|
+
|
137
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(true)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "when 'Yes' is entered" do
|
142
|
+
let(:input) { 'Yes' }
|
143
|
+
|
144
|
+
it "must return true" do
|
145
|
+
expect(stdin).to receive(:gets).and_return(input)
|
146
|
+
|
147
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(true)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when 'yes' is entered" do
|
152
|
+
let(:input) { 'yes' }
|
153
|
+
|
154
|
+
it "must return true" do
|
155
|
+
expect(stdin).to receive(:gets).and_return(input)
|
156
|
+
|
157
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(true)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context "when 'N' is entered" do
|
162
|
+
let(:input) { 'N' }
|
163
|
+
|
164
|
+
it "must return false" do
|
165
|
+
expect(stdin).to receive(:gets).and_return(input)
|
166
|
+
|
167
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(false)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "when 'n' is entered" do
|
172
|
+
let(:input) { 'n' }
|
173
|
+
|
174
|
+
it "must return false" do
|
175
|
+
expect(stdin).to receive(:gets).and_return(input)
|
176
|
+
|
177
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(false)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "when 'NO' is entered" do
|
182
|
+
let(:input) { 'NO' }
|
183
|
+
|
184
|
+
it "must return false" do
|
185
|
+
expect(stdin).to receive(:gets).and_return(input)
|
186
|
+
|
187
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(false)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "when 'No' is entered" do
|
192
|
+
let(:input) { 'No' }
|
193
|
+
|
194
|
+
it "must return false" do
|
195
|
+
expect(stdin).to receive(:gets).and_return(input)
|
196
|
+
|
197
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(false)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context "when 'no' is entered" do
|
202
|
+
let(:input) { 'no' }
|
203
|
+
|
204
|
+
it "must return false" do
|
205
|
+
expect(stdin).to receive(:gets).and_return(input)
|
206
|
+
|
207
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(false)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context "when input besides y/n/yes/no is entered" do
|
212
|
+
let(:input) { 'jflksjfls' }
|
213
|
+
|
214
|
+
it "must return false" do
|
215
|
+
expect(stdin).to receive(:gets).and_return(input)
|
216
|
+
|
217
|
+
expect(subject.ask_yes_or_no(prompt)).to eq(false)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "when defualt: is given" do
|
222
|
+
context "and is true" do
|
223
|
+
let(:default) { true }
|
224
|
+
|
225
|
+
it "must include [Y] in the prompt" do
|
226
|
+
expect(stdout).to receive(:print).with("#{prompt} (Y/N) [Y]: ")
|
227
|
+
expect(stdin).to receive(:gets).and_return(input)
|
228
|
+
|
229
|
+
subject.ask_yes_or_no(prompt, default: default)
|
230
|
+
end
|
231
|
+
|
232
|
+
context "and empty user-input is given" do
|
233
|
+
let(:input) { "" }
|
234
|
+
|
235
|
+
it "must return true" do
|
236
|
+
expect(stdout).to receive(:print).with("#{prompt} (Y/N) [Y]: ")
|
237
|
+
expect(stdin).to receive(:gets).and_return(input)
|
238
|
+
|
239
|
+
expect(subject.ask_yes_or_no(prompt, default: default)).to eq(default)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context "and is false" do
|
245
|
+
let(:default) { false }
|
246
|
+
|
247
|
+
it "must include [N] in the prompt" do
|
248
|
+
expect(stdout).to receive(:print).with("#{prompt} (Y/N) [N]: ")
|
249
|
+
expect(stdin).to receive(:gets).and_return(input)
|
250
|
+
|
251
|
+
subject.ask_yes_or_no(prompt, default: default)
|
252
|
+
end
|
253
|
+
|
254
|
+
context "and empty user-input is given" do
|
255
|
+
let(:input) { "" }
|
256
|
+
|
257
|
+
it "must return false" do
|
258
|
+
expect(stdout).to receive(:print).with("#{prompt} (Y/N) [N]: ")
|
259
|
+
expect(stdin).to receive(:gets).and_return(input)
|
260
|
+
|
261
|
+
expect(subject.ask_yes_or_no(prompt, default: default)).to eq(default)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "#ask_multiple_choice" do
|
269
|
+
context "when given an Array" do
|
270
|
+
let(:choices) do
|
271
|
+
[
|
272
|
+
"foo",
|
273
|
+
"bar",
|
274
|
+
"baz"
|
275
|
+
]
|
276
|
+
end
|
277
|
+
|
278
|
+
let(:input) { "2" }
|
279
|
+
|
280
|
+
it "must print the numbered choices, a prompt with the choices, read input, and return the choice" do
|
281
|
+
expect(stdout).to receive(:puts).with(" 1) #{choices[0]}")
|
282
|
+
expect(stdout).to receive(:puts).with(" 2) #{choices[1]}")
|
283
|
+
expect(stdout).to receive(:puts).with(" 3) #{choices[2]}")
|
284
|
+
expect(stdout).to receive(:puts).with(no_args)
|
285
|
+
expect(stdout).to receive(:print).with("#{prompt} (1, 2, 3): ")
|
286
|
+
expect(stdin).to receive(:gets).and_return(input)
|
287
|
+
|
288
|
+
expect(subject.ask_multiple_choice(prompt,choices)).to eq(choices[input.to_i - 1])
|
289
|
+
end
|
290
|
+
|
291
|
+
context "when empty user-input is given" do
|
292
|
+
it "must ask for input again, until non-empty input is given" do
|
293
|
+
expect(stdin).to receive(:gets).and_return("")
|
294
|
+
expect(stdin).to receive(:gets).and_return("")
|
295
|
+
expect(stdin).to receive(:gets).and_return(input)
|
296
|
+
|
297
|
+
expect(subject.ask_multiple_choice(prompt,choices)).to eq(choices[input.to_i - 1])
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
context "and default: is given" do
|
302
|
+
let(:default) { '3' }
|
303
|
+
|
304
|
+
it "must include the default: choice in the prompt" do
|
305
|
+
expect(stdout).to receive(:print).with("#{prompt} (1, 2, 3) [#{default}]: ")
|
306
|
+
expect(stdin).to receive(:gets).and_return(input)
|
307
|
+
|
308
|
+
subject.ask_multiple_choice(prompt,choices, default: default)
|
309
|
+
end
|
310
|
+
|
311
|
+
context "and empty user-input is given" do
|
312
|
+
it "must return the value for the default choice" do
|
313
|
+
expect(stdin).to receive(:gets).and_return("")
|
314
|
+
|
315
|
+
expect(subject.ask_multiple_choice(prompt,choices, default: default)).to eq(choices[default.to_i - 1])
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
context "when given a Hash" do
|
322
|
+
let(:choices) do
|
323
|
+
{
|
324
|
+
"A" => "foo",
|
325
|
+
"B" => "bar",
|
326
|
+
"C" => "baz"
|
327
|
+
}
|
328
|
+
end
|
329
|
+
|
330
|
+
let(:input) { "B" }
|
331
|
+
|
332
|
+
it "must print the labeled choices, a prompt with the choices, read input, and return the choice" do
|
333
|
+
expect(stdout).to receive(:puts).with(" #{choices.keys[0]}) #{choices.values[0]}")
|
334
|
+
expect(stdout).to receive(:puts).with(" #{choices.keys[1]}) #{choices.values[1]}")
|
335
|
+
expect(stdout).to receive(:puts).with(" #{choices.keys[2]}) #{choices.values[2]}")
|
336
|
+
expect(stdout).to receive(:puts).with(no_args)
|
337
|
+
expect(stdout).to receive(:print).with("#{prompt} (#{choices.keys[0]}, #{choices.keys[1]}, #{choices.keys[2]}): ")
|
338
|
+
expect(stdin).to receive(:gets).and_return(input)
|
339
|
+
|
340
|
+
expect(subject.ask_multiple_choice(prompt,choices)).to eq(choices[input])
|
341
|
+
end
|
342
|
+
|
343
|
+
context "when empty user-input is given" do
|
344
|
+
it "must ask for input again, until non-empty input is given" do
|
345
|
+
expect(stdin).to receive(:gets).and_return("")
|
346
|
+
expect(stdin).to receive(:gets).and_return("")
|
347
|
+
expect(stdin).to receive(:gets).and_return(input)
|
348
|
+
|
349
|
+
expect(subject.ask_multiple_choice(prompt,choices)).to eq(choices[input])
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
context "and default: is given" do
|
354
|
+
let(:default) { 'C' }
|
355
|
+
|
356
|
+
it "must include the default: choice in the prompt" do
|
357
|
+
expect(stdout).to receive(:print).with("#{prompt} (#{choices.keys[0]}, #{choices.keys[1]}, #{choices.keys[2]}) [#{default}]: ")
|
358
|
+
expect(stdin).to receive(:gets).and_return(input)
|
359
|
+
|
360
|
+
subject.ask_multiple_choice(prompt,choices, default: default)
|
361
|
+
end
|
362
|
+
|
363
|
+
context "and empty user-input is given" do
|
364
|
+
it "must return the value for the default choice" do
|
365
|
+
expect(stdin).to receive(:gets).and_return("")
|
366
|
+
|
367
|
+
expect(subject.ask_multiple_choice(prompt,choices, default: default)).to eq(choices[default])
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
describe "#ask_secret" do
|
375
|
+
let(:input) { 's3cr3t' }
|
376
|
+
|
377
|
+
context "when stdin supports to #noecho" do
|
378
|
+
it "must call #noecho, read input, then return the input" do
|
379
|
+
allow(stdin).to receive(:noecho).and_yield
|
380
|
+
expect(stdin).to receive(:gets).and_return(input)
|
381
|
+
|
382
|
+
expect(subject.ask_secret(prompt)).to eq(input)
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
context "when stdin does not support #noecho" do
|
387
|
+
it "must fallback to reading input" do
|
388
|
+
expect(stdin).to receive(:gets).and_return(input)
|
389
|
+
|
390
|
+
expect(subject.ask_secret(prompt)).to eq(input)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
context "when empty user-input is given" do
|
395
|
+
it "must ask for input again, until non-empty input is given" do
|
396
|
+
expect(stdin).to receive(:gets).and_return("")
|
397
|
+
expect(stdin).to receive(:gets).and_return("")
|
398
|
+
expect(stdin).to receive(:gets).and_return("")
|
399
|
+
expect(stdin).to receive(:gets).and_return(input)
|
400
|
+
|
401
|
+
expect(subject.ask_secret(prompt)).to eq(input)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
context "when required: is false" do
|
406
|
+
context "and empty user-input is given" do
|
407
|
+
it "must return the empty user-input" do
|
408
|
+
expect(stdin).to receive(:gets).and_return("")
|
409
|
+
|
410
|
+
expect(subject.ask_secret(prompt, required: false)).to eq("")
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|