Class: TTY::Prompt::Question

Inherits:
Object
  • Object
show all
Includes:
Checks
Defined in:
lib/tty/prompt/question.rb,
lib/tty/prompt/question/checks.rb,
lib/tty/prompt/question/modifier.rb,
lib/tty/prompt/question/validation.rb

Overview

A class responsible for gathering user input

Direct Known Subclasses

ConfirmQuestion, Keypress, MaskQuestion, Multiline

Defined Under Namespace

Modules: Checks Classes: Modifier, Validation

Constant Summary collapse

UndefinedSetting =
Class.new do
  def to_s
    "undefined"
  end
  alias_method :inspect, :to_s
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(prompt, **options) ⇒ Question

Initialize a Question


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
# File 'lib/tty/prompt/question.rb', line 37

def initialize(prompt, **options)
  # Option deprecation
  if options[:validation]
    warn "[DEPRECATION] The `:validation` option is deprecated. Use `:validate` instead."
    options[:validate] = options[:validation]
  end

  @prompt       = prompt
  @prefix       = options.fetch(:prefix) { @prompt.prefix }
  @default      = options.fetch(:default) { UndefinedSetting }
  @required     = options.fetch(:required) { false }
  @echo         = options.fetch(:echo) { true }
  @in           = options.fetch(:in) { UndefinedSetting }
  @modifier     = options.fetch(:modifier) { [] }
  @validation   = options.fetch(:validate) { UndefinedSetting }
  @convert      = options.fetch(:convert) { UndefinedSetting }
  @active_color = options.fetch(:active_color) { @prompt.active_color }
  @help_color   = options.fetch(:help_color) { @prompt.help_color }
  @error_color  = options.fetch(:error_color) { :red }
  @value        = options.fetch(:value) { UndefinedSetting }
  @quiet        = options.fetch(:quiet) { @prompt.quiet }
  @messages     = Utils.deep_copy(options.fetch(:messages) { { } })
  @done         = false
  @first_render = true
  @input        = nil

  @evaluator = Evaluator.new(self)

  @evaluator << CheckRequired
  @evaluator << CheckDefault
  @evaluator << CheckRange
  @evaluator << CheckValidation
  @evaluator << CheckModifier
  @evaluator << CheckConversion
end

Instance Attribute Details

#messageObject (readonly)

Store question message


28
29
30
# File 'lib/tty/prompt/question.rb', line 28

def message
  @message
end

#messagesObject (readonly)

Stores all the error messages displayed to user The currently supported messages are:

* :range?
* :required?
* :valid?

78
79
80
# File 'lib/tty/prompt/question.rb', line 78

def messages
  @messages
end

#modifierObject (readonly)


30
31
32
# File 'lib/tty/prompt/question.rb', line 30

def modifier
  @modifier
end

#validationObject (readonly)


32
33
34
# File 'lib/tty/prompt/question.rb', line 32

def validation
  @validation
end

Instance Method Details

#call(message = "", &block) ⇒ self

Call the question

Parameters:

  • message (String) (defaults to: "")

Returns:

  • (self)

107
108
109
110
111
112
113
# File 'lib/tty/prompt/question.rb', line 107

def call(message = "", &block)
  @message = message
  block.call(self) if block
  @prompt.subscribe(self) do
    render
  end
end

#convert(value = (not_set = true), message = nil) ⇒ Object

Specify answer conversion


237
238
239
240
241
242
243
244
# File 'lib/tty/prompt/question.rb', line 237

def convert(value = (not_set = true), message = nil)
  messages[:convert?] = message if message
  if not_set
    @convert
  else
    @convert = value
  end
end

#convert?Boolean

Check if conversion is set

Returns:

  • (Boolean)

251
252
253
# File 'lib/tty/prompt/question.rb', line 251

def convert?
  @convert != UndefinedSetting
end

#convert_result(value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Convert value to expected type

Parameters:

  • value (Object)

221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/tty/prompt/question.rb', line 221

def convert_result(value)
  if convert? && !Utils.blank?(value)
    case @convert
    when Proc
      @convert.call(value)
    else
      Converters.convert(@convert, value)
    end
  else
    value
  end
end

#default(value = (not_set = true)) ⇒ Object

Set default value.


258
259
260
261
# File 'lib/tty/prompt/question.rb', line 258

def default(value = (not_set = true))
  return @default if not_set
  @default = value
end

#default?Boolean

Check if default value is set

Returns:

  • (Boolean)

268
269
270
# File 'lib/tty/prompt/question.rb', line 268

def default?
  @default != UndefinedSetting
end

#echo(value = nil) ⇒ Object Also known as: echo?

Turn terminal echo on or off. This is used to secure the display so that the entered characters are not echoed back to the screen.


328
329
330
331
# File 'lib/tty/prompt/question.rb', line 328

def echo(value = nil)
  return @echo if value.nil?
  @echo = value
end

#in(value = (not_set = true), message = nil) ⇒ Object

Set expected range of values

Parameters:

  • value (String) (defaults to: (not_set = true))

348
349
350
351
352
353
354
355
# File 'lib/tty/prompt/question.rb', line 348

def in(value = (not_set = true), message = nil)
  messages[:range?] = message if message
  if in? && !@in.is_a?(Range)
    @in = Converters.convert(:range, @in)
  end
  return @in if not_set
  @in = Converters.convert(:range, value)
end

#in?Boolean

Check if range is set

Returns:

  • (Boolean)

