Class: HighLine::Question

Inherits:
Object
  • Object
show all
Defined in:
lib/highline/question.rb

Overview

Question objects contain all the details of a single invocation of HighLine.ask(). The object is initialized by the parameters passed to HighLine.ask() and then queried to make sure each step of the input process is handled according to the users wishes.

Direct Known Subclasses

Menu

Defined Under Namespace

Classes: NoAutoCompleteMatch

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(question, answer_type) {|_self| ... } ⇒ Question

Create an instance of HighLine::Question. Expects a question to ask (can be "") and an answer_type to convert the answer to. The answer_type parameter must be a type recongnized by Question.convert(). If given, a block is yeilded the new Question object to allow custom initializaion.

Yields:

  • (_self)

Yield Parameters:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/highline/question.rb', line 31

def initialize( question, answer_type )
	# initialize instance data
	@question    = question
	@answer_type = answer_type
	
	@character    = nil
	@echo         = true
	@whitespace   = :strip
	@case         = nil
	@default      = nil
	@validate     = nil
	@above        = nil
	@below        = nil
	@in           = nil
	@confirm      = nil
	@responses    = Hash.new
	
	# allow block to override settings
	yield self if block_given?

	# finalize responses based on settings
	build_responses
end

Instance Attribute Details

#aboveObject

Used to control range checks for answer.



96
97
98
# File 'lib/highline/question.rb', line 96

def above
  @above
end

#answer_typeObject

The type that will be used to convert this answer.



56
57
58
# File 'lib/highline/question.rb', line 56

def answer_type
  @answer_type
end

#belowObject

Used to control range checks for answer.



96
97
98
# File 'lib/highline/question.rb', line 96

def below
  @below
end

#caseObject

Used to control whitespace processing for the answer to this question. See HighLine::Question.change_case() for acceptable settings.



86
87
88
# File 'lib/highline/question.rb', line 86

def case
  @case
end

#characterObject

Can be set to true to use HighLine’s cross-platform character reader instead of fetching an entire line of input. (Note: HighLine’s character reader ONLY supports STDIN on Windows and Unix.) Can also be set to :getc to use that method on the input stream.

WARNING: The echo attribute for a question is ignored when using thw :getc method.



66
67
68
# File 'lib/highline/question.rb', line 66

def character
  @character
end

#confirmObject

Asks a yes or no confirmation question, to ensure a user knows what they have just agreed to. If set to true the question will be, “Are you sure? ” Any other true value for this attribute is assumed to be the question to ask. When false or nil (the default), answers are not confirmed.



106
107
108
# File 'lib/highline/question.rb', line 106

def confirm
  @confirm
end

#defaultObject

Used to provide a default answer to this question.



88
89
90
# File 'lib/highline/question.rb', line 88

def default
  @default
end

#echoObject

Can be set to true or false to control whether or not input will be echoed back to the user. A setting of true will cause echo to match input, but any other true value will be treated as to String to echo for each character typed.

This requires HighLine’s character reader. See the character attribute for details.



76
77
78
# File 'lib/highline/question.rb', line 76

def echo
  @echo
end

#inObject

If set, answer must pass an include?() check on this object.



98
99
100
# File 'lib/highline/question.rb', line 98

def in
  @in
end

#responsesObject (readonly)

A Hash that stores the various responses used by HighLine to notify the user. The currently used responses and their purpose are as follows:

:ambiguous_completion

Used to notify the user of an ambiguous answer the auto-completion system cannot resolve.

:ask_on_error

This is the question that will be redisplayed to the user in the event of an error. Can be set to :question to repeat the original question.

:invalid_type

The error message shown when a type conversion fails.

:no_completion

Used to notify the user that their selection does not have a valid auto-completion match.

:not_in_range

Used to notify the user that a provided answer did not satisfy the range requirement tests.

:not_valid

The error message shown when validation checks fail.



131
132
133
# File 'lib/highline/question.rb', line 131

def responses
  @responses
end

#validateObject

If set to a Regexp, the answer must match (before type conversion). Can also be set to a Proc which will be called with the provided answer to validate with a true or false return.



94
95
96
# File 'lib/highline/question.rb', line 94

def validate
  @validate
end

#whitespaceObject

Used to control whitespace processing for the answer to this question. See HighLine::Question.remove_whitespace() for acceptable settings.



81
82
83
# File 'lib/highline/question.rb', line 81

def whitespace
  @whitespace
end

Instance Method Details

#answer_or_default(answer_string) ⇒ Object

Returns the provided answer_string or the default answer for this Question if a default was set and the answer is empty.



137
138
139
140
141
142
143
# File 'lib/highline/question.rb', line 137

def answer_or_default( answer_string )
	if answer_string.length == 0 and not @default.nil?
		@default
	else
		answer_string
	end
end

#build_responsesObject

Called late in the initialization process to build intelligent responses based on the details of this Question object.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/highline/question.rb', line 149

def build_responses(  )
	### WARNING:  This code is quasi-duplicated in     ###
	### Menu.update_responses().  Check their too when ###
	### making changes!                                ###
	append_default unless default.nil?
	@responses = { :ambiguous_completion =>
	                   "Ambiguous choice.  " +
	                   "Please choose one of #{@answer_type.inspect}.",
	               :ask_on_error         =>
	                   "?  ",
	               :invalid_type         =>
	                   "You must enter a valid #{@answer_type}.",
	               :no_completion        =>
	                   "You must choose one of " +
	                   "#{@answer_type.inspect}.",
	               :not_in_range         =>
	                   "Your answer isn't within the expected range " +
	                   "(#{expected_range}).",
	               :not_valid            =>
	                   "Your answer isn't valid (must match " +
	                   "#{@validate.inspect})." }.merge(@responses)
	### WARNING:  This code is quasi-duplicated in     ###
	### Menu.update_responses().  Check their too when ###
	### making changes!                                ###
