highline_wrapper 0.1.0 → 1.2.2

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.
@@ -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