Class: HighLine::Question

Inherits:
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, NotEnoughAnswers

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:



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
# File 'lib/highline/question.rb', line 38

def initialize( question, answer_type )
  # initialize instance data
  @question    = question
  @answer_type = answer_type

  @many_answers = nil
  @at_least     = 1
  @character    = nil
  @limit        = nil
  @echo         = true
  @readline     = false
  @whitespace   = :strip
  @case         = nil
  @default      = nil
  @validate     = nil
  @above        = nil
  @below        = nil
  @in           = nil
  @confirm      = nil
  @gather       = false
  @first_answer = nil
  @directory    = Pathname.new(File.expand_path(File.dirname($0)))
  @glob         = "*"
  @responses    = Hash.new
  @overwrite    = false
  
  # 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.



146
147
148
# File 'lib/highline/question.rb', line 146

def above
  @above
end

#answer_typeObject

The type that will be used to convert this answer.



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

def answer_type
  @answer_type
end

#at_leastObject

Allows you to set a character limit for input.



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

def at_least
  @at_least
end

#belowObject

Used to control range checks for answer.



146
147
148
# File 'lib/highline/question.rb', line 146

def below
  @below
end

#caseObject

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



136
137
138
# File 'lib/highline/question.rb', line 136

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 and overwrite attributes for a question are ignored when using the :getc method.



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

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.



156
157
158
# File 'lib/highline/question.rb', line 156

def confirm
  @confirm
end

#defaultObject

Used to provide a default answer to this question.



138
139
140
# File 'lib/highline/question.rb', line 138

def default
  @default
end

#directoryObject

The directory from which a user will be allowed to select files, when File or Pathname is specified as an answer_type. Initially set to Pathname.new(File.expand_path(File.dirname($0))).



183
184
185
# File 'lib/highline/question.rb', line 183

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

Note: When using HighLine to manage echo on Unix based systems, we recommend installing the termios gem. Without it, it’s possible to type fast enough to have letters still show up (when reading character by character only).



116
117
118
# File 'lib/highline/question.rb', line 116

def echo
  @echo
end

#first_answerObject

Returns first_answer, which will be unset following this call.



324
325
326
327
328
# File 'lib/highline/question.rb', line 324

def first_answer( )
  @first_answer
ensure
  @first_answer = nil
end

#gatherObject

When set, the user will be prompted for multiple answers which will be collected into an Array or Hash and returned as the final answer.

You can set gather to an Integer to have an Array of exactly that many answers collected, or a String/Regexp to match an end input which will not be returned in the Array.

Optionally gather can be set to a Hash. In this case, the question will be asked once for each key and the answers will be returned in a Hash, mapped by key. The @key variable is set before each question is evaluated, so you can use it in your question.



170
171
172
# File 'lib/highline/question.rb', line 170

def gather
  @gather
end

#globObject

The glob pattern used to limit file selection when File or Pathname is specified as an answer_type. Initially set to "*".



188
189
190
# File 'lib/highline/question.rb', line 188

def glob
  @glob
end

#inObject

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



148
149
150
# File 'lib/highline/question.rb', line 148

def in
  @in
end

#limitObject

Specify minimum number of answers that user has to give. It should be used only with :many_answers = true



101
102
103
# File 'lib/highline/question.rb', line 101

def limit
  @limit
end

#many_answersObject

Allows you to read many answers

WARNING: This option forces a character by character read.



92
93
94
# File 'lib/highline/question.rb', line 92

def many_answers
  @many_answers
end

#overwriteObject

When set to true the question is asked, but output does not progress to the next line. The Cursor is moved back to the beginning of the question line and it is cleared so that all the contents of the line disappear from the screen.



220
221
222
# File 'lib/highline/question.rb', line 220

def overwrite
  @overwrite
end

#questionObject

The ERb template of the question to be asked.



73
74
75
# File 'lib/highline/question.rb', line 73

def question
  @question
end

#readlineObject

