tty-prompt 0.18.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +95 -0
  3. data/README.md +598 -256
  4. data/lib/tty-prompt.rb +1 -2
  5. data/lib/tty/prompt.rb +192 -144
  6. data/lib/tty/prompt/answers_collector.rb +5 -5
  7. data/lib/tty/prompt/{enum_paginator.rb → block_paginator.rb} +20 -19
  8. data/lib/tty/prompt/choice.rb +9 -10
  9. data/lib/tty/prompt/choices.rb +30 -12
  10. data/lib/tty/prompt/confirm_question.rb +42 -16
  11. data/lib/tty/prompt/const.rb +17 -0
  12. data/lib/tty/prompt/converter_dsl.rb +6 -7
  13. data/lib/tty/prompt/converter_registry.rb +31 -26
  14. data/lib/tty/prompt/converters.rb +139 -32
  15. data/lib/tty/prompt/enum_list.rb +81 -26
  16. data/lib/tty/prompt/errors.rb +31 -0
  17. data/lib/tty/prompt/evaluator.rb +2 -2
  18. data/lib/tty/prompt/expander.rb +45 -15
  19. data/lib/tty/prompt/keypress.rb +33 -36
  20. data/lib/tty/prompt/list.rb +198 -63
  21. data/lib/tty/prompt/mask_question.rb +11 -8
  22. data/lib/tty/prompt/multi_list.rb +131 -28
  23. data/lib/tty/prompt/multiline.rb +9 -7
  24. data/lib/tty/prompt/paginator.rb +38 -26
  25. data/lib/tty/prompt/question.rb +92 -37
  26. data/lib/tty/prompt/question/checks.rb +20 -2
  27. data/lib/tty/prompt/question/modifier.rb +4 -2
  28. data/lib/tty/prompt/question/validation.rb +3 -3
  29. data/lib/tty/prompt/selected_choices.rb +77 -0
  30. data/lib/tty/prompt/slider.rb +125 -30
  31. data/lib/tty/prompt/statement.rb +3 -3
  32. data/lib/tty/prompt/suggestion.rb +7 -6
  33. data/lib/tty/prompt/symbols.rb +58 -34
  34. data/lib/tty/prompt/test.rb +36 -0
  35. data/lib/tty/prompt/timer.rb +75 -0
  36. data/lib/tty/prompt/utils.rb +1 -3
  37. data/lib/tty/prompt/version.rb +1 -1
  38. metadata +29 -227
  39. data/Rakefile +0 -8
  40. data/examples/ask.rb +0 -7
  41. data/examples/ask_valid.rb +0 -12
  42. data/examples/collect.rb +0 -21
  43. data/examples/echo.rb +0 -11
  44. data/examples/enum_select.rb +0 -7
  45. data/examples/enum_select_disabled.rb +0 -16
  46. data/examples/enum_select_paged.rb +0 -9
  47. data/examples/enum_select_wrapped.rb +0 -15
  48. data/examples/expand.rb +0 -29
  49. data/examples/in.rb +0 -9
  50. data/examples/inputs.rb +0 -10
  51. data/examples/key_events.rb +0 -15
  52. data/examples/keypress.rb +0 -9
  53. data/examples/mask.rb +0 -13
  54. data/examples/multi_select.rb +0 -8
  55. data/examples/multi_select_disabled.rb +0 -17
  56. data/examples/multi_select_paged.rb +0 -9
  57. data/examples/multi_select_wrapped.rb +0 -15
  58. data/examples/multiline.rb +0 -9
  59. data/examples/pause.rb +0 -9
  60. data/examples/select.rb +0 -24
  61. data/examples/select_disabled.rb +0 -18
  62. data/examples/select_enum.rb +0 -8
  63. data/examples/select_filtered.rb +0 -11
  64. data/examples/select_paginated.rb +0 -11
  65. data/examples/select_wrapped.rb +0 -15
  66. data/examples/slider.rb +0 -6
  67. data/examples/validation.rb +0 -9
  68. data/examples/yes_no.rb +0 -7
  69. data/lib/tty/prompt/messages.rb +0 -49
  70. data/lib/tty/prompt/timeout.rb +0 -78
  71. data/lib/tty/test_prompt.rb +0 -20
  72. data/spec/spec_helper.rb +0 -45
  73. data/spec/unit/ask_spec.rb +0 -132
  74. data/spec/unit/choice/eql_spec.rb +0 -22
  75. data/spec/unit/choice/from_spec.rb +0 -96
  76. data/spec/unit/choices/add_spec.rb +0 -12
  77. data/spec/unit/choices/each_spec.rb +0 -13
  78. data/spec/unit/choices/find_by_spec.rb +0 -10
  79. data/spec/unit/choices/new_spec.rb +0 -10
  80. data/spec/unit/choices/pluck_spec.rb +0 -9
  81. data/spec/unit/collect_spec.rb +0 -96
  82. data/spec/unit/converters/convert_bool_spec.rb +0 -58
  83. data/spec/unit/converters/convert_char_spec.rb +0 -11
  84. data/spec/unit/converters/convert_custom_spec.rb +0 -14
  85. data/spec/unit/converters/convert_date_spec.rb +0 -34
  86. data/spec/unit/converters/convert_file_spec.rb +0 -18
  87. data/spec/unit/converters/convert_number_spec.rb +0 -39
  88. data/spec/unit/converters/convert_path_spec.rb +0 -15
  89. data/spec/unit/converters/convert_range_spec.rb +0 -22
  90. data/spec/unit/converters/convert_regex_spec.rb +0 -12
  91. data/spec/unit/converters/convert_string_spec.rb +0 -21
  92. data/spec/unit/converters/on_error_spec.rb +0 -9
  93. data/spec/unit/distance/distance_spec.rb +0 -73
  94. data/spec/unit/enum_paginator_spec.rb +0 -75
  95. data/spec/unit/enum_select_spec.rb +0 -446
  96. data/spec/unit/error_spec.rb +0 -20
  97. data/spec/unit/evaluator_spec.rb +0 -67
  98. data/spec/unit/expand_spec.rb +0 -198
  99. data/spec/unit/keypress_spec.rb +0 -72
  100. data/spec/unit/mask_spec.rb +0 -132
  101. data/spec/unit/multi_select_spec.rb +0 -511
  102. data/spec/unit/multiline_spec.rb +0 -77
  103. data/spec/unit/new_spec.rb +0 -20
  104. data/spec/unit/ok_spec.rb +0 -10
  105. data/spec/unit/paginator_spec.rb +0 -73
  106. data/spec/unit/question/checks_spec.rb +0 -97
  107. data/spec/unit/question/default_spec.rb +0 -31
  108. data/spec/unit/question/echo_spec.rb +0 -38
  109. data/spec/unit/question/in_spec.rb +0 -115
  110. data/spec/unit/question/initialize_spec.rb +0 -12
  111. data/spec/unit/question/modifier/apply_to_spec.rb +0 -24
  112. data/spec/unit/question/modifier/letter_case_spec.rb +0 -41
  113. data/spec/unit/question/modifier/whitespace_spec.rb +0 -51
  114. data/spec/unit/question/modify_spec.rb +0 -41
  115. data/spec/unit/question/required_spec.rb +0 -92
  116. data/spec/unit/question/validate_spec.rb +0 -115
  117. data/spec/unit/question/validation/call_spec.rb +0 -31
  118. data/spec/unit/question/validation/coerce_spec.rb +0 -30
  119. data/spec/unit/result_spec.rb +0 -40
  120. data/spec/unit/say_spec.rb +0 -67
  121. data/spec/unit/select_spec.rb +0 -660
  122. data/spec/unit/slider_spec.rb +0 -100
  123. data/spec/unit/statement/initialize_spec.rb +0 -15
  124. data/spec/unit/subscribe_spec.rb +0 -22
  125. data/spec/unit/suggest_spec.rb +0 -28
  126. data/spec/unit/warn_spec.rb +0 -21
  127. data/spec/unit/yes_no_spec.rb +0 -251
  128. data/tasks/console.rake +0 -11
  129. data/tasks/coverage.rake +0 -11
  130. data/tasks/spec.rake +0 -29
  131. data/tty-prompt.gemspec +0 -33
