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
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'question'
3
+ require_relative "question"
4
4
 
5
5
  module TTY
6
6
  class Prompt
7
7
  class MaskQuestion < Question
8
+ # Names for delete keys
9
+ DELETE_KEYS = %i[backspace delete].freeze
10
+
8
11
  # Create masked question
9
12
  #
10
13
  # @param [Hash] options
@@ -27,19 +30,20 @@ module TTY
27
30
  # @api public
28
31
  def mask(char = (not_set = true))
29
32
  return @mask if not_set
33
+
30
34
  @mask = char
31
35
  end
32
36
 
33
- def keyreturn(event)
37
+ def keyreturn(_event)
34
38
  @done_masked = true
35
39
  end
36
40
 
37
- def keyenter(event)
41
+ def keyenter(_event)
38
42
  @done_masked = true
39
43
  end
40
44
 
41
45
  def keypress(event)
42
- if [:backspace, :delete].include?(event.key.name)
46
+ if DELETE_KEYS.include?(event.key.name)
43
47
  @input.chop! unless @input.empty?
44
48
  elsif event.value =~ /^[^\e\n\r]/
45
49
  @input += event.value
@@ -75,7 +79,7 @@ module TTY
75
79
  def read_input(question)
76
80
  @done_masked = false
77
81
  @failure = false
78
- @input = ''
82
+ @input = ""
79
83
  @prompt.print(question)
80
84
  until @done_masked
81
85
  @prompt.read_keypress
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'list'
3
+ require_relative "list"
4
+ require_relative "selected_choices"
4
5
 
5
6
  module TTY
6
7
  class Prompt
@@ -9,8 +10,6 @@ module TTY
9
10
  #
10
11
  # @api private
11
12
  class MultiList < List
12
- HELP = '(Use %s arrow%s keys, press Space to select and Enter to finish%s)'
13
-
14
13
  # Create instance of TTY::Prompt::MultiList menu.
15
14
  #
16
15
  # @param [Prompt] :prompt
@@ -19,12 +18,20 @@ module TTY
19
18
  # @api public
20
19
  def initialize(prompt, **options)
21
20
  super
22
- @selected = []
21
+ @selected = SelectedChoices.new
23
22
  @help = options[:help]
24
23
  @echo = options.fetch(:echo, true)
24
+ @min = options[:min]
25
25
  @max = options[:max]
26
26
  end
27
27
 
28
+ # Set a minimum number of choices
29
+ #
30
+ # @api public
31
+ def min(value)
32
+ @min = value
33
+ end
34
+
28
35
  # Set a maximum number of choices
29
36
  #
30
37
  # @api public
@@ -32,19 +39,54 @@ module TTY
32
39
  @max = value
33
40
  end
34
41
 
42
+ # Callback fired when enter/return key is pressed
43
+ #
44
+ # @api private
45
+ def keyenter(*)
46
+ valid = true
47
+ valid = @min <= @selected.size if @min
48
+ valid = @selected.size <= @max if @max
49
+
50
+ super if valid
51
+ end
52
+ alias keyreturn keyenter
53
+
35
54
  # Callback fired when space key is pressed
36
55
  #
37
56
  # @api private
38
57
  def keyspace(*)
39
58
  active_choice = choices[@active - 1]
40
59
  if @selected.include?(active_choice)
41
- @selected.delete(active_choice)
60
+ @selected.delete_at(@active - 1)
42
61
  else
43
62
  return if @max && @selected.size >= @max
44
- @selected << active_choice
63
+
64
+ @selected.insert(@active - 1, active_choice)
45
65
  end
46
66
  end
47
67
 
68
+ # Selects all choices when Ctrl+A is pressed
69
+ #
70
+ # @api private
71
+ def keyctrl_a(*)
72
+ return if @max && @max < choices.size
73
+
74
+ @selected = SelectedChoices.new(choices.enabled, choices.enabled_indexes)
75
+ end
76
+
77
+ # Revert currently selected choices when Ctrl+I is pressed
78
+ #
79
+ # @api private
80
+ def keyctrl_r(*)
81
+ return if @max && @max < choices.size
82
+
83
+ indexes = choices.each_with_index.reduce([]) do |acc, (choice, idx)|
84
+ acc << idx if !choice.disabled? && !@selected.include?(choice)
85
+ acc
86
+ end
87
+ @selected = SelectedChoices.new(choices.enabled - @selected.to_a, indexes)
88
+ end
89
+
48
90
  private