Use the Readline library to fetch input. This allows input editing as well as keeping a history. In addition, tab will auto-complete within an Array of choices or a file listing.

WARNING: This option is incompatible with all of HighLine’s character reading modes and it causes HighLine to ignore the specified input stream.



126
127
128
# File 'lib/highline/question.rb', line 126

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



213
214
215
# File 'lib/highline/question.rb', line 213

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.



144
145
146
# File 'lib/highline/question.rb', line 144

def validate
  @validate
end

#whitespaceObject

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



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

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.



226
227
228
229
230
231
232
# File 'lib/highline/question.rb', line 226

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.



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/highline/question.rb', line 238

def build_responses(  )
  ### WARNING:  This code is quasi-duplicated in     ###
  ### Menu.update_responses().  Check there too when ###
  ### making changes!                                ###
  append_default unless default.nil?
  @responses = { :ambiguous_completion =>
                   "Ambiguous choice.  " +
                   "Please choose from #{@answer_type.inspect}.",
                 :ask_on_error         =>
                   "?  ",
                 :invalid_type         =>
                   "You must enter a valid #{@answer_type}.",
                 :no_completion        =>
                   "You must choose from " +
                   "#{@answer_type.inspect}.",
                 :not_enough_answers  =>
                   "You must give at least #{@at_least} answers",
                 :not_in_range         =>
                   "Your answer isn't within the expected range " +
                   "(#{expected_range}).",
                 :not_valid            =>
                   "Your answer isn't valid" + (@validate.is_a?(Regexp) ? " (must match #{@validate.inspect})." : "") }.merge(@responses)
  ### WARNING:  This code is quasi-duplicated in     ###
  ### Menu.update_responses().  Check there 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.



279
280
281
282
283
284
285
286
287
288
289
# File 'lib/highline/question.rb', line 279

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

This method converts answers to proper type



292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/highline/question.rb', line 292

def convert( answer_string )
  if @many_answers
    answer = []
    answer_string.split.each do | single_answer |
      answer << convert_single_answer(single_answer)
    end
    if answer.size < @at_least
      raise NotEnoughAnswers
    end
  else
    answer = convert_single_answer(answer_string)
  end
  answer        
end

#expected_rangeObject

Returns a english explination of the current range settings.



308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/highline/question.rb', line 308

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

#first_answer?Boolean

Returns true if first_answer is set.

Returns:

  • (Boolean)


331
332
333
# File 'lib/highline/question.rb', line 331

def first_answer?( )
  not @first_answer.nil?
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)


341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/highline/question.rb', line 341

def in_range?( answer_object )
  if !@many_answers
    answer_object = [answer_object]
  end
  answer_object.each do | single_answer_object |
    return false unless
      (@above.nil? or single_answer_object > @above) and
      (@below.nil? or single_answer_object < @below) and
      (@in.nil? or @in.include?(single_answer_object))
  end
  return true
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.



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/highline/question.rb', line 373

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

#selectionObject

Returns an Array of valid answers to this question. These answers are only known when answer_type is set to an Array of choices, File, or Pathname. Any other time, this method will return an empty Array.



395
396
397
398
399
400
401
402
403
404
405
# File 'lib/highline/question.rb', line 395

def selection(  )
  if @answer_type.is_a?(Array)
    @answer_type
  elsif [File, Pathname].include?(@answer_type)
    Dir[File.join(@directory.to_s, @glob)].map do |file|
      File.basename(file)
    end
  else
    [ ]
  end      
end

#to_strObject

Stringifies the question to be asked.



408
409
410
# File 'lib/highline/question.rb', line 408

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)


419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/highline/question.rb', line 419

def valid_answer?( answer_string )
  return true if @validate.nil?
  answers = []
  if @many_answers
    answers = answer_string.split
  else
    answers << answer_string
  end
  answers.each do |single_answer_string|
    return false unless 
      (@validate.is_a?(Regexp) and single_answer_string =~ @validate) or
      (@validate.is_a?(Proc)   and @validate[single_answer_string])
  end
  return true
end