tty-prompt 0.18.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
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,74 +1,181 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
- require 'necromancer'
5
-
6
- require_relative 'converter_dsl'
3
+ require_relative "const"
4
+ require_relative "converter_dsl"
7
5
 
8
6
  module TTY
9
7
  class Prompt
10
8
  module Converters
11
9
  extend ConverterDSL
12
10
 
13
- # Delegate Necromancer errors
14
- #
15
- # @api private
16
- def self.on_error
17
- if block_given?
18
- yield
19
- else
20
- raise ArgumentError, 'You need to provide a block argument.'
11
+ TRUE_VALUES = /^(t(rue)?|y(es)?|on|1)$/i.freeze
12
+ FALSE_VALUES = /^(f(alse)?|n(o)?|off|0)$/i.freeze
13
+
14
+ SINGLE_DIGIT_MATCHER = /^(?<digit>\-?\d+(\.\d+)?)$/.freeze
15
+ DIGIT_MATCHER = /^(?<open>-?\d+(\.\d+)?)
16
+ \s*(?<sep>(\.\s*){2,3}|-|,)\s*
17
+ (?<close>-?\d+(\.\d+)?)$
18
+ /x.freeze
19
+ LETTER_MATCHER = /^(?<open>\w)
20
+ \s*(?<sep>(\.\s*){2,3}|-|,)\s*
21
+ (?<close>\w)$
22
+ /x.freeze
23
+
24
+ converter(:boolean, :bool) do |input|
25
+ case input.to_s
26
+ when TRUE_VALUES then true
27
+ when FALSE_VALUES then false
28
+ else Const::Undefined
21
29
  end
22
- rescue Necromancer::ConversionTypeError => e
23
- raise ConversionError, e.message
24
- end
25
-
26
- converter(:bool) do |input|
27
- on_error { Necromancer.convert(input).to(:boolean, strict: true) }
28
30
  end
29
31
 
30
- converter(:string) do |input|
32
+ converter(:string, :str) do |input|
31
33
  String(input).chomp
32
34
  end
33
35
 
34
- converter(:symbol) do |input|
36
+ converter(:symbol, :sym) do |input|
35
37
  input.to_sym
36
38
  end
37
39
 
40
+ converter(:char) do |input|
41
+ String(input).chars.to_a[0]
42
+ end
43
+
38
44
  converter(:date) do |input|
39
- on_error { Necromancer.convert(input).to(:date, strict: true) }
45
+ begin
46
+ require "date" unless defined?(::Date)
47
+ ::Date.parse(input)
48
+ rescue ArgumentError
49
+ Const::Undefined
50
+ end
40
51
  end
41
52
 
42
53
  converter(:datetime) do |input|
43
- on_error { Necromancer.convert(input).to(:datetime, strict: true) }
54
+ begin
55
+ require "date" unless defined?(::Date)
56
+ ::DateTime.parse(input.to_s)
57
+ rescue ArgumentError
58
+ Const::Undefined
59
+ end
44
60
  end
45
61
 
46
- converter(:int) do |input|
47
- on_error { Necromancer.convert(input).to(:integer, strict: true) }
62
+ converter(:time) do |input|
63
+ begin
64
+ require "time"
65
+ ::Time.parse(input.to_s)
66
+ rescue ArgumentError
67
+ Const::Undefined
68
+ end
69
+ end
70
+
71
+ converter(:integer, :int) do |input|
72
+ begin
73
+ Integer(input)
74
+ rescue ArgumentError
75
+ Const::Undefined
76
+ end
48
77
  end
49
78
 
50
79
  converter(:float) do |input|
51
- on_error { Necromancer.convert(input).to(:float, strict: true) }
80
+ begin
81
+ Float(input)
82
+ rescue TypeError, ArgumentError
83
+ Const::Undefined
84
+ end
52
85
  end
53
86
 
87
+ # Convert string number to integer or float
88
+ #
89
+ # @return [Integer,Float,Const::Undefined]
90
+ #
91
+ # @api private
92
+ def cast_to_num(num)
93
+ ([convert(:int, num), convert(:float, num)] - [Const::Undefined]).first ||
94
+ Const::Undefined
95
+ end
96
+ module_function :cast_to_num
97
+
54
98
  converter(:range) do |input|