49
91
 
50
92
  # Setup default options and active selection
@@ -53,12 +95,23 @@ module TTY
53
95
  def setup_defaults
54
96
  validate_defaults
55
97
  # At this stage, @choices matches all the visible choices.
56
- @selected = @choices.values_at(*@default.map { |d| d - 1 })
98
+ default_indexes = @default.map do |d|
99
+ if d.to_s =~ INTEGER_MATCHER
100
+ d - 1
101
+ else
102
+ choices.index(choices.find_by(:name, d.to_s))
103
+ end
104
+ end
105
+ @selected = SelectedChoices.new(@choices.values_at(*default_indexes),
106
+ default_indexes)
57
107
 
58
- if !@default.empty?
108
+ if @default.empty?
109
+ # no default, pick the first non-disabled choice
110
+ @active = choices.index { |choice| !choice.disabled? } + 1
111
+ elsif @default.last.to_s =~ INTEGER_MATCHER
59
112
  @active = @default.last
60
- else
61
- @active = @choices.index { |choice| !choice.disabled? } + 1
113
+ elsif default_choice = choices.find_by(:name, @default.last.to_s)
114
+ @active = choices.index(default_choice) + 1
62
115
  end
63
116
  end
64
117
 
@@ -68,37 +121,63 @@ module TTY
68
121
  #
69
122
  # @api private
70
123
  def selected_names
71
- @selected.map(&:name).join(', ')
124
+ @selected.map(&:name).join(", ")
72
125
  end
73
126
 
74
- # Header part showing the maximum number of choices
127
+ # Header part showing the minimum/maximum number of choices
75
128
  #
76
129
  # @return [String]
77
130
  #
78
131
  # @api private
79
- def max_help
80
- "(max. #{@max}) "
132
+ def minmax_help
133
+ help = []
134
+ help << "min. #{@min}" if @min
135
+ help << "max. #{@max}" if @max
136
+ "(%s) " % [help.join(", ")]
137
+ end
138
+
139
+ # Build a default help text
140
+ #
141
+ # @return [String]
142
+ #
143
+ # @api private
144
+ def default_help
145
+ str = []
146
+ str << "(Press "
147
+ str << "#{arrows_help} arrow"
148
+ str << " or 1-#{choices.size} number" if enumerate?
149
+ str << " to move, Space"
150
+ str << "/Ctrl+A|R" if @max.nil?
151
+ str << " to select"
152
+ str << " (all|rev)" if @max.nil?
153
+ str << (filterable? ? "," : " and")
154
+ str << " Enter to finish"
155
+ str << " and letters to filter" if filterable?
156
+ str << ")"
157
+ str.join
81
158
  end
82
159
 
83
160
  # Render initial help text and then currently selected choices
84
161
  #
85
162
  # @api private
86
163
  def render_header
87
- instructions = @prompt.decorate(help, :bright_black)
88
- max_suffix = @max ? max_help : ""
164
+ instructions = @prompt.decorate(help, @help_color)
165
+ minmax_suffix = @min || @max ? minmax_help : ""
166
+ print_selected = @selected.size.nonzero? && @echo
89
167
 
90
168
  if @done && @echo
91
169
  @prompt.decorate(selected_names, @active_color)
92
- elsif @selected.size.nonzero? && @echo
93
- help_suffix = filterable? && @filter.any? ? " #{filter_help}" : ""
94
- max_suffix + selected_names +
95
- (@first_render ? " #{instructions}" : help_suffix)
96
- elsif @first_render
97
- max_suffix + instructions
170
+ elsif (@first_render && (help_start? || help_always?)) ||
171
+ (help_always? && !@filter.any? && !@done)
172
+ minmax_suffix +
173
+ (print_selected ? "#{selected_names} " : "") +
174
+ instructions
98
175
  elsif filterable? && @filter.any?