@@ -1,2 +1 @@
1
- require_relative 'tty/prompt'
2
- require_relative 'tty/test_prompt'
1
+ require_relative "tty/prompt"
@@ -1,49 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
4
- require 'pastel'
5
- require 'tty-cursor'
6
- require 'tty-reader'
7
-
8
- require_relative 'prompt/answers_collector'
9
- require_relative 'prompt/confirm_question'
10
- require_relative 'prompt/expander'
11
- require_relative 'prompt/enum_list'
12
- require_relative 'prompt/keypress'
13
- require_relative 'prompt/list'
14
- require_relative 'prompt/multi_list'
15
- require_relative 'prompt/multiline'
16
- require_relative 'prompt/mask_question'
17
- require_relative 'prompt/question'
18
- require_relative 'prompt/slider'
19
- require_relative 'prompt/statement'
20
- require_relative 'prompt/suggestion'
21
- require_relative 'prompt/utils'
22
- require_relative 'prompt/version'
3
+ require "forwardable"
4
+ require "pastel"
5
+ require "tty-cursor"
6
+ require "tty-reader"
7
+ require "tty-screen"
8
+
9
+ require_relative "prompt/answers_collector"
10
+ require_relative "prompt/confirm_question"
11
+ require_relative "prompt/errors"
12
+ require_relative "prompt/expander"
13
+ require_relative "prompt/enum_list"
14
+ require_relative "prompt/keypress"
15
+ require_relative "prompt/list"
16
+ require_relative "prompt/multi_list"
17
+ require_relative "prompt/multiline"
18
+ require_relative "prompt/mask_question"
19
+ require_relative "prompt/question"
20
+ require_relative "prompt/slider"
21
+ require_relative "prompt/statement"
22
+ require_relative "prompt/suggestion"
23
+ require_relative "prompt/symbols"
24
+ require_relative "prompt/utils"
25
+ require_relative "prompt/version"
23
26
 
