highline_wrapper 0.1.0 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
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
+
11
+ return format_multiple_selections(choices, indices, options[:with_indexes]) unless indices.empty?
12
+ return recurse(prompt, choices, options) if options[:required]
13
+ return return_empty_defaults(options) if options[:defaults].empty?
14
+
15
+ return_defaults(choices, options)
16
+ end
17
+
18
+ private def ask_highline(prompt)
19
+ indices = []
20
+ super(prompt).to_s.split(',').each { |i| indices << i.strip.to_i - 1 }
21
+ indices
22
+ end
23
+
24
+ private def return_defaults(choices, options)
25
+ options[:default_indexes] = options[:defaults].map { |d| choices.index(d) }
26
+ print_default_message(options, choices) if options[:indicate_default_message]
27
+ format_multiple_selections(choices, options[:default_indexes], options[:with_indexes])
28
+ end
29
+
30
+ private def print_default_message(options, choices)
31
+ defaults = options[:default_indexes].map { |i| "#{i + 1}. #{choices[i]}".strip }.join(', ')
32
+ puts "--- Defaults selected: #{defaults} ---"
33
+ end
34
+
35
+ private def format_multiple_selections(choices, indices, with_indexes)
36
+ selected = []
37
+ indices.each { |index| selected << format_selection(choices, index, with_indexes) }
38
+ selected
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
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
+
11
+ return format_selection(choices, index, options[:with_index]) unless index == -1
12
+ return recurse(prompt, choices, options) if options[:required]
13
+ return return_empty_defaults(options) if options[:default].nil?
14
+
15
+ return_defaults(choices, options)
16
+ end
17
+
18
+ private def return_defaults(choices, options)
19
+ options[:default_index] = choices.index(options[:default])
20
+ print_default_message(options) if options[:indicate_default_message]
21
+ format_selection(choices, options[:default_index], options[:with_index])
22
+ end
23
+
24
+ private def print_default_message(options)
25
+ puts "--- Default selected: #{options[:default_index] + 1}. #{options[:default]} ---"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
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
+
11
+ return answer unless answer.empty?
12
+ return recurse(prompt, nil, options) if options[:required]
13
+
14
+ print_default_message(options) if options[:indicate_default_message]
15
+ options[:default]
16
+ end
17
+
18
+ private def print_default_message(options)
19
+ if !options[:secret]
20
+ puts "--- Default selected: #{options[:default].empty? ? 'EMPTY' : options[:default]} ---"
21
+ elsif options[:secret]
22
+ puts '--- Default selected: HIDDEN ---'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
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 ---'
27
+ choices.nil? ? ask(prompt, options) : ask(prompt, choices, options)
28
+ end
29
+
30
+ def return_empty_defaults(options)
31
+ puts '--- Default selected: EMPTY ---' if options[:indicate_default_message]
32
+ options[:defaults] || options[:default]
33
+ end
34
+
35
+ private def highline
36
+ @highline ||= HighLine.new
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class HighlineWrapper
4
- VERSION = '0.1.0'
4
+ VERSION = '1.2.2'
5
5
  end
