tty-prompt 0.19.0 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
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