55
- on_error { Necromancer.convert(input).to(:range, strict: true) }
99
+ if input.is_a?(::Range)
100
+ input
101
+ elsif match = input.to_s.match(SINGLE_DIGIT_MATCHER)
102
+ digit = cast_to_num(match[:digit])
103
+ ::Range.new(digit, digit)
104
+ elsif match = input.to_s.match(DIGIT_MATCHER)
105
+ open = cast_to_num(match[:open])
106
+ close = cast_to_num(match[:close])
107
+ ::Range.new(open, close, match[:sep].gsub(/\s*/, "") == "...")
108
+ elsif match = input.to_s.match(LETTER_MATCHER)
109
+ ::Range.new(match[:open], match[:close],
110
+ match[:sep].gsub(/\s*/, "") == "...")
111
+ else Const::Undefined
112
+ end
56
113
  end
57
114
 
58
115
  converter(:regexp) do |input|
59
116
  Regexp.new(input)
60
117
  end
61
118
 
62
- converter(:file) do |input|
63
- ::File.open(::File.join(Dir.pwd, input))
119
+ converter(:filepath, :file) do |input|
120
+ ::File.expand_path(input)
64
121
  end
65
122
 
66
- converter(:path) do |input|
67
- Pathname.new(::File.join(Dir.pwd, input))
123
+ converter(:pathname, :path) do |input|
124
+ require "pathname" unless defined?(::Pathname)
125
+ ::Pathname.new(input)
68
126
  end
69
127
 
70
- converter(:char) do |input|
71
- String(input).chars.to_a[0]
128
+ converter(:uri) do |input|
129
+ require "uri" unless defined?(::URI)
130
+ ::URI.parse(input)
131
+ end
132
+
133
+ converter(:list, :array) do |val|
134
+ (val.respond_to?(:to_a) ? val : val.split(/(?<!\\),/))
135
+ .map { |v| v.strip.gsub(/\\,/, ",") }
136
+ .reject(&:empty?)
137
+ end
138
+
139
+ converter(:hash, :map) do |val|
140
+ values = val.respond_to?(:to_a) ? val : val.split(/[& ]/)
141
+ values.each_with_object({}) do |pair, pairs|
142
+ key, value = pair.split(/[=:]/, 2)
143
+ if (current = pairs[key.to_sym])
144
+ pairs[key.to_sym] = Array(current) << value
145
+ else
146
+ pairs[key.to_sym] = value
147
+ end
148
+ pairs
149
+ end
150
+ end
151
+
152
+ converter_registry.keys.each do |type|
153
+ next if type =~ /list|array|map|hash/
154
+
155
+ [:"#{type}_list", :"#{type}_array", :"#{type}s"].each do |new_type|
156
+ converter(new_type) do |val|
157
+ converter_registry[:array].(val).map do |obj|
158
+ converter_registry[type].(obj)
159
+ end
160
+ end
161
+ end
162
+
163
+ [:"#{type}_map", :"#{type}_hash"].each do |new_type|
164
+ converter(new_type) do |val|
165
+ converter_registry[:hash].(val).each_with_object({}) do |(k, v), h|
166
+ h[k] = converter_registry[type].(v)
167
+ end
168
+ end
169
+ end
170
+
171
+ [:"string_#{type}_map", :"str_#{type}_map",
172
+ :"string_#{type}_hash", :"str_#{type}_hash"].each do |new_type|
173
+ converter(new_type) do |val|
174
+ converter_registry[:hash].(val).each_with_object({}) do |(k, v), h|
175
+ h[converter_registry[:string].(k)] = converter_registry[type].(v)
176
+ end
177
+ end
178
+ end
72
179
  end
73
180
  end # Converters
74
181
  end # Prompt
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'English'
3
+ require "English"
4
4
 
5
- require_relative 'choices'
6
- require_relative 'enum_paginator'
7
- require_relative 'paginator'
8
- require_relative 'symbols'
5
+ require_relative "choices"
6
+ require_relative "block_paginator"
7
+ require_relative "paginator"
9
8
 
10
9
  module TTY
11
10
  class Prompt
@@ -14,22 +13,25 @@ module TTY
14
13
  #
15
14
  # @api private
16
15
  class EnumList
17
- include Symbols
16
+ PAGE_HELP = "(Press tab/right or left to reveal more choices)"
18
17
 
19
- PAGE_HELP = '(Press tab/right or left to reveal more choices)'
18
+ # Checks type of default parameter to be integer
19
+ INTEGER_MATCHER = /\A[-+]?\d+\Z/.freeze
20
20
 