@@ -0,0 +1,34 @@
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
+
11
+ return parse(answer, prompt, options) unless answer.empty?
12
+ return recurse(prompt, nil, options) if options[:required]
13
+
14
+ print_default_message(options) if options[:indicate_default_message]
15
+ options[:default]
16
+ end
17
+
18
+ private def parse(answer, prompt, options)
19
+ case answer
20
+ when 'yes', 'y'
21
+ true
22
+ when 'no', 'n'
23
+ false
24
+ else
25
+ recurse(prompt, nil, options)
26
+ end
27
+ end
28
+
29
+ private def print_default_message(options)
30
+ puts "--- Default selected: #{options[:default] ? 'YES' : 'NO'} ---"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,226 @@
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
+
48
+ it 'should call the return empty defaults if the user skips' do
49
+ allow(highline).to receive(:ask).and_return('')
50
+ expect(subject).to receive(:return_empty_defaults)
51
+ subject.ask(Faker::Lorem.sentence, choices, options)
52
+ end
53
+ end
54
+
55
+ context 'with required set to true' do
56
+ context 'with_indexes set to false' do
57
+ let(:options) do
58
+ {
59
+ with_indexes: false,
60
+ defaults: [],
61
+ required: true
62
+ }
63
+ end
64
+
65
+ it 'should return the value the user selects' do
66
+ allow(highline).to receive(:ask).and_return('1,2')
67
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
68
+ expect(resp).to eq([{ value: 'one' }, { value: 'two' }])
69
+ end
70
+
71
+ it 'should recurse multiple times if the user skips' do
72
+ allow(highline).to receive(:ask).and_return('', '', '3')
73
+ expect(subject).to receive(:ask).exactly(3).times.and_call_original
74
+ subject.ask(Faker::Lorem.sentence, choices, options)
75
+ end
76
+ end
77
+
78
+ context 'with_indexes set to true' do
79
+ let(:options) do
80
+ {
81
+ with_indexes: true,
82
+ defaults: [],
83
+ required: true
84
+ }
85
+ end
86
+
87
+ it 'should return the value the user selects' do
88
+ allow(highline).to receive(:ask).and_return('1, 3')
89
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
90
+ expect(resp).to eq([{ value: 'one', index: 0 }, { value: 'three', index: 2 }])
91
+ end
92
+
93
+ it 'should recurse multiple times if the user skips' do
94
+ allow(highline).to receive(:ask).and_return('', '', '3')
95
+ expect(subject).to receive(:ask).exactly(3).times.and_call_original
96
+ subject.ask(Faker::Lorem.sentence, choices, options)
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'with required set to false' do
102
+ context 'with_indexes set to false' do
103
+ context 'with defaults set' do
104
+ let(:options) do
105
+ {
106
+ indicate_default_message: true,
107
+ with_indexes: false,
108
+ defaults: ['two'],
109
+ required: false
110
+ }
111
+ end
112
+
113
+ it 'should return the value the user selects' do
114
+ allow(highline).to receive(:ask).and_return('1, 2')
115
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
116
+ expect(resp).to eq([{ value: 'one' }, { value: 'two' }])
117
+ end
118
+
119
+ it 'should return the default if the user skips' do
120
+ allow(highline).to receive(:ask).and_return('')
121
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
122
+ expect(resp).to eq([{ value: 'two' }])
123
+ end
124
+
125
+ it 'should call to return the defaults if the user skips' do
126
+ allow(highline).to receive(:ask).and_return('')
127
+ expect(subject).to receive(:return_defaults).and_call_original
128
+ expect(subject).to receive(:puts)
129
+ subject.ask(Faker::Lorem.sentence, choices, options)
130
+ end
131
+
132
+ context 'when the indicate_default_message is false' do
133
+ let(:options) do
134
+ {
135
+ indicate_default_message: false,
136
+ with_indexes: false,
137
+ defaults: ['two'],
138
+ required: false
139
+ }
140
+ end
141
+
142
+ it 'should call to return the defaults if the user skips' do
143
+ allow(highline).to receive(:ask).and_return('')
144
+ expect(subject).to receive(:return_defaults)
145
+ expect(subject).not_to receive(:puts)
146
+ subject.ask(Faker::Lorem.sentence, choices, options)
147
+ end
148
+ end
149
+ end
150
+
151
+ context 'with defaults set to []' do
152
+ let(:options) do
153
+ {
154
+ with_indexes: false,
155
+ defaults: [],
156
+ required: false
157
+ }
158
+ end
159
+
160
+ it 'should return the value the user selects' do
161
+ allow(highline).to receive(:ask).and_return('1,3')
162
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
163
+ expect(resp).to eq([{ value: 'one' }, { value: 'three' }])
164
+ end
165
+
166
+ it 'should return nil if the user skips' do
167
+ allow(highline).to receive(:ask).and_return('')
168
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
169
+ expect(resp).to eq([])
170
+ end
171
+ end
172
+ end
173
+
174
+ context 'with_indexes set to true' do
175
+ context 'with default set' do
176
+ let(:options) do
177
+ {
178
+ with_indexes: true,
179
+ defaults: ['two'],
180
+ required: false
181
+ }
182
+ end
183
+
184
+ it 'should return the value the user selects' do
185
+ allow(highline).to receive(:ask).and_return('1,2')
186
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
187
+ expect(resp).to eq([{ value: 'one', index: 0 }, { value: 'two', index: 1 }])
188
+ end
189
+
190
+ it 'should return the default if the user skips' do
191
+ allow(highline).to receive(:ask).and_return('')
192
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
193
+ expect(resp).to eq([{ value: 'two', index: 1 }])
194
+ end
195
+ end
196
+
197
+ context 'with default nil' do
198
+ let(:options) do
199
+ {
200
+ with_indexes: true,
201
+ defaults: [],
202
+ required: false
203
+ }
204
+ end
205
+
206
+ it 'should return the value the user selects' do
207
+ allow(highline).to receive(:ask).and_return('1')
208
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
209
+ expect(resp).to eq([{ value: 'one', index: 0 }])
210
+ end
211
+
212
+ it 'should return [] if the user skips' do
213
+ allow(highline).to receive(:ask).and_return('')
214
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
215
+ expect(resp).to eq([])
216
+ end
217
+
218
+ it 'should call the return empty defaults message' do
219
+ allow(highline).to receive(:ask).and_return('')
220
+ expect(subject).to receive(:return_empty_defaults)
221
+ subject.ask(Faker::Lorem.sentence, choices, options)
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,226 @@
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
+
48
+ it 'should call the return empty defaults if the user skips' do
49
+ allow(highline).to receive(:ask).and_return('')
50
+ expect(subject).to receive(:return_empty_defaults)
51
+ subject.ask(Faker::Lorem.sentence, choices, options)
52
+ end
53
+ end
54
+
55
+ context 'with required set to true' do
56
+ context 'with_index set to false' do
57
+ let(:options) do
58
+ {
59
+ with_index: false,
60
+ default: Faker::Lorem.word,
61
+ required: true
62
+ }
63
+ end
64
+
65
+ it 'should return the value the user selects' do
66
+ allow(highline).to receive(:ask).and_return(1)
67
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
68
+ expect(resp).to eq({ value: 'one' })
69
+ end
70
+
71
+ it 'should recurse multiple times if the user skips' do
72
+ allow(highline).to receive(:ask).and_return(0, 0, 3)
73
+ expect(subject).to receive(:ask).exactly(3).times.and_call_original
74
+ subject.ask(Faker::Lorem.sentence, choices, options)
75
+ end
76
+ end
77
+
78
+ context 'with_index set to true' do
79
+ let(:options) do
80
+ {
81
+ with_index: true,
82
+ default: nil,
83
+ required: true
84
+ }
85
+ end
86
+
87
+ it 'should return the value the user selects' do
88
+ allow(highline).to receive(:ask).and_return(1)
89
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
90
+ expect(resp).to eq({ value: 'one', index: 0 })
91
+ end
92
+
93
+ it 'should recurse multiple times if the user skips' do
94
+ allow(highline).to receive(:ask).and_return(0, 0, 3)
95
+ expect(subject).to receive(:ask).exactly(3).times.and_call_original
96
+ subject.ask(Faker::Lorem.sentence, choices, options)
97
+ end
98
+ end
99
+ end
100
+
101
+ context 'with required set to false' do
102
+ context 'with_index set to false' do
103
+ context 'with default set' do
104
+ let(:options) do
105
+ {
106
+ indicate_default_message: true,
107
+ with_index: false,
108
+ default: 'two',
109
+ required: false
110
+ }
111
+ end
112
+
113
+ it 'should return the value the user selects' do
114
+ allow(highline).to receive(:ask).and_return(1)
115
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
116
+ expect(resp).to eq({ value: 'one' })
117
+ end
118
+
119
+ it 'should return the default if the user skips' do
120
+ allow(highline).to receive(:ask).and_return(0)
121
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
122
+ expect(resp).to eq({ value: 'two' })
123
+ end
124
+
125
+ it 'should call to return the defaults if the user skips' do
126
+ allow(highline).to receive(:ask).and_return(0)
127
+ expect(subject).to receive(:return_defaults).and_call_original
128
+ expect(subject).to receive(:puts)
129
+ subject.ask(Faker::Lorem.sentence, choices, options)
130
+ end
131
+
132
+ context 'when the indicate_default_message is false' do
133
+ let(:options) do
134
+ {
135
+ indicate_default_message: false,
136
+ with_indexes: false,
137
+ default: 'two',
138
+ required: false
139
+ }
140
+ end
141
+
142
+ it 'should call to return the defaults if the user skips' do
143
+ allow(highline).to receive(:ask).and_return(0)
144
+ expect(subject).to receive(:return_defaults)
145
+ expect(subject).not_to receive(:puts)
146
+ subject.ask(Faker::Lorem.sentence, choices, options)
147
+ end
148
+ end
149
+ end
150
+
151
+ context 'with default nil' do
152
+ let(:options) do
153
+ {
154
+ with_index: false,
155
+ default: nil,
156
+ required: false
157
+ }
158
+ end
159
+
160
+ it 'should return the value the user selects' do
161
+ allow(highline).to receive(:ask).and_return(1)
162
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
163
+ expect(resp).to eq({ value: 'one' })
164
+ end
165
+
166
+ it 'should return nil if the user skips' do
167
+ allow(highline).to receive(:ask).and_return(0)
168
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
169
+ expect(resp).to eq(nil)
170
+ end
171
+ end
172
+ end
173
+
174
+ context 'with_index set to true' do
175
+ context 'with default set' do
176
+ let(:options) do
177
+ {
178
+ with_index: true,
179
+ default: 'two',
180
+ required: false
181
+ }
182
+ end
183
+
184
+ it 'should return the value the user selects' do
185
+ allow(highline).to receive(:ask).and_return(1)
186
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
187
+ expect(resp).to eq({ value: 'one', index: 0 })
188
+ end
189
+
190
+ it 'should return the default if the user skips' do
191
+ allow(highline).to receive(:ask).and_return(0)
192
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
193
+ expect(resp).to eq({ value: 'two', index: 1 })
194
+ end
195
+ end
196
+
197
+ context 'with default nil' do
198
+ let(:options) do
199
+ {
200
+ with_index: true,
201
+ default: nil,
202
+ required: false
203
+ }
204
+ end
205
+
206
+ it 'should return the value the user selects' do
207
+ allow(highline).to receive(:ask).and_return(1)
208
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
209
+ expect(resp).to eq({ value: 'one', index: 0 })
210
+ end
211
+
212
+ it 'should return nil if the user skips' do
213
+ allow(highline).to receive(:ask).and_return(0)
214
+ resp = subject.ask(Faker::Lorem.sentence, choices, options)
215
+ expect(resp).to eq(nil)
216
+ end
217
+
218
+ it 'should call the return empty defaults message' do
219
+ allow(highline).to receive(:ask).and_return(0)
220
+ expect(subject).to receive(:return_empty_defaults)
221
+ subject.ask(Faker::Lorem.sentence, choices, options)
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end