highline_wrapper 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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