21
21
  # Create instance of EnumList menu.
22
22
  #
23
23
  # @api public
24
- def initialize(prompt, options = {})
24
+ def initialize(prompt, **options)
25
25
  @prompt = prompt
26
26
  @prefix = options.fetch(:prefix) { @prompt.prefix }
27
- @enum = options.fetch(:enum) { ')' }
28
- @default = options.fetch(:default) { 1 }
27
+ @enum = options.fetch(:enum) { ")" }
28
+ @default = options.fetch(:default, nil)
29
29
  @active_color = options.fetch(:active_color) { @prompt.active_color }
30
30
  @help_color = options.fetch(:help_color) { @prompt.help_color }
31
31
  @error_color = options.fetch(:error_color) { @prompt.error_color }
32
- @cycle = options.fetch(:cycle) { false }
32
+ @cycle = options.fetch(:cycle, false)
33
+ @quiet = options.fetch(:quiet) { @prompt.quiet }
34
+ @symbols = @prompt.symbols.merge(options.fetch(:symbols, {}))
33
35
  @input = nil
34
36
  @done = false
35
37
  @first_render = true
@@ -38,10 +40,22 @@ module TTY
38
40
  @choices = Choices.new
39
41
  @per_page = options[:per_page]
40
42
  @page_help = options[:page_help] || PAGE_HELP
41
- @paginator = EnumPaginator.new
43
+ @paginator = BlockPaginator.new
42
44
  @page_active = @default
43
45
  end
44
46
 
47
+ # Change symbols used by this prompt
48
+ #
49
+ # @param [Hash] new_symbols
50
+ # the new symbols to use
51
+ #
52
+ # @api public
53
+ def symbols(new_symbols = (not_set = true))
54
+ return @symbols if not_set
55
+
56
+ @symbols.merge!(new_symbols)
57
+ end
58
+
45
59
  # Set default option selected
46
60
  #
47
61
  # @api public
@@ -49,6 +63,15 @@ module TTY
49
63
  @default = default
50
64
  end
51
65
 
66
+ # Check if default value is set
67
+ #
68
+ # @return [Boolean]
69
+ #
70
+ # @api public
71
+ def default?
72
+ !@default.to_s.empty?
73
+ end
74
+
52
75
  # Set number of items per page
53
76
  #
54
77
  # @api public
@@ -83,6 +106,13 @@ module TTY
83
106
  @enum = value
84
107
  end
85
108
 
109
+ # Set quiet mode
110
+ #
111
+ # @api public
112
+ def quiet(value)
113
+ @quiet = value
114
+ end
115
+
86
116
  # Add a single choice
87
117
  #
88
118
  # @api public
@@ -125,8 +155,9 @@ module TTY
125
155
  end
126
156
 
127
157
  def keypress(event)
128
- if [:backspace, :delete].include?(event.key.name)
158
+ if %i[backspace delete].include?(event.key.name)
129
159
  return if @input.empty?
160
+
130
161
  @input.chop!
131
162
  mark_choice_as_active
132
163
  elsif event.value =~ /^\d+$/
@@ -144,7 +175,7 @@ module TTY
144
175
  if choice_in_range && !choice_disabled || @input.empty?
145
176
  @done = true
146
177
  else
147
- @input = ''
178
+ @input = ""
148
179
  @failure = true
149
180
  end
150
181
  end
@@ -193,6 +224,8 @@ module TTY
193
224
  def validate_defaults
194
225
  msg = if @default.nil? || @default.to_s.empty?
195
226
  "default index must be an integer in range (1 - #{choices.size})"
227
+ elsif @default.to_s !~ INTEGER_MATCHER
228
+ validate_default_name
196
229
  elsif @default < 1 || @default > @choices.size
197
230
  "default index #{@default} out of range (1 - #{@choices.size})"
198
231
  elsif choices[@default - 1] && choices[@default - 1].disabled?
@@ -202,11 +235,31 @@ module TTY
202
235
  raise(ConfigurationError, msg) if msg
203
236
  end
204
237
 
238
+ # Validate default choice name
239
+ #
240
+ # @return [String]
241
+ #
242
+ # @api private
243
+ def validate_default_name
244
+ default_choice = choices.find_by(:name, @default.to_s)
245
+ if default_choice.nil?
246
+ "no choice found for the default name: #{@default.inspect}"
247
+ elsif default_choice.disabled?
248
+ "default name #{@default.inspect} matches disabled choice"
249
+ end
250
+ end
251
+
205
252
  # Setup default option and active selection