24
27
  module TTY
25
28
  # A main entry for asking prompt questions.
26
29
  class Prompt
27
30
  extend Forwardable
28
31
 
29
- # Raised when wrong parameter is used to configure prompt
30
- ConfigurationError = Class.new(StandardError)
31
-
32
- # Raised when type conversion cannot be performed
33
- ConversionError = Class.new(StandardError)
34
-
35
- # Raised when the passed in validation argument is of wrong type
36
- ValidationCoercion = Class.new(TypeError)
37
-
38
- # Raised when the required argument is not supplied
39
- ArgumentRequired = Class.new(ArgumentError)
40
-
41
- # Raised when the argument validation fails
42
- ArgumentValidation = Class.new(ArgumentError)
43
-
44
- # Raised when the argument is not expected
45
- InvalidArgument = Class.new(ArgumentError)
46
-
47
32
  # @api private
48
33
  attr_reader :input
49
34
 
@@ -69,12 +54,27 @@ module TTY
69
54
  # @api private
70
55
  attr_reader :active_color, :help_color, :error_color, :enabled_color
71
56
 
72
- def_delegators :@pastel, :decorate, :strip
57
+ # Quiet mode
58
+ #
59
+ # @api private
60
+ attr_reader :quiet
61
+
62
+ # The collection of display symbols
63
+ #
64
+ # @example
65
+ # prompt = TTY::Prompt.new(symbols: {marker: ">"})
66
+ #
67
+ # @return [Hash]
68
+ #
69
+ # @api private
70
+ attr_reader :symbols
71
+
72
+ def_delegators :@pastel, :strip
73
73
 
74
74
  def_delegators :@cursor, :clear_lines, :clear_line,
75
75
  :show, :hide
76
76
 
77
- def_delegators :@reader, :read_char, :read_line, :read_keypress,
77
+ def_delegators :@reader, :read_char, :read_keypress, :read_line,
78
78
  :read_multiline, :on, :subscribe, :unsubscribe, :trigger,
79
79
  :count_screen_lines
80
80
 
@@ -82,61 +82,90 @@ module TTY
82
82
 
83
83
  def self.messages
