blob: 52f495942c065e98a4fc08bce39fa29951576240 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
# encoding: utf-8
class HighLine
# Deals with the task of "asking" a question
class QuestionAsker
# @return [Question] question to be asked
attr_reader :question
include CustomErrors
# To do its work QuestionAsker needs a Question
# to be asked and a HighLine context where to
# direct output.
#
# @param question [Question] question to be asked
# @param highline [HighLine] context
def initialize(question, highline)
@question = question
@highline = highline
end
#
# Gets just one answer, as opposed to #gather_answers
#
# @return [String] answer
def ask_once
question.show_question(@highline)
begin
question.get_response_or_default(@highline)
raise NotValidQuestionError unless question.valid_answer?
question.convert
if question.confirm
confirmation = @highline.send(:confirm, question)
raise NoConfirmationQuestionError unless confirmation
end
rescue ExplainableError => e
explain_error(e.explanation_key)
retry
rescue ArgumentError => error
case error.message
when /ambiguous/
# the assumption here is that OptionParser::Completion#complete
# (used for ambiguity resolution) throws exceptions containing
# the word 'ambiguous' whenever resolution fails
explain_error(:ambiguous_completion)
retry
when /invalid value for/
explain_error(:invalid_type)
retry
else
raise
end
end
question.answer
end
## Multiple questions
#
# Collects an Array/Hash full of answers as described in
# HighLine::Question.gather().
#
# @return [Array, Hash] answers
def gather_answers
verify_match = question.verify_match
answers = []
# when verify_match is set this loop will repeat until unique_answers == 1
loop do
answers = gather_answers_based_on_type
break unless verify_match &&
(@highline.send(:unique_answers, answers).size > 1)
explain_error(:mismatch)
end
verify_match ? @highline.send(:last_answer, answers) : answers
end
# Gather multiple integer values based on {Question#gather} count
# @return [Array] answers
def gather_integer
gather_with_array do |answers|
(question.gather - 1).times { answers << ask_once }
end
end
# Gather multiple values until any of them matches the
# {Question#gather} Regexp.
# @return [Array] answers
def gather_regexp
gather_with_array do |answers|
answers << ask_once until answer_matches_regex(answers.last)
answers.pop
end
end
# Gather multiple values and store them on a Hash
# with keys provided by the Hash on {Question#gather}
# @return [Hash]
def gather_hash
sorted_keys = question.gather.keys.sort_by(&:to_s)
sorted_keys.each_with_object({}) do |key, answers|
@highline.key = key
answers[key] = ask_once
end
end
private
## Delegate to Highline
def explain_error(error)
@highline.say(error_final_response(error)) if error
@highline.say(question.ask_on_error_msg)
end
def error_final_response(error)
final_response = question.final_responses[error]
final_response.call(question.answer) rescue final_response
end
def gather_with_array
[].tap do |answers|
answers << ask_once
question.template = ""
yield answers
end
end
def answer_matches_regex(answer)
if question.gather.is_a?(::String) || question.gather.is_a?(Symbol)
answer.to_s == question.gather.to_s
elsif question.gather.is_a?(Regexp)
answer.to_s =~ question.gather
end
end
def gather_answers_based_on_type
case question.gather
when Integer
gather_integer
when ::String, Symbol, Regexp
gather_regexp
when Hash
gather_hash
end
end
end
end
|