Class: HighLine::Question
- Includes:
- CustomErrors
- Defined in:
- lib/highline/question.rb,
lib/highline/question/answer_converter.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
Defined Under Namespace
Classes: AnswerConverter
Instance Attribute Summary collapse
-
#above ⇒ Object
Used to control range checks for answer.
-
#answer ⇒ Object
The answer, set by HighLine#ask.
-
#answer_type ⇒ Object
The type that will be used to convert this answer.
-
#below ⇒ Object
Used to control range checks for answer.
-
#case ⇒ Object
Used to control character case processing for the answer to this question.
-
#character ⇒ Object
Can be set to
true
to use HighLine’s cross-platform character reader instead of fetching an entire line of input. -
#completion ⇒ Object
For Auto-completion.
-
#confirm ⇒ Object
Asks a yes or no confirmation question, to ensure a user knows what they have just agreed to.
-
#default ⇒ Object
Used to provide a default answer to this question.
-
#default_hint_show ⇒ Object
Set it to a truthy or falsy value to enable or disable showing the default value hint between vertical bars (pipes) when asking the question.
-
#directory ⇒ Object
The directory from which a user will be allowed to select files, when File or Pathname is specified as an answer_type.
-
#echo ⇒ Object
Can be set to
true
orfalse
to control whether or not input will be echoed back to the user. -
#first_answer ⇒ Object
Returns first_answer, which will be unset following this call.
-
#gather ⇒ Object
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.
-
#glob ⇒ Object
The glob pattern used to limit file selection when File or Pathname is specified as an answer_type.
-
#in ⇒ Object
If set, answer must pass an include?() check on this object.
-
#limit ⇒ Object
Allows you to set a character limit for input.
-
#overwrite ⇒ Object
When set to
true
the question is asked, but output does not progress to the next line. -
#readline ⇒ Object
Use the Readline library to fetch input.
-
#template ⇒ Object
The ERb template of the question to be asked.
-
#validate ⇒ Object
If set to a Regexp, the answer must match (before type conversion).
-
#verify_match ⇒ Object
When set to
true
multiple entries will be collected according to the setting for gather, except they will be required to match each other. -
#whitespace ⇒ Object
Used to control whitespace processing for the answer to this question.
Class Method Summary collapse
-
.build(template_or_question, answer_type = nil, &details) ⇒ Question
If template_or_question is already a Question object just return it.
Instance Method Summary collapse
-
#answer_or_default(answer_string) ⇒ String
Returns the provided answer_string or the default answer for this Question if a default was set and the answer is empty.
-
#ask_on_error_msg ⇒ self, String
Provides the String to be asked when at an error situation.
-
#build_responses(message_source = answer_type) ⇒ Hash
Called late in the initialization process to build intelligent responses based on the details of this Question object.
-
#build_responses_new_hash(message_source) ⇒ Hash
When updating the responses hash, it generates the new one.
-
#change_case(answer_string) ⇒ String
Returns the provided answer_string after changing character case by the rules of this Question.
-
#check_range ⇒ Object
Run #in_range? and raise an error if not succesful.
-
#choices_complete(answer_string) ⇒ String
Try to auto complete answer_string.
-
#confirm_question(highline) ⇒ String
Returns the String to be shown when asking for an answer confirmation.
-
#convert ⇒ Object
Transforms the given answer_string into the expected type for this Question.
- #default_responses_hash ⇒ Object
-
#expected_range ⇒ Object
Returns an English explanation of the current range settings.
- #final_response(error) ⇒ Object
-
#final_responses ⇒ Object
This is the actual responses hash that gets used in determining output Notice that we give @user_responses precedence over the responses generated internally via build_response.
-
#first_answer? ⇒ Boolean
Returns true if first_answer is set.
-
#format_answer(answer_string) ⇒ String
Convert to String, remove whitespace and change case when necessary.
-
#get_echo_for_response(response) ⇒ String
Returns an echo string that is adequate for this Question settings.
-
#get_response(highline) ⇒ String
Return a line or character of input, as requested for this question.
-
#get_response_or_default(highline) ⇒ String
Uses #get_response but returns a default answer using #answer_or_default in case no answers was returned.
-
#in_range? ⇒ Boolean
Returns
true
if the answer_object is greater than the above attribute, less than the below attribute and include?()ed in the in attribute. -
#initialize(template, answer_type) {|_self| ... } ⇒ Question
constructor
Create an instance of HighLine::Question.
-
#remove_whitespace(answer_string) ⇒ String
Returns the provided answer_string after processing whitespace by the rules of this Question.
-
#responses ⇒ Object
A Hash that stores the various responses used by HighLine to notify the user.
-
#selection ⇒ Object
Returns an Array of valid answers to this question.
-
#show_question(highline) ⇒ void
readline() needs to handle its own output, but readline only supports full line reading.
-
#to_s ⇒ Object
Stringifies the template to be asked.
-
#valid_answer? ⇒ Boolean
Returns
true
if the provided answer_string is accepted by the validate attribute orfalse
if it’s not.
Constructor Details
#initialize(template, answer_type) {|_self| ... } ⇒ Question
Create an instance of HighLine::Question. Expects a template to ask (can be ""
) and an answer_type to convert the answer to. The answer_type parameter must be a type recognized by Question.convert(). If given, a block is yielded the new Question object to allow custom initialization.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/highline/question.rb', line 52 def initialize(template, answer_type) # initialize instance data @template = String(template).dup @answer_type = answer_type @completion = @answer_type @echo = true @default_hint_show = true @whitespace = :strip @case = nil @in = nil @first_answer = nil @glob = "*" @overwrite = false @user_responses = {} @internal_responses = default_responses_hash @directory = Pathname.new(File.(File.dirname($PROGRAM_NAME))) # allow block to override settings yield self if block_given? # finalize responses based on settings build_responses end |
Instance Attribute Details
#above ⇒ Object
Used to control range checks for answer.
154 155 156 |
# File 'lib/highline/question.rb', line 154 def above @above end |
#answer ⇒ Object
The answer, set by HighLine#ask
81 82 83 |
# File 'lib/highline/question.rb', line 81 def answer @answer end |
#answer_type ⇒ Object
The type that will be used to convert this answer.
84 85 86 |
# File 'lib/highline/question.rb', line 84 def answer_type @answer_type end |
#below ⇒ Object
Used to control range checks for answer.
154 155 156 |
# File 'lib/highline/question.rb', line 154 def below @below end |
#case ⇒ Object
Used to control character case processing for the answer to this question. See HighLine::Question.change_case() for acceptable settings.
137 138 139 |
# File 'lib/highline/question.rb', line 137 def case @case end |
#character ⇒ Object
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.
96 97 98 |
# File 'lib/highline/question.rb', line 96 def character @character end |
#completion ⇒ Object
For Auto-completion
86 87 88 |
# File 'lib/highline/question.rb', line 86 def completion @completion end |
#confirm ⇒ Object
Asks a yes or no confirmation question, to ensure a user knows what they have just agreed to. The confirm attribute can be set to : true
: In this case the question will be, “Are you sure?”. Proc : The Proc is yielded the answer given. The Proc must
output a string which is then used as the confirm
question.
String : The String must use ERB syntax. The String is
evaluated with access to question and answer and
is then used as the confirm question.
When set to false
or nil
(the default), answers are not confirmed.
168 169 170 |
# File 'lib/highline/question.rb', line 168 def confirm @confirm end |
#default ⇒ Object
Used to provide a default answer to this question.
139 140 141 |
# File 'lib/highline/question.rb', line 139 def default @default end |
#default_hint_show ⇒ Object
Set it to a truthy or falsy value to enable or disable showing the default value hint between vertical bars (pipes) when asking the question. Defaults to true
143 144 145 |
# File 'lib/highline/question.rb', line 143 def default_hint_show @default_hint_show end |
#directory ⇒ Object
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)))
.
201 202 203 |
# File 'lib/highline/question.rb', line 201 def directory @directory end |
#echo ⇒ Object
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 a 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).
117 118 119 |
# File 'lib/highline/question.rb', line 117 def echo @echo end |
#first_answer ⇒ Object
Returns first_answer, which will be unset following this call.
405 406 407 408 409 |
# File 'lib/highline/question.rb', line 405 def first_answer @first_answer ensure @first_answer = nil end |
#gather ⇒ Object
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.
182 183 184 |
# File 'lib/highline/question.rb', line 182 def gather @gather end |
#glob ⇒ Object
The glob pattern used to limit file selection when File or Pathname is specified as an answer_type. Initially set to "*"
.
206 207 208 |
# File 'lib/highline/question.rb', line 206 def glob @glob end |
#in ⇒ Object
If set, answer must pass an include?() check on this object.
156 157 158 |
# File 'lib/highline/question.rb', line 156 def in @in end |
#limit ⇒ Object
Allows you to set a character limit for input.
WARNING: This option forces a character by character read.
102 103 104 |
# File 'lib/highline/question.rb', line 102 def limit @limit end |
#overwrite ⇒ Object
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.
240 241 242 |
# File 'lib/highline/question.rb', line 240 def overwrite @overwrite end |
#readline ⇒ Object
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.
127 128 129 |
# File 'lib/highline/question.rb', line 127 def readline @readline end |
#template ⇒ Object
The ERb template of the question to be asked.
78 79 80 |
# File 'lib/highline/question.rb', line 78 def template @template end |
#validate ⇒ Object
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. It’s possible to use a custom validator class. It must respond to ‘#valid?`. The result of `#inspect` will be used in error messages. See README.md for details.
152 153 154 |
# File 'lib/highline/question.rb', line 152 def validate @validate end |
#verify_match ⇒ Object
When set to true
multiple entries will be collected according to the setting for gather, except they will be required to match each other. Multiple identical entries will return a single answer.
188 189 190 |
# File 'lib/highline/question.rb', line 188 def verify_match @verify_match end |
#whitespace ⇒ Object
Used to control whitespace processing for the answer to this question. See HighLine::Question.remove_whitespace() for acceptable settings.
132 133 134 |
# File 'lib/highline/question.rb', line 132 def whitespace @whitespace end |
Class Method Details
.build(template_or_question, answer_type = nil, &details) ⇒ Question
If template_or_question is already a Question object just return it. If not, build it.
35 36 37 38 39 40 41 |
# File 'lib/highline/question.rb', line 35 def self.build(template_or_question, answer_type = nil, &details) if template_or_question.is_a? Question template_or_question else Question.new(template_or_question, answer_type, &details) end end |
Instance Method Details
#answer_or_default(answer_string) ⇒ String
Returns the provided answer_string or the default answer for this Question if a default was set and the answer is empty.
248 249 250 251 |
# File 'lib/highline/question.rb', line 248 def answer_or_default(answer_string) return default if answer_string.empty? && default answer_string end |
#ask_on_error_msg ⇒ self, String
Provides the String to be asked when at an error situation. It may be just the question itself (repeat on error).
575 576 577 578 579 580 581 |
# File 'lib/highline/question.rb', line 575 def ask_on_error_msg if final_responses[:ask_on_error] == :question self elsif final_responses[:ask_on_error] final_responses[:ask_on_error] end end |
#build_responses(message_source = answer_type) ⇒ Hash
Called late in the initialization process to build intelligent responses based on the details of this Question object. Also used by Menu#update_responses.
262 263 264 265 266 267 268 269 |
# File 'lib/highline/question.rb', line 262 def build_responses( = answer_type) append_default_to_template if default_hint_show new_hash = build_responses_new_hash() # Update our internal responses with the new hash # generated from the message source @internal_responses = @internal_responses.merge(new_hash) end |
#build_responses_new_hash(message_source) ⇒ Hash
When updating the responses hash, it generates the new one.
281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/highline/question.rb', line 281 def build_responses_new_hash() { ambiguous_completion: "Ambiguous choice. Please choose one of " + choice_error_str() + ".", invalid_type: "You must enter a valid #{}.", no_completion: "You must choose one of " + choice_error_str() + ".", not_in_range: "Your answer isn't within the expected range " \ "(#{expected_range}).", not_valid: "Your answer isn't valid (must match " \ "#{validate.inspect})." } end |
#change_case(answer_string) ⇒ String
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
.
326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/highline/question.rb', line 326 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 |
#check_range ⇒ Object
Run #in_range? and raise an error if not succesful
372 373 374 |
# File 'lib/highline/question.rb', line 372 def check_range raise NotInRangeQuestionError unless in_range? end |
#choices_complete(answer_string) ⇒ String
Try to auto complete answer_string
379 380 381 382 383 384 385 386 |
# File 'lib/highline/question.rb', line 379 def choices_complete(answer_string) # cheating, using OptionParser's Completion module choices = selection choices.extend(OptionParser::Completion) answer = choices.complete(answer_string) raise NoAutoCompleteMatch unless answer answer end |
#confirm_question(highline) ⇒ String
Returns the String to be shown when asking for an answer confirmation.
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'lib/highline/question.rb', line 552 def confirm_question(highline) if confirm == true "Are you sure? " elsif confirm.is_a?(Proc) confirm.call(answer) else # evaluate ERb under initial scope, so it will have # access to question and answer template = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+ ERB.new(confirm, trim_mode: "%") else ERB.new(confirm, nil, "%") end template_renderer = TemplateRenderer.new(template, self, highline) template_renderer.render end end |
#convert ⇒ 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.
- File
-
The entered file name is auto-completed in terms of directory + glob, opened, and returned.
- Float
-
Answer is converted with Kernel.Float().
- Integer
-
Answer is converted with Kernel.Integer().
nil
-
Answer is left in String format. (Default.)
- Pathname
-
Same as File, save that a Pathname object is returned.
- String
-
Answer is converted with Kernel.String().
- HighLine::String
-
Answer is converted with HighLine::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.
367 368 369 |
# File 'lib/highline/question.rb', line 367 def convert AnswerConverter.new(self).convert end |
#default_responses_hash ⇒ Object
271 272 273 274 275 276 |
# File 'lib/highline/question.rb', line 271 def default_responses_hash { ask_on_error: "? ", mismatch: "Your entries didn't match." } end |
#expected_range ⇒ Object
Returns an English explanation of the current range settings.
389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/highline/question.rb', line 389 def expected_range expected = [] expected << "above #{above}" if above expected << "below #{below}" if below expected << "included in #{@in.inspect}" if @in 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 |
#final_response(error) ⇒ Object
300 301 302 303 304 305 306 307 |
# File 'lib/highline/question.rb', line 300 def final_response(error) response = final_responses[error] if response.respond_to?(:call) response.call(answer) else response end end |
#final_responses ⇒ Object
This is the actual responses hash that gets used in determining output Notice that we give @user_responses precedence over the responses generated internally via build_response
296 297 298 |
# File 'lib/highline/question.rb', line 296 def final_responses @internal_responses.merge(@user_responses) end |
#first_answer? ⇒ Boolean
Returns true if first_answer is set.
412 413 414 |
# File 'lib/highline/question.rb', line 412 def first_answer? true if @first_answer end |
#format_answer(answer_string) ⇒ String
Convert to String, remove whitespace and change case when necessary
470 471 472 473 474 |
# File 'lib/highline/question.rb', line 470 def format_answer(answer_string) answer_string = String(answer_string) answer_string = remove_whitespace(answer_string) change_case(answer_string) end |
#get_echo_for_response(response) ⇒ String
Returns an echo string that is adequate for this Question settings.
599 600 601 602 603 604 605 606 607 608 609 610 |
# File 'lib/highline/question.rb', line 599 def get_echo_for_response(response) # actually true, not only truethy value if echo == true response # any truethy value, probably a String elsif echo echo # any falsy value, false or nil else "" end end |
#get_response(highline) ⇒ String
Return a line or character of input, as requested for this question. Character input will be returned as a single character String, not an Integer.
This question’s first_answer will be returned instead of input, if set.
Raises EOFError if input is exhausted.
524 525 526 527 528 529 530 531 532 533 534 535 |
# File 'lib/highline/question.rb', line 524 def get_response(highline) return first_answer if first_answer? case character when :getc highline.get_response_getc_mode(self) when true highline.get_response_character_mode(self) else highline.get_response_line_mode(self) end end |
#get_response_or_default(highline) ⇒ String
Uses #get_response but returns a default answer using #answer_or_default in case no answers was returned.
544 545 546 |
# File 'lib/highline/question.rb', line 544 def get_response_or_default(highline) self.answer = answer_or_default(get_response(highline)) end |
#in_range? ⇒ Boolean
Returns true
if the answer_object is greater than the above attribute, less than the below attribute and include?()ed in the in attribute. Otherwise, false
is returned. Any nil
attributes are not checked.
422 423 424 425 426 |
# File 'lib/highline/question.rb', line 422 def in_range? (!above || answer > above) && (!below || answer < below) && (!@in || @in.include?(answer)) end |
#remove_whitespace(answer_string) ⇒ String
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 whitespace runs to a single space.
:strip_and_collapse
-
Calls strip(), then collapses all whitespace runs to a single space.
:chomp_and_collapse
-
Calls chomp(), then collapses all whitespace 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.
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
# File 'lib/highline/question.rb', line 449 def remove_whitespace(answer_string) if !whitespace 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 |
#responses ⇒ Object
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.
231 232 233 |
# File 'lib/highline/question.rb', line 231 def responses @user_responses end |
#selection ⇒ Object
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.
481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/highline/question.rb', line 481 def selection if completion.is_a?(Array) completion elsif [File, Pathname].include?(completion) Dir[File.join(directory.to_s, glob)].map do |file| File.basename(file) end else [] end end |
#show_question(highline) ⇒ void
This method returns an undefined value.
readline() needs to handle its own output, but readline only supports full line reading. Therefore if question.echo is anything but true, the prompt will not be issued. And we have to account for that now. Also, JRuby-1.7’s ConsoleReader.readLine() needs to be passed the prompt to handle line editing properly.
590 591 592 |
# File 'lib/highline/question.rb', line 590 def show_question(highline) highline.say(self) end |
#to_s ⇒ Object
Stringifies the template to be asked.
494 495 496 |
# File 'lib/highline/question.rb', line 494 def to_s template end |
#valid_answer? ⇒ 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.
505 506 507 508 509 510 |
# File 'lib/highline/question.rb', line 505 def valid_answer? !validate || (validate.is_a?(Regexp) && answer =~ validate) || (validate.is_a?(Proc) && validate[answer]) || (validate.respond_to?(:valid?) && validate.valid?(answer)) end |