84
84
  {
85
- range?: 'Value %{value} must be within the range %{in}',
86
- valid?: 'Your answer is invalid (must match %{valid})',
87
- required?: 'Value must be provided'
85
+ range?: "Value %{value} must be within the range %{in}",
86
+ valid?: "Your answer is invalid (must match %{valid})",
87
+ required?: "Value must be provided",
88
+ convert?: "Cannot convert `%{value}` to '%{type}' type"
88
89
  }
89
90
  end
90
91
 
91
92
  # Initialize a Prompt
92
93
  #
93
- # @param [Hash] options
94
- # @option options [IO] :input
94
+ # @param [IO] :input
95
95
  # the input stream
96
- # @option options [IO] :output
96
+ # @param [IO] :output
97
97
  # the output stream
98
- # @option options [Hash] :env
98
+ # @param [Hash] :env
99
99
  # the environment variables
100
- # @option options [String] :prefix
100
+ # @param [Hash] :symbols
101
+ # the symbols displayed in prompts such as :marker, :cross
102
+ # @param options [Boolean] :quiet
103
+ # enable quiet mode, don't re-echo the question
104
+ # @param [String] :prefix
101
105
  # the prompt prefix, by default empty
102
- # @option options [Boolean] :enable_color
106
+ # @param [Symbol] :interrupt
107
+ # handling of Ctrl+C key out of :signal, :exit, :noop
108
+ # @param [Boolean] :track_history
109
+ # disable line history tracking, true by default
110
+ # @param [Boolean] :enable_color
103
111
  # enable color support, true by default
104
- # @option options [String] :active_color
112
+ # @param [String,Proc] :active_color
105
113
  # the color used for selected option
106
- # @option options [String] :help_color
114
+ # @param [String,Proc] :help_color
107
115
  # the color used for help text
108
- # @option options [String] :error_color
116
+ # @param [String] :error_color
109
117
  # the color used for displaying error messages
110
- # @option options [Symbol] :interrupt
111
- # handling of Ctrl+C key out of :signal, :exit, :noop
112
- # @option options [Boolean] :track_history
113
- # disable line history tracking, true by default
114
118
  #
115
119
  # @api public
116
- def initialize(*args)
117
- options = Utils.extract_options!(args)
118
- @input = options.fetch(:input) { $stdin }
119
- @output = options.fetch(:output) { $stdout }
120
- @env = options.fetch(:env) { ENV }
121
- @prefix = options.fetch(:prefix) { '' }
122
- @enabled_color = options[:enable_color]
123
- @active_color = options.fetch(:active_color) { :green }
124
- @help_color = options.fetch(:help_color) { :bright_black }
125
- @error_color = options.fetch(:error_color) { :red }
126
- @interrupt = options.fetch(:interrupt) { :error }
127
- @track_history = options.fetch(:track_history) { true }
120
+ def initialize(input: $stdin, output: $stdout, env: ENV, symbols: {},
121
+ prefix: "", interrupt: :error, track_history: true,
122
+ quiet: false, enable_color: nil, active_color: :green,
123
+ help_color: :bright_black, error_color: :red)
124
+ @input = input
125
+ @output = output
126
+ @env = env
127
+ @prefix = prefix
128
+ @enabled_color = enable_color
129
+ @active_color = active_color
130
+ @help_color = help_color
131
+ @error_color = error_color
132
+ @interrupt = interrupt
133
+ @track_history = track_history
134
+ @symbols = Symbols.symbols.merge(symbols)
135
+ @quiet = quiet
128
136
 
129
137
  @cursor = TTY::Cursor
130
- @pastel = Pastel.new(@enabled_color.nil? ? {} : { enabled: @enabled_color })
138
+ @pastel = enabled_color.nil? ? Pastel.new : Pastel.new(enabled: enabled_color)
131
139
  @reader = TTY::Reader.new(
132
- input: @input,
133
- output: @output,
134
- interrupt: @interrupt,
135
- track_history: @track_history,
136
- env: @env
140
+ input: input,
141
+ output: output,
142
+ interrupt: interrupt,
143
+ track_history: track_history,
144
+ env: env
137
145
  )
138
146
  end
139
147
 
