tty-prompt 0.19.0 → 0.23.1

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