end

#change_case(answer_string) ⇒ Object

Returns the provided answer_string after changing character case by the rules of this Question. Valid settings for whitespace are:

nil

Do not alter character case. (Default.)

:up

Calls upcase().

:upcase

Calls upcase().

:down

Calls downcase().

:downcase

Calls downcase().

:capitalize

Calls capitalize().

An unrecognized choice (like :none) is treated as nil.



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/highline/question.rb', line 189

def change_case( answer_string )
	if [:up, :upcase].include?(@case)
		answer_string.upcase
	elsif [:down, :downcase].include?(@case)
		answer_string.downcase
	elsif @case == :capitalize
		answer_string.capitalize
	else
		answer_string
	end
end

#convert(answer_string) ⇒ Object

Transforms the given answer_string into the expected type for this Question. Currently supported conversions are:

[...]

Answer must be a member of the passed Array. Auto-completion is used to expand partial answers.

lambda {...}

Answer is passed to lambda for conversion.

Date

Date.parse() is called with answer.

DateTime

DateTime.parse() is called with answer.

Float

Answer is converted with Kernel.Float().

Integer

Answer is converted with Kernel.Integer().

nil

Answer is left in String format. (Default.)

String

Answer is converted with Kernel.String().

Regexp

Answer is fed to Regexp.new().

Symbol

The method to_sym() is called on answer and the result returned.

any other Class

The answer is passed on to Class.parse().

This method throws ArgumentError, if the conversion cannot be completed for any reason.



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/highline/question.rb', line 224

def convert( answer_string )
	if @answer_type.nil?
		answer_string
	elsif [Float, Integer, String].include?(@answer_type)
		Kernel.send(@answer_type.to_s.to_sym, answer_string)
	elsif @answer_type == Symbol
		answer_string.to_sym
	elsif @answer_type == Regexp
		Regexp.new(answer_string)
	elsif @answer_type.is_a?(Array)
		# cheating, using OptionParser's Completion module
		@answer_type.extend(OptionParser::Completion)
		answer = @answer_type.complete(answer_string)
		if answer.nil?
			raise NoAutoCompleteMatch
		end
		answer.last
	elsif [Date, DateTime].include?(@answer_type) or
	      @answer_type.is_a?(Class)
		@answer_type.parse(answer_string)
	elsif @answer_type.is_a?(Proc)
		@answer_type[answer_string]
	end
end

#expected_rangeObject

Returns a english explination of the current range settings.



250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/highline/question.rb', line 250

def expected_range(  )
	expected = [ ]

	expected << "above #{@above}" unless @above.nil?
	expected << "below #{@below}" unless @below.nil?
	expected << "included in #{@in.inspect}" unless @in.nil?

	case expected.size
	when 0 then ""
	when 1 then expected.first
	when 2 then expected.join(" and ")
	else        expected[0..-2].join(", ") + ", and #{expected.last}"
	end
end

#in_range?(answer_object) ⇒ Boolean

Returns true if the answer_object is greater than the above attribute, less than the below attribute and included?()ed in the in attribute. Otherwise, false is returned. Any nil attributes are not checked.

Returns:

  • (Boolean)


271
272
273
274
275
# File 'lib/highline/question.rb', line 271

def in_range?( answer_object )
	(@above.nil? or answer_object > @above) and
	(@below.nil? or answer_object < @below) and
	(@in.nil? or @in.include?(answer_object))
end

#remove_whitespace(answer_string) ⇒ Object

Returns the provided answer_string after processing whitespace by the rules of this Question. Valid settings for whitespace are:

nil

Do not alter whitespace.

:strip

Calls strip(). (Default.)

:chomp

Calls chomp().

:collapse

Collapses all whitspace runs to a single space.

:strip_and_collapse

Calls strip(), then collapses all whitspace runs to a single space.

:chomp_and_collapse

Calls chomp(), then collapses all whitspace runs to a single space.

:remove

Removes all whitespace.

An unrecognized choice (like :none) is treated as nil.

This process is skipped, for single character input.



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/highline/question.rb', line 296

def remove_whitespace( answer_string )
	if @whitespace.nil?
		answer_string
	elsif [:strip, :chomp].include?(@whitespace)
		answer_string.send(@whitespace)
	elsif @whitespace == :collapse
		answer_string.gsub(/\s+/, " ")
	elsif [ :strip_and_collapse,
	        :chomp_and_collapse ].include?(@whitespace)
		result = answer_string.send(@whitespace.to_s[/^[a-z]+/])
		result.gsub(/\s+/, " ")
	elsif @whitespace == :remove
		answer_string.gsub(/\s+/, "")
	else
		answer_string
	end
end

#to_strObject

Stringifies the question to be asked.



315
316
317
# File 'lib/highline/question.rb', line 315

def to_str(  )
	@question
end

#valid_answer?(answer_string) ⇒ Boolean

Returns true if the provided answer_string is accepted by the validate attribute or false if it’s not.

It’s important to realize that an answer is validated after whitespace and case handling.

Returns:

  • (Boolean)


326
327
328
329
330
# File 'lib/highline/question.rb', line 326

def valid_answer?( answer_string )
	@validate.nil? or 
	(@validate.is_a?(Regexp) and answer_string =~ @validate) or
	(@validate.is_a?(Proc)   and @validate[answer_string])
end