362
363
364
# File 'lib/tty/prompt/question.rb', line 362

def in?
  @in != UndefinedSetting
end

#inspectObject

String representation of this question


380
381
382
# File 'lib/tty/prompt/question.rb', line 380

def inspect
  "#<#{self.class.name} @message=#{message}, @input=#{@input}>"
end

#message_for(name, tokens = nil) ⇒ Array[String]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Retrieve message based on the key

Parameters:

  • name (Symbol)

    the name of message key

  • tokens (Hash) (defaults to: nil)

    the tokens to evaluate

Returns:

  • (Array[String])

91
92
93
94
95
96
97
98
# File 'lib/tty/prompt/question.rb', line 91

def message_for(name, tokens = nil)
  template = @messages[name]
  if template && !template.match(/\%\{/).nil?
    [template % tokens]
  else
    [template || ""]
  end
end

#modify(*rules) ⇒ Object

Modify string according to the rule given.

Parameters:

  • rule (Symbol)

320
321
322
# File 'lib/tty/prompt/question.rb', line 320

def modify(*rules)
  @modifier = rules
end

#process_input(question) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Decide how to handle input from user


161
162
163
164
165
166
167
# File 'lib/tty/prompt/question.rb', line 161

def process_input(question)
  @input = read_input(question)
  if Utils.blank?(@input)
    @input = default? ? default : nil
  end
  @evaluator.(@input)
end

#quiet(value) ⇒ Object

Set quiet mode.


369
370
371
# File 'lib/tty/prompt/question.rb', line 369

def quiet(value)
  @quiet = value
end

#raw(value = nil) ⇒ Object Also known as: raw?

Turn raw mode on or off. This enables character-based input.


337
338
339
340
# File 'lib/tty/prompt/question.rb', line 337

def raw(value = nil)
  return @raw if value.nil?
  @raw = value
end

#read_input(question) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process input


172
173
174
175
176
177
178
179
# File 'lib/tty/prompt/question.rb', line 172

def read_input(question)
  options = {echo: echo}
  if value? && @first_render
    options[:value] = @value
    @first_render = false
  end
  @prompt.read_line(question, **options).chomp
end

#refresh(lines, lines_to_clear) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Determine area of the screen to clear

Parameters:

  • lines (Integer)

    number of lines to clear

Returns:

  • (String)

201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/tty/prompt/question.rb', line 201

def refresh(lines, lines_to_clear)
  output = []
  if @done
    if @errors.count.zero?
      output << @prompt.cursor.up(lines)
    else
      lines += @errors.count
      lines_to_clear += @errors.count
    end
  else
    output << @prompt.cursor.up(lines)
  end
  output.join + @prompt.clear_lines(lines_to_clear)
end

#renderObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Read answer and convert to type


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/tty/prompt/question.rb', line 118

def render
  @errors = []
  until @done
    result = process_input(render_question)
    if result.failure?
      @errors = result.errors
      @prompt.print(render_error(result.errors))
    else
      @done = true
    end
    question    = render_question
    input_line  = question + result.value.to_s
    total_lines = @prompt.count_screen_lines(input_line)
    @prompt.print(refresh(question.lines.count, total_lines))
  end
  @prompt.print(render_question) unless @quiet
  result.value
end

#render_error(errors) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Handle error condition

Returns:

  • (String)

186
187
188
189
190
191
# File 'lib/tty/prompt/question.rb', line 186

def render_error(errors)
  errors.reduce([]) do |acc, err|
    acc << @prompt.decorate(">>", :red) + " " + err
    acc
  end.join("\n")
end

#render_questionString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Render question

Returns:

  • (String)

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/tty/prompt/question.rb', line 142

def render_question
  header = []
  if !Utils.blank?(@prefix) || !Utils.blank?(message)
    header << "#{@prefix}#{message} "
  end
  if !echo?
    header
  elsif @done
    header << @prompt.decorate(@input.to_s, @active_color)
  elsif default? && !Utils.blank?(@default)
    header << @prompt.decorate("(#{default})", @help_color) + " "
  end
  header << "\n" if @done
  header.join
end

#required(value = (not_set = true), message = nil) ⇒ Boolean Also known as: required?

Ensure that passed argument is present or not

Returns:

  • (Boolean)

277
278
279
280
281
# File 'lib/tty/prompt/question.rb', line 277

def required(value = (not_set = true), message = nil)
  messages[:required?] = message if message
  return @required if not_set
  @required = value
end

#to_sObject


374
375
376
# File 'lib/tty/prompt/question.rb', line 374

def to_s
  message.to_s
end

#validate(value = nil, message = nil, &block) ⇒ Question

Set validation rule for an argument

Parameters:

  • value (Object) (defaults to: nil)

Returns:


291
292
293
294
# File 'lib/tty/prompt/question.rb', line 291

def validate(value = nil, message = nil, &block)
  messages[:valid?] = message if message
  @validation = (value || block)
end

#validation?Boolean

Returns:

  • (Boolean)

311
312
313
# File 'lib/tty/prompt/question.rb', line 311

def validation?
  @validation != UndefinedSetting
end

#value(val) ⇒ Object

Prepopulate input with custom content


299
300
301
302
# File 'lib/tty/prompt/question.rb', line 299

def value(val)
  return @value if val.nil?
  @value = val
end

#value?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if custom value is present

Returns:

  • (Boolean)

307
308
309
# File 'lib/tty/prompt/question.rb', line 307

def value?
  @value != UndefinedSetting
end