99
- max_suffix + filter_help
100
- elsif @max
101
- max_help
176
+ minmax_suffix +
177
+ (print_selected ? "#{selected_names} " : "") +
178
+ @prompt.decorate(filter_help, @help_color)
179
+ else
180
+ minmax_suffix + (print_selected ? selected_names : "")
102
181
  end
103
182
  end
104
183
 
@@ -121,9 +200,9 @@ module TTY
121
200
 
122
201
  sync_paginators if @paging_changed
123
202
  paginator.paginate(choices, @active, @per_page) do |choice, index|
124
- num = enumerate? ? (index + 1).to_s + @enum + ' ' : ''
125
- indicator = (index + 1 == @active) ? @symbols[:marker] : ' '
126
- indicator += ' '
203
+ num = enumerate? ? (index + 1).to_s + @enum + " " : ""
204
+ indicator = (index + 1 == @active) ? @symbols[:marker] : " "
205
+ indicator += " "
127
206
  message = if @selected.include?(choice) && !choice.disabled?
128
207
  selected = @prompt.decorate(@symbols[:radio_on], @active_color)
129
208
  "#{selected} #{num}#{choice.name}"
@@ -134,7 +213,7 @@ module TTY
134
213
  "#{@symbols[:radio_off]} #{num}#{choice.name}"
135
214
  end
136
215
  end_index = paginated? ? paginator.end_index : choices.size - 1
137
- newline = (index == end_index) ? '' : "\n"
216
+ newline = (index == end_index) ? "" : "\n"
138
217
  output << indicator + message + newline
139
218
  end
140
219
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'question'
4
- require_relative 'symbols'
3
+ require_relative "question"
4
+ require_relative "symbols"
5
5
 
6
6
  module TTY
7
7
  class Prompt
@@ -9,9 +9,9 @@ module TTY
9
9
  #
10
10
  # @api private
11
11
  class Multiline < Question
12
- HELP = '(Press CTRL-D or CTRL-Z to finish)'.freeze
12
+ HELP = "(Press Ctrl+D or Ctrl+Z to finish)".freeze
13
13
 
14
- def initialize(prompt, options = {})
14
+ def initialize(prompt, **options)
15
15
  super
16
16
  @help = options[:help] || self.class::HELP
17
17
  @first_render = true
@@ -25,6 +25,7 @@ module TTY
25
25
  # @api public
26
26
  def help(value = (not_set = true))
27
27
  return @help if not_set
28
+
28
29
  @help = value
29
30
  end
30
31
 
@@ -42,7 +43,7 @@ module TTY
42
43
  if !echo?
43
44
  header
44
45
  elsif @done
45
- header << @prompt.decorate("#{@input}", @active_color)
46
+ header << @prompt.decorate(@input.to_s, @active_color)
46
47
  elsif @first_render
47
48
  header << @prompt.decorate(help, @help_color)
48
49
  @first_render = false
@@ -55,8 +56,9 @@ module TTY
55
56
  @prompt.print(question)
56
57
  @lines = read_input
57
58
  @input = "#{@lines.first.strip} ..." unless @lines.first.to_s.empty?
58
- if Utils.blank?(@input)
59
- @input = default? ? default : nil
59
+ if Utils.blank?(@input) && default?
60
+ @input = default
61
+ @lines = default
60
62
  end
61
63
  @evaluator.(@lines)
62
64
  end
@@ -40,7 +40,7 @@ module TTY
40
40
  #
41
41
  # @api private
42
42
  def check_page_size!
43
- raise InvalidArgument, 'per_page must be > 0' if @per_page < 1
43
+ raise InvalidArgument, "per_page must be > 0" if @per_page < 1
44
44
  end
45
45
 
46
46
  # Paginate collection given an active index
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'converters'
4
- require_relative 'evaluator'
5
- require_relative 'question/modifier'
6
- require_relative 'question/validation'
7
- require_relative 'question/checks'
8
- require_relative 'utils'
3
+ require_relative "converters"
4
+ require_relative "evaluator"
5
+ require_relative "question/modifier"
6
+ require_relative "question/validation"
7
+ require_relative "question/checks"
8
+ require_relative "utils"
9
9
 
