highline_wrapper 0.1.0 → 1.0.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/Gemfile.lock +100 -0
- data/README.md +269 -13
- data/lib/highline_wrapper.rb +82 -31
- data/lib/highline_wrapper/checkbox_question.rb +32 -0
- data/lib/highline_wrapper/multiple_choice_question.rb +20 -0
- data/lib/highline_wrapper/open_ended_question.rb +19 -0
- data/lib/highline_wrapper/question.rb +35 -0
- data/lib/highline_wrapper/version.rb +1 -1
- data/lib/highline_wrapper/yes_no_question.rb +26 -0
- data/spec/highline_wrapper/checkbox_question_spec.rb +188 -0
- data/spec/highline_wrapper/multiple_choice_question_spec.rb +188 -0
- data/spec/highline_wrapper/open_ended_question_spec.rb +94 -0
- data/spec/highline_wrapper/question_spec.rb +63 -0
- data/spec/highline_wrapper/yes_no_question_spec.rb +88 -0
- metadata +24 -11
- data/lib/highline_wrapper/client.rb +0 -68
- data/spec/highline_wrapper/client_spec.rb +0 -109
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'question'
|
4
|
+
|
5
|
+
class HighlineWrapper
|
6
|
+
class CheckboxQuestion < Question
|
7
|
+
class << self
|
8
|
+
def ask(prompt, choices, options)
|
9
|
+
indices = ask_highline(format_options(prompt, choices))
|
10
|
+
puts
|
11
|
+
|
12
|
+
return format_multiple_selections(choices, indices, options[:with_indexes]) unless indices.empty?
|
13
|
+
return recurse(prompt, choices, options) if options[:required]
|
14
|
+
return options[:defaults] if options[:defaults].empty?
|
15
|
+
|
16
|
+
format_multiple_selections(choices, options[:defaults].map { |d| choices.index(d) }, options[:with_indexes])
|
17
|
+
end
|
18
|
+
|
19
|
+
private def ask_highline(prompt)
|
20
|
+
indices = []
|
21
|
+
super(prompt).to_s.split(',').each { |i| indices << i.strip.to_i - 1 }
|
22
|
+
indices
|
23
|
+
end
|
24
|
+
|
25
|
+
private def format_multiple_selections(choices, indices, with_indexes)
|
26
|
+
selected = []
|
27
|
+
indices.each { |index| selected << format_selection(choices, index, with_indexes) }
|
28
|
+
selected
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'question'
|
4
|
+
|
5
|
+
class HighlineWrapper
|
6
|
+
class MultipleChoiceQuestion < Question
|
7
|
+
class << self
|
8
|
+
def ask(prompt, choices, options)
|
9
|
+
index = ask_highline(format_options(prompt, choices)).to_i - 1
|
10
|
+
puts
|
11
|
+
|
12
|
+
return format_selection(choices, index, options[:with_index]) unless index == -1
|
13
|
+
return recurse(prompt, choices, options) if options[:required]
|
14
|
+
return nil if options[:default].nil?
|
15
|
+
|
16
|
+
format_selection(choices, choices.index(options[:default]), options[:with_index])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'question'
|
4
|
+
|
5
|
+
class HighlineWrapper
|
6
|
+
class OpenEndedQuestion < Question
|
7
|
+
class << self
|
8
|
+
def ask(prompt, options)
|
9
|
+
answer = ask_highline(prompt, secret: options[:secret]).to_s
|
10
|
+
puts unless answer.empty? && options[:secret]
|
11
|
+
|
12
|
+
return answer unless answer.empty?
|
13
|
+
return recurse(prompt, nil, options) if options[:required]
|
14
|
+
|
15
|
+
options[:default]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class HighlineWrapper
|
4
|
+
class Question
|
5
|
+
class << self
|
6
|
+
def ask_highline(prompt, secret: false)
|
7
|
+
highline.ask(prompt) do |conf|
|
8
|
+
conf.readline = true
|
9
|
+
conf.echo = '*' if secret
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def format_options(prompt, choices)
|
14
|
+
choices_as_string_options = ''.dup
|
15
|
+
choices.each_with_index { |choice, index| choices_as_string_options << "#{index + 1}. #{choice}\n" }
|
16
|
+
"#{prompt}\n#{choices_as_string_options.strip}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def format_selection(choices, index, with_index)
|
20
|
+
response = { value: choices[index] }
|
21
|
+
response[:index] = index if with_index
|
22
|
+
response
|
23
|
+
end
|
24
|
+
|
25
|
+
def recurse(prompt, choices, options)
|
26
|
+
puts "This question is required.\n\n"
|
27
|
+
choices.nil? ? ask(prompt, options) : ask(prompt, choices, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
private def highline
|
31
|
+
@highline ||= HighLine.new
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'question'
|
4
|
+
|
5
|
+
class HighlineWrapper
|
6
|
+
class YesNoQuestion < Question
|
7
|
+
class << self
|
8
|
+
def ask(prompt, options)
|
9
|
+
answer = ask_highline(prompt).to_s.downcase
|
10
|
+
puts
|
11
|
+
|
12
|
+
return parse(answer, prompt, options) unless answer.empty?
|
13
|
+
return recurse(prompt, nil, options) if options[:required]
|
14
|
+
|
15
|
+
options[:default]
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse(answer, prompt, options)
|
19
|
+
return true if answer.include?('y')
|
20
|
+
return false if answer.include?('n')
|
21
|
+
|
22
|
+
recurse(prompt, nil, options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'highline_wrapper'
|
5
|
+
|
6
|
+
describe HighlineWrapper::CheckboxQuestion do
|
7
|
+
let(:choices) { %w[one two three] }
|
8
|
+
let(:response) { double(:response, readline: true, to_i: 3) }
|
9
|
+
let(:highline) { double(:highline_cli, ask: response) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(HighLine).to receive(:new).and_return(highline)
|
13
|
+
allow(subject).to receive(:puts)
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
HighlineWrapper::CheckboxQuestion.instance_variable_set('@highline', nil)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { HighlineWrapper::CheckboxQuestion }
|
21
|
+
|
22
|
+
context 'with the options as defaults' do
|
23
|
+
let(:options) do
|
24
|
+
{
|
25
|
+
with_indexes: false,
|
26
|
+
defaults: [],
|
27
|
+
required: false
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should ask the highline client ask' do
|
32
|
+
expect(highline).to receive(:ask)
|
33
|
+
subject.ask(Faker::Lorem.sentence, choices, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return the value the user selects' do
|
37
|
+
allow(highline).to receive(:ask).and_return('1,3')
|
38
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
39
|
+
expect(resp).to eq([{ value: 'one' }, { value: 'three' }])
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should return empty array if the user skips' do
|
43
|
+
allow(highline).to receive(:ask).and_return('')
|
44
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
45
|
+
expect(resp).to eq([])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with required set to true' do
|
50
|
+
context 'with_indexes set to false' do
|
51
|
+
let(:options) do
|
52
|
+
{
|
53
|
+
with_indexes: false,
|
54
|
+
defaults: [],
|
55
|
+
required: true
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return the value the user selects' do
|
60
|
+
allow(highline).to receive(:ask).and_return('1,2')
|
61
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
62
|
+
expect(resp).to eq([{ value: 'one' }, { value: 'two' }])
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should recurse multiple times if the user skips' do
|
66
|
+
allow(highline).to receive(:ask).and_return('', '', '3')
|
67
|
+
expect(subject).to receive(:ask).exactly(3).times.and_call_original
|
68
|
+
subject.ask(Faker::Lorem.sentence, choices, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with_indexes set to true' do
|
73
|
+
let(:options) do
|
74
|
+
{
|
75
|
+
with_indexes: true,
|
76
|
+
defaults: [],
|
77
|
+
required: true
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should return the value the user selects' do
|
82
|
+
allow(highline).to receive(:ask).and_return('1, 3')
|
83
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
84
|
+
expect(resp).to eq([{ value: 'one', index: 0 }, { value: 'three', index: 2 }])
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should recurse multiple times if the user skips' do
|
88
|
+
allow(highline).to receive(:ask).and_return('', '', '3')
|
89
|
+
expect(subject).to receive(:ask).exactly(3).times.and_call_original
|
90
|
+
subject.ask(Faker::Lorem.sentence, choices, options)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with required set to false' do
|
96
|
+
context 'with_indexes set to false' do
|
97
|
+
context 'with defaults set' do
|
98
|
+
let(:options) do
|
99
|
+
{
|
100
|
+
with_indexes: false,
|
101
|
+
defaults: ['two'],
|
102
|
+
required: false
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should return the value the user selects' do
|
107
|
+
allow(highline).to receive(:ask).and_return('1, 2')
|
108
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
109
|
+
expect(resp).to eq([{ value: 'one' }, { value: 'two' }])
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should return the default if the user skips' do
|
113
|
+
allow(highline).to receive(:ask).and_return('')
|
114
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
115
|
+
expect(resp).to eq([{ value: 'two' }])
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'with defaults set to []' do
|
120
|
+
let(:options) do
|
121
|
+
{
|
122
|
+
with_indexes: false,
|
123
|
+
defaults: [],
|
124
|
+
required: false
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should return the value the user selects' do
|
129
|
+
allow(highline).to receive(:ask).and_return('1,3')
|
130
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
131
|
+
expect(resp).to eq([{ value: 'one' }, { value: 'three' }])
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should return nil if the user skips' do
|
135
|
+
allow(highline).to receive(:ask).and_return('')
|
136
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
137
|
+
expect(resp).to eq([])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'with_indexes set to true' do
|
143
|
+
context 'with default set' do
|
144
|
+
let(:options) do
|
145
|
+
{
|
146
|
+
with_indexes: true,
|
147
|
+
defaults: ['two'],
|
148
|
+
required: false
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should return the value the user selects' do
|
153
|
+
allow(highline).to receive(:ask).and_return('1,2')
|
154
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
155
|
+
expect(resp).to eq([{ value: 'one', index: 0 }, { value: 'two', index: 1 }])
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should return the default if the user skips' do
|
159
|
+
allow(highline).to receive(:ask).and_return('')
|
160
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
161
|
+
expect(resp).to eq([{ value: 'two', index: 1 }])
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'with default nil' do
|
166
|
+
let(:options) do
|
167
|
+
{
|
168
|
+
with_indexes: true,
|
169
|
+
defaults: [],
|
170
|
+
required: false
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should return the value the user selects' do
|
175
|
+
allow(highline).to receive(:ask).and_return('1')
|
176
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
177
|
+
expect(resp).to eq([{ value: 'one', index: 0 }])
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should return [] if the user skips' do
|
181
|
+
allow(highline).to receive(:ask).and_return('')
|
182
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
183
|
+
expect(resp).to eq([])
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'highline_wrapper'
|
5
|
+
|
6
|
+
describe HighlineWrapper::MultipleChoiceQuestion do
|
7
|
+
let(:choices) { %w[one two three] }
|
8
|
+
let(:response) { double(:response, readline: true, to_i: 3) }
|
9
|
+
let(:highline) { double(:highline_cli, ask: response) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(HighLine).to receive(:new).and_return(highline)
|
13
|
+
allow(subject).to receive(:puts)
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
HighlineWrapper::MultipleChoiceQuestion.instance_variable_set('@highline', nil)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { HighlineWrapper::MultipleChoiceQuestion }
|
21
|
+
|
22
|
+
context 'with the options as defaults' do
|
23
|
+
let(:options) do
|
24
|
+
{
|
25
|
+
with_index: false,
|
26
|
+
default: nil,
|
27
|
+
required: false
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should ask the highline client ask' do
|
32
|
+
expect(highline).to receive(:ask)
|
33
|
+
subject.ask(Faker::Lorem.sentence, choices, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return the value the user selects' do
|
37
|
+
allow(highline).to receive(:ask).and_return(1)
|
38
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
39
|
+
expect(resp).to eq({ value: 'one' })
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should return nil if the user skips' do
|
43
|
+
allow(highline).to receive(:ask).and_return(0)
|
44
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
45
|
+
expect(resp).to eq(nil)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with required set to true' do
|
50
|
+
context 'with_index set to false' do
|
51
|
+
let(:options) do
|
52
|
+
{
|
53
|
+
with_index: false,
|
54
|
+
default: Faker::Lorem.word,
|
55
|
+
required: true
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should return the value the user selects' do
|
60
|
+
allow(highline).to receive(:ask).and_return(1)
|
61
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
62
|
+
expect(resp).to eq({ value: 'one' })
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should recurse multiple times if the user skips' do
|
66
|
+
allow(highline).to receive(:ask).and_return(0, 0, 3)
|
67
|
+
expect(subject).to receive(:ask).exactly(3).times.and_call_original
|
68
|
+
subject.ask(Faker::Lorem.sentence, choices, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with_index set to true' do
|
73
|
+
let(:options) do
|
74
|
+
{
|
75
|
+
with_index: true,
|
76
|
+
default: nil,
|
77
|
+
required: true
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should return the value the user selects' do
|
82
|
+
allow(highline).to receive(:ask).and_return(1)
|
83
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
84
|
+
expect(resp).to eq({ value: 'one', index: 0 })
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should recurse multiple times if the user skips' do
|
88
|
+
allow(highline).to receive(:ask).and_return(0, 0, 3)
|
89
|
+
expect(subject).to receive(:ask).exactly(3).times.and_call_original
|
90
|
+
subject.ask(Faker::Lorem.sentence, choices, options)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'with required set to false' do
|
96
|
+
context 'with_index set to false' do
|
97
|
+
context 'with default set' do
|
98
|
+
let(:options) do
|
99
|
+
{
|
100
|
+
with_index: false,
|
101
|
+
default: 'two',
|
102
|
+
required: false
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should return the value the user selects' do
|
107
|
+
allow(highline).to receive(:ask).and_return(1)
|
108
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
109
|
+
expect(resp).to eq({ value: 'one' })
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should return the default if the user skips' do
|
113
|
+
allow(highline).to receive(:ask).and_return(0)
|
114
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
115
|
+
expect(resp).to eq({ value: 'two' })
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'with default nil' do
|
120
|
+
let(:options) do
|
121
|
+
{
|
122
|
+
with_index: false,
|
123
|
+
default: nil,
|
124
|
+
required: false
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should return the value the user selects' do
|
129
|
+
allow(highline).to receive(:ask).and_return(1)
|
130
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
131
|
+
expect(resp).to eq({ value: 'one' })
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should return nil if the user skips' do
|
135
|
+
allow(highline).to receive(:ask).and_return(0)
|
136
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
137
|
+
expect(resp).to eq(nil)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'with_index set to true' do
|
143
|
+
context 'with default set' do
|
144
|
+
let(:options) do
|
145
|
+
{
|
146
|
+
with_index: true,
|
147
|
+
default: 'two',
|
148
|
+
required: false
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should return the value the user selects' do
|
153
|
+
allow(highline).to receive(:ask).and_return(1)
|
154
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
155
|
+
expect(resp).to eq({ value: 'one', index: 0 })
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should return the default if the user skips' do
|
159
|
+
allow(highline).to receive(:ask).and_return(0)
|
160
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
161
|
+
expect(resp).to eq({ value: 'two', index: 1 })
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'with default nil' do
|
166
|
+
let(:options) do
|
167
|
+
{
|
168
|
+
with_index: true,
|
169
|
+
default: nil,
|
170
|
+
required: false
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should return the value the user selects' do
|
175
|
+
allow(highline).to receive(:ask).and_return(1)
|
176
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
177
|
+
expect(resp).to eq({ value: 'one', index: 0 })
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should return nil if the user skips' do
|
181
|
+
allow(highline).to receive(:ask).and_return(0)
|
182
|
+
resp = subject.ask(Faker::Lorem.sentence, choices, options)
|
183
|
+
expect(resp).to eq(nil)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|