148
+ # Decorate a string with colors
149
+ #
150
+ # @param [String] :string
151
+ # the string to color
152
+ # @param [Array<Proc|Symbol>] :colors
153
+ # collection of color symbols or callable object
154
+ #
155
+ # @api public
156
+ def decorate(string, *colors)
157
+ if Utils.blank?(string) || @enabled_color == false || colors.empty?
158
+ return string
159
+ end
160
+
161
+ coloring = colors.first
162
+ if coloring.respond_to?(:call)
163
+ coloring.call(string)
164
+ else
165
+ @pastel.decorate(string, *colors)
166
+ end
167
+ end
168
+
140
169
  # Invoke a question type of prompt
141
170
  #
142
171
  # @example
@@ -146,10 +175,9 @@ module TTY
146
175
  # @return [String]
147
176
  #
148
177
  # @api public
149
- def invoke_question(object, message, *args, &block)
150
- options = Utils.extract_options!(args)
178
+ def invoke_question(object, message, **options, &block)
151
179
  options[:messages] = self.class.messages
152
- question = object.new(self, options)
180
+ question = object.new(self, **options)
153
181
  question.(message, &block)
154
182
  end
155
183
 
@@ -170,8 +198,8 @@ module TTY
170
198
  # @return [TTY::Prompt::Question]
171
199
  #
172
200
  # @api public
173
- def ask(message, *args, &block)
174
- invoke_question(Question, message, *args, &block)
201
+ def ask(message = "", **options, &block)
202
+ invoke_question(Question, message, **options, &block)
175
203
  end
176
204
 
177
205
  # Ask a question with a keypress answer
@@ -179,20 +207,20 @@ module TTY
179
207
  # @see #ask
180
208
  #
181
209
  # @api public
182
- def keypress(message, *args, &block)
183
- invoke_question(Keypress, message, *args, &block)
210
+ def keypress(message = "", **options, &block)
211
+ invoke_question(Keypress, message, **options, &block)
184
212
  end
185
213
 
186
214
  # Ask a question with a multiline answer
187
215
  #
188
216
  # @example
189
- # prompt.multiline('Description?')
217
+ # prompt.multiline("Description?")
190
218
  #
191
219
  # @return [Array[String]]
192
220
  #
193
221
  # @api public
194
- def multiline(message, *args, &block)
195
- invoke_question(Multiline, message, *args, &block)
222
+ def multiline(message = "", **options, &block)
223
+ invoke_question(Multiline, message, **options, &block)
196
224
  end
197
225
 
198
226
  # Invoke a list type of prompt
@@ -207,9 +235,7 @@ module TTY
207
235
  # @api public
208
236
  def invoke_select(object, question, *args, &block)
209
237
  options = Utils.extract_options!(args)
210
- choices = if block
211
- []
212
- elsif args.empty?
238
+ choices = if args.empty? && !block
213
239
  possible = options.dup
214
240
  options = {}
215
241
  possible
@@ -219,7 +245,7 @@ module TTY
219
245
  args.flatten
220
246
  end
221
247
 
222
- list = object.new(self, options)
248
+ list = object.new(self, **options)
223
249
  list.(question, choices, &block)
224
250
  end
225
251
 
@@ -232,8 +258,8 @@ module TTY
232
258
  # @return [TTY::Prompt::MaskQuestion]
233
259
  #
234
260
  # @api public
235
- def mask(message, *args, &block)
236
- invoke_question(MaskQuestion, message, *args, &block)
261
+ def mask(message = "", **options, &block)
262
+ invoke_question(MaskQuestion, message, **options, &block)
237
263
  end
238
264
 
239
265
  # Ask a question with a list of options
@@ -301,42 +327,36 @@ module TTY
301
327
  end
302
328
 
303
329
  # A shortcut method to ask the user positive question and return
304
- # true for 'yes' reply, false for 'no'.
330
+ # true for "yes" reply, false for "no".
305
331
  #
306
332
  # @example
307
333
  # prompt = TTY::Prompt.new
308
- # prompt.yes?('Are you human?')
334
+ # prompt.yes?("Are you human?")
309
335
  # # => Are you human? (Y/n)
310
336
  #
311
337
  # @return [Boolean]
312
338
  #
313
339
  # @api public