10
10
  module TTY
11
11
  # A class responsible for shell prompt interactions.
@@ -35,23 +35,30 @@ module TTY
35
35
  #
36
36
  # @api public
37
37
  def initialize(prompt, **options)
38
- @prompt = prompt
39
- @prefix = options.fetch(:prefix) { @prompt.prefix }
40
- @default = options.fetch(:default) { UndefinedSetting }
41
- @required = options.fetch(:required) { false }
42
- @echo = options.fetch(:echo) { true }
43
- @in = options.fetch(:in) { UndefinedSetting }
44
- @modifier = options.fetch(:modifier) { [] }
45
- @validation = options.fetch(:validation) { UndefinedSetting }
46
- @convert = options.fetch(:convert) { UndefinedSetting }
38
+ # Option deprecation
39
+ if options[:validation]
40
+ warn "[DEPRECATION] The `:validation` option is deprecated. Use `:validate` instead."
41
+ options[:validate] = options[:validation]
42
+ end
43
+
44
+ @prompt = prompt
45
+ @prefix = options.fetch(:prefix) { @prompt.prefix }
46
+ @default = options.fetch(:default) { UndefinedSetting }
47
+ @required = options.fetch(:required) { false }
48
+ @echo = options.fetch(:echo) { true }
49
+ @in = options.fetch(:in) { UndefinedSetting }
50
+ @modifier = options.fetch(:modifier) { [] }
51
+ @validation = options.fetch(:validate) { UndefinedSetting }
52
+ @convert = options.fetch(:convert) { UndefinedSetting }
47
53
  @active_color = options.fetch(:active_color) { @prompt.active_color }
48
- @help_color = options.fetch(:help_color) { @prompt.help_color }
49
- @error_color = options.fetch(:error_color) { :red }
50
- @value = options.fetch(:value) { UndefinedSetting }
51
- @messages = Utils.deep_copy(options.fetch(:messages) { { } })
52
- @done = false
54
+ @help_color = options.fetch(:help_color) { @prompt.help_color }
55
+ @error_color = options.fetch(:error_color) { :red }
56
+ @value = options.fetch(:value) { UndefinedSetting }
57
+ @quiet = options.fetch(:quiet) { @prompt.quiet }
58
+ @messages = Utils.deep_copy(options.fetch(:messages) { {} })
59
+ @done = false
53
60
  @first_render = true
54
- @input = nil
61
+ @input = nil
55
62
 
56
63
  @evaluator = Evaluator.new(self)
57
64
 
@@ -60,6 +67,7 @@ module TTY
60
67
  @evaluator << CheckRange
61
68
  @evaluator << CheckValidation
62
69
  @evaluator << CheckModifier
70
+ @evaluator << CheckConversion
63
71
  end
64
72
 
65
73
  # Stores all the error messages displayed to user
