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.
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class HighlineWrapper
4
- VERSION = '0.1.0'
4
+ VERSION = '1.0.0'
5
5
  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