314
- def yes?(message, *args, &block)
315
- defaults = { default: true }
316
- options = Utils.extract_options!(args)
317
- options.merge!(defaults.reject { |k, _| options.key?(k) })
318
-
319
- question = ConfirmQuestion.new(self, options)
340
+ def yes?(message, **options, &block)
341
+ opts = { default: true }.merge(options)
342
+ question = ConfirmQuestion.new(self, **opts)
320
343
  question.call(message, &block)
321
344
  end
322
345
 
323
346
  # A shortcut method to ask the user negative question and return
324
- # true for 'no' reply.
347
+ # true for "no" reply.
325
348
  #
326
349
  # @example
327
350
  # prompt = TTY::Prompt.new
328
- # prompt.no?('Are you alien?') # => true
351
+ # prompt.no?("Are you alien?") # => true
329
352
  # # => Are you human? (y/N)
330
353
  #
331
354
  # @return [Boolean]
332
355
  #
333
356
  # @api public
334
- def no?(message, *args, &block)
335
- defaults = { default: false }
336
- options = Utils.extract_options!(args)
337
- options.merge!(defaults.reject { |k, _| options.key?(k) })
338
-
339
- question = ConfirmQuestion.new(self, options)
357
+ def no?(message, **options, &block)
358
+ opts = { default: false }.merge(options)
359
+ question = ConfirmQuestion.new(self, **opts)
340
360
  !question.call(message, &block)
341
361
  end
342
362
 
@@ -345,15 +365,15 @@ module TTY
345
365
  # @example
346
366
  # prompt = TTY::Prompt.new
347
367
  # choices = [{
348
- # key: 'Y',
349
- # name: 'Overwrite',
368
+ # key: "Y",
369
+ # name: "Overwrite",
350
370
  # value: :yes
351
371
  # }, {
352
- # key: 'n',
353
- # name: 'Skip',
372
+ # key: "n",
373
+ # name: "Skip",
354
374
  # value: :no
355
375
  # }]
356
- # prompt.expand('Overwirte Gemfile?', choices)
376
+ # prompt.expand("Overwirte Gemfile?", choices)
357
377
  #
358
378
  # @return [Object]
359
379
  # the user specified value
@@ -367,18 +387,21 @@ module TTY
367
387
  #
368
388
  # @example
369
389
  # prompt = TTY::Prompt.new
370
- # prompt.slider('What size?', min: 32, max: 54, step: 2)
390
+ # prompt.slider("What size?", min: 32, max: 54, step: 2)
391
+ # prompt.slider("What size?", [ 'xs', 's', 'm', 'l', 'xl' ])
371
392
  #
372
393
  # @param [String] question
373
394
  # the question to ask
374
395
  #
396
+ # @param [Array] choices
397
+ # the choices to display
398
+ #
375
399
  # @return [String]
376
400
  #
377
401
  # @api public
378
- def slider(question, *args, &block)
379
- options = Utils.extract_options!(args)
380
- slider = Slider.new(self, options)
381
- slider.call(question, &block)
402
+ def slider(question, choices = nil, **options, &block)
403
+ slider = Slider.new(self, **options)
404
+ slider.call(question, choices, &block)
382
405
  end
383
406
 
384
407
  # Print statement out. If the supplied message ends with a space or
@@ -392,11 +415,11 @@ module TTY
392
415
  # @return [String]
393
416
  #
394
417
  # @api public
395
- def say(message = '', options = {})
418
+ def say(message = "", **options)
396
419
  message = message.to_s
397
420
  return if message.empty?
398
421
 
399
- statement = Statement.new(self, options)
422
+ statement = Statement.new(self, **options)
400
423
  statement.call(message)
401
424
  end
402
425
 
@@ -411,9 +434,9 @@ module TTY
411
434
  # @return [Array] messages
412
435
  #
413
436
  # @api public
414
- def ok(*args)
415
- options = Utils.extract_options!(args)
416
- args.each { |message| say message, options.merge(color: :green) }
437
+ def ok(*args, **options)
438
+ opts = { color: :green }.merge(options)
439
+ args.each { |message| say(message, **opts) }
417
440
  end
418
441
 
419
442
  # Print statement(s) out in yellow color.