@@ -85,7 +93,7 @@ module TTY
85
93
  if template && !template.match(/\%\{/).nil?
86
94
  [template % tokens]
87
95
  else
88
- [template || '']
96
+ [template || ""]
89
97
  end
90
98
  end
91
99
 
@@ -96,7 +104,7 @@ module TTY
96
104
  # @return [self]
97
105
  #
98
106
  # @api public
99
- def call(message = '', &block)
107
+ def call(message = "", &block)
100
108
  @message = message
101
109
  block.call(self) if block
102
110
  @prompt.subscribe(self) do
@@ -122,8 +130,8 @@ module TTY
122
130
  total_lines = @prompt.count_screen_lines(input_line)
123
131
  @prompt.print(refresh(question.lines.count, total_lines))
124
132
  end
125
- @prompt.print(render_question)
126
- convert_result(result.value)
133
+ @prompt.print(render_question) unless @quiet
134
+ result.value
127
135
  end
128
136
 
129
137
  # Render question
@@ -141,7 +149,7 @@ module TTY
141
149
  elsif @done
142
150
  header << @prompt.decorate(@input.to_s, @active_color)
143
151
  elsif default? && !Utils.blank?(@default)
144
- header << @prompt.decorate("(#{default})", @help_color) + ' '
152
+ header << @prompt.decorate("(#{default})", @help_color) + " "
145
153
  end
146
154
  header << "\n" if @done
147
155
  header.join
@@ -162,12 +170,12 @@ module TTY
162
170
  #
163
171
  # @api private
164
172
  def read_input(question)
165
- options = {echo: echo}
173
+ options = { echo: echo }
166
174
  if value? && @first_render
167
175
  options[:value] = @value
168
176
  @first_render = false
169
177
  end
170
- @prompt.read_line(question, options).chomp
178
+ @prompt.read_line(question, **options).chomp
171
179
  end
172
180
 
173
181
  # Handle error condition
@@ -177,7 +185,7 @@ module TTY
177
185
  # @api private
178
186
  def render_error(errors)
179
187
  errors.reduce([]) do |acc, err|
180
- acc << @prompt.decorate('>>', :red) + ' ' + err
188
+ acc << @prompt.decorate(">>", :red) + " " + err
181
189
  acc
182
190
  end.join("\n")
183
191
  end
@@ -211,8 +219,13 @@ module TTY
211
219
  #
212
220
  # @api private
213
221
  def convert_result(value)
214
- if convert? & !Utils.blank?(value)
215
- Converters.convert(@convert, value)
222
+ if convert? && !Utils.blank?(value)
223
+ case @convert
224
+ when Proc
225
+ @convert.call(value)
226
+ else
227
+ Converters.convert(@convert, value)
228
+ end
216
229
  else
217
230
  value
218
231
  end
@@ -221,8 +234,13 @@ module TTY
221
234
  # Specify answer conversion
222
235
  #
223
236
  # @api public
224
- def convert(value)
225
- @convert = value
237
+ def convert(value = (not_set = true), message = nil)
238
+ messages[:convert?] = message if message
239
+ if not_set
240
+ @convert
241
+ else
242
+ @convert = value
243
+ end
226
244
  end
227
245
 
228
246
  # Check if conversion is set
@@ -239,6 +257,7 @@ module TTY
239
257
  # @api public
240
258
  def default(value = (not_set = true))
241
259
  return @default if not_set
260
+
242
261
  @default = value
243
262
  end
244
263
 
@@ -259,9 +278,10 @@ module TTY
259
278
  def required(value = (not_set = true), message = nil)
260
279
  messages[:required?] = message if message
261
280
  return @required if not_set
281
+
262
282
  @required = value
263
283
  end
264
- alias_method :required?, :required
284
+ alias required? required
265
285
 
266
286
  # Set validation rule for an argument
267
287
  #
@@ -280,6 +300,7 @@ module TTY
280
300
  # @api public
281
301
  def value(val)
282
302
  return @value if val.nil?
303
+
283
304
  @value = val
284
305
  end
285
306
 
@@ -309,18 +330,20 @@ module TTY
309
330
  # @api public
310
331
  def echo(value = nil)
311
332
  return @echo if value.nil?
333
+
312
334
  @echo = value
313
335
  end
314
- alias_method :echo?, :echo
336
+ alias echo? echo
315
337
 
316
338
  # Turn raw mode on or off. This enables character-based input.
317
339
  #
318
340
  # @api public
319
341
  def raw(value = nil)
320
342
  return @raw if value.nil?
343
+
321
344
  @raw = value
322
345
  end
323
- alias_method :raw?, :raw
346
+ alias raw? raw
324
347
 
325
348
  # Set expected range of values
326
349
  #
@@ -333,6 +356,7 @@ module TTY
333
356
  @in = Converters.convert(:range, @in)
334
357
  end
335
358
  return @in if not_set
359
+
336
360
  @in = Converters.convert(:range, value)
337
361
  end
338
362
 
@@ -345,6 +369,13 @@ module TTY
345
369
  @in != UndefinedSetting
346
370
  end
347
371
 
372
+ # Set quiet mode.
373
+ #
374
+ # @api public
375
+ def quiet(value)
376
+ @quiet = value
377
+ end
378
+
348
379
  # @api public
349
380
  def to_s
350
381
  message.to_s