206
253
  #
207
254
  # @api private
208
255
  def setup_defaults
256
+ if @default.to_s.empty?
257
+ @default = (0..choices.length).find { |i| !choices[i].disabled? } + 1
258
+ end
209
259
  validate_defaults
260
+ if default_choice = choices.find_by(:name, @default)
261
+ @default = choices.index(default_choice) + 1
262
+ end
210
263
  mark_choice_as_active
211
264
  end
212
265
 
@@ -219,7 +272,7 @@ module TTY
219
272
  #
220
273
  # @api private
221
274
  def render
222
- @input = ''
275
+ @input = ""
223
276
  until @done
224
277
  question = render_question
225
278
  @prompt.print(question)
@@ -231,7 +284,7 @@ module TTY
231
284
  question_lines = question.split($INPUT_RECORD_SEPARATOR, -1)
232
285
  @prompt.print(refresh(question_lines_count(question_lines)))
233
286
  end
234
- @prompt.print(render_question)
287
+ @prompt.print(render_question) unless @quiet
235
288
  answer
236
289
  end
237
290
 
@@ -286,8 +339,8 @@ module TTY
286
339
  #
287
340
  # @api private
288
341
  def error_message
289
- error = 'Please enter a valid number'
290
- "\n" + @prompt.decorate('>>', @error_color) + ' ' + error
342
+ error = "Please enter a valid number"
343
+ "\n" + @prompt.decorate(">>", @error_color) + " " + error
291
344
  end
292
345
 
293
346
  # Render error message and return cursor to position of input
@@ -310,8 +363,9 @@ module TTY
310
363
  #
311
364
  # @api private
312
365
  def render_header
313
- return '' unless @done
314
- return '' unless @active
366
+ return "" unless @done
367
+ return "" unless @active
368
+
315
369
  selected_item = @choices[@active - 1].name.to_s
316
370
  @prompt.decorate(selected_item, @active_color)
317
371
  end
@@ -331,7 +385,8 @@ module TTY
331
385
  #
332
386
  # @api private
333
387
  def page_help_message
334
- return '' unless paginated?
388
+ return "" unless paginated?
389
+
335
390
  "\n" + @prompt.decorate(@page_help, @help_color)
336
391
  end
337
392
 
@@ -358,15 +413,15 @@ module TTY
358
413
  output = []
359
414
 
360
415
  @paginator.paginate(@choices, @page_active, @per_page) do |choice, index|
361
- num = (index + 1).to_s + @enum + ' '
416
+ num = (index + 1).to_s + @enum + " "
362
417
  selected = num.to_s + choice.name.to_s
363
418
  output << if index + 1 == @active && !choice.disabled?
364
- (' ' * 2) + @prompt.decorate(selected, @active_color)
419
+ (" " * 2) + @prompt.decorate(selected, @active_color)
365
420
  elsif choice.disabled?
366
- @prompt.decorate(symbols[:cross], :red) + ' ' +
367
- selected + ' ' + choice.disabled.to_s
421
+ @prompt.decorate(@symbols[:cross], :red) + " " +
422
+ selected + " " + choice.disabled.to_s
368
423
  else
369
- (' ' * 2) + selected
424
+ (" " * 2) + selected
370
425
  end
371
426
  output << "\n"
372
427
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTY
4
+ class Prompt
5
+ Error = Class.new(StandardError)
6
+
7
+ # Raised when wrong parameter is used to configure prompt
8
+ ConfigurationError = Class.new(Error)
9
+
10
+ # Raised when type conversion cannot be performed
11
+ ConversionError = Class.new(Error)
12
+
13
+ # Raised when the passed in validation argument is of wrong type
14
+ ValidationCoercion = Class.new(Error)
15
+
16
+ # Raised when the required argument is not supplied
17
+ ArgumentRequired = Class.new(Error)
18
+
19
+ # Raised when the argument validation fails
20
+ ArgumentValidation = Class.new(Error)
21
+
22
+ # Raised when the argument is not expected
23
+ InvalidArgument = Class.new(Error)
24
+
25
+ # Raised when overriding already defined conversion
26
+ ConversionAlreadyDefined = Class.new(Error)
27
+
28
+ # Raised when conversion type isn't registered
29
+ UnsupportedConversion = Class.new(Error)
30
+ end # Prompt
31
+ end # TTY