@@ -427,9 +450,9 @@ module TTY
427
450
  # @return [Array] messages
428
451
  #
429
452
  # @api public
430
- def warn(*args)
431
- options = Utils.extract_options!(args)
432
- args.each { |message| say message, options.merge(color: :yellow) }
453
+ def warn(*args, **options)
454
+ opts = { color: :yellow }.merge(options)
455
+ args.each { |message| say(message, **opts) }
433
456
  end
434
457
 
435
458
  # Print statement(s) out in red color.
@@ -443,16 +466,38 @@ module TTY
443
466
  # @return [Array] messages
444
467
  #
445
468
  # @api public
446
- def error(*args)
447
- options = Utils.extract_options!(args)
448
- args.each { |message| say message, options.merge(color: :red) }
469
+ def error(*args, **options)
470
+ opts = { color: :red }.merge(options)
471
+ args.each { |message| say(message, **opts) }
472
+ end
473
+
474
+ # Print debug information in terminal top right corner
475
+ #
476
+ # @example
477
+ # prompt.debug "info1", "info2"
478
+ #
479
+ # @param [Array] messages
480
+ #
481
+ # @retrun [nil]
482
+ #
483
+ # @api public
484
+ def debug(*messages)
485
+ longest = messages.max_by(&:length).size
486
+ width = TTY::Screen.width - longest
487
+ print cursor.save
488
+ messages.reverse_each do |msg|
489
+ print cursor.column(width) + cursor.up + cursor.clear_line_after
490
+ print msg
491
+ end
492
+ ensure
493
+ print cursor.restore
449
494
  end
450
495
 
451
496
  # Takes the string provided by the user and compare it with other possible
452
497
  # matches to suggest an unambigous string
453
498
  #
454
499
  # @example
455
- # prompt.suggest('sta', ['status', 'stage', 'commit', 'branch'])
500
+ # prompt.suggest("sta", ["status", "stage", "commit", "branch"])
456
501
  # # => "status, stage"
457
502
  #
458
503
  # @param [String] message
@@ -470,8 +515,8 @@ module TTY
470
515
  # @return [String]
471
516
  #
472
517
  # @api public
473
- def suggest(message, possibilities, options = {})
474
- suggestion = Suggestion.new(options)
518
+ def suggest(message, possibilities, **options)
519
+ suggestion = Suggestion.new(**options)
475
520
  say(suggestion.suggest(message, possibilities))
476
521
  end
477
522
 
@@ -479,15 +524,15 @@ module TTY
479
524
  #
480
525
  # @example
481
526
  # prompt.collect do
482
- # key(:name).ask('Name?')
527
+ # key(:name).ask("Name?")
483
528
  # end
484
529
  #
485
530
  # @return [Hash]
486
531
  # the collection of answers
487
532
  #
488
533
  # @api public
489
- def collect(options = {}, &block)
490
- collector = AnswersCollector.new(self, options)
534
+ def collect(**options, &block)
535
+ collector = AnswersCollector.new(self, **options)
491
536
  collector.call(&block)
492
537
  end
493
538
 
@@ -521,21 +566,24 @@ module TTY
521
566
  $stderr
522
567
  end
523
568
 
524
- # Inspect class name and public attributes
569
+ # Inspect this instance public attributes
570
+ #
525
571
  # @return [String]
526
572
  #
527
573
  # @api public
528
574
  def inspect
529
- attributes = {
530
- input: input,
531
- output: output,
532
- prefix: prefix,
533
- active_color: active_color,
534
- error_color: error_color,
535
- enabled_color: enabled_color,
536
- help_color: help_color
537
- }
538
- "#<#{self.class}: #{attributes.each { |name, val| "@#{name}=#{val}" }}"
575
+ attributes = [
576
+ :prefix,
577
+ :quiet,
578
+ :enabled_color,
579
+ :active_color,
580
+ :error_color,
581
+ :help_color,
582
+ :input,
583
+ :output,
584
+ ]
585
+ name = self.class.name
586
+ "#<#{name}#{attributes.map { |attr| " #{attr}=#{send(attr).inspect}" }.join}>"
539
587
  end
540
588
  end # Prompt
541
589
  end # TTY