truex-skylight 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +277 -0
  3. data/CLA.md +9 -0
  4. data/CONTRIBUTING.md +1 -0
  5. data/LICENSE.md +79 -0
  6. data/README.md +4 -0
  7. data/bin/skylight +3 -0
  8. data/ext/extconf.rb +186 -0
  9. data/ext/libskylight.yml +6 -0
  10. data/ext/skylight_memprof.c +115 -0
  11. data/ext/skylight_native.c +416 -0
  12. data/ext/skylight_native.h +20 -0
  13. data/lib/skylight.rb +2 -0
  14. data/lib/skylight/api.rb +79 -0
  15. data/lib/skylight/cli.rb +146 -0
  16. data/lib/skylight/compat.rb +47 -0
  17. data/lib/skylight/config.rb +498 -0
  18. data/lib/skylight/core.rb +122 -0
  19. data/lib/skylight/data/cacert.pem +3894 -0
  20. data/lib/skylight/formatters/http.rb +17 -0
  21. data/lib/skylight/gc.rb +107 -0
  22. data/lib/skylight/helpers.rb +137 -0
  23. data/lib/skylight/instrumenter.rb +290 -0
  24. data/lib/skylight/middleware.rb +75 -0
  25. data/lib/skylight/native.rb +69 -0
  26. data/lib/skylight/normalizers.rb +133 -0
  27. data/lib/skylight/normalizers/action_controller/process_action.rb +35 -0
  28. data/lib/skylight/normalizers/action_controller/send_file.rb +76 -0
  29. data/lib/skylight/normalizers/action_view/render_collection.rb +18 -0
  30. data/lib/skylight/normalizers/action_view/render_partial.rb +18 -0
  31. data/lib/skylight/normalizers/action_view/render_template.rb +18 -0
  32. data/lib/skylight/normalizers/active_record/sql.rb +79 -0
  33. data/lib/skylight/normalizers/active_support/cache.rb +50 -0
  34. data/lib/skylight/normalizers/active_support/cache_clear.rb +16 -0
  35. data/lib/skylight/normalizers/active_support/cache_decrement.rb +16 -0
  36. data/lib/skylight/normalizers/active_support/cache_delete.rb +16 -0
  37. data/lib/skylight/normalizers/active_support/cache_exist.rb +16 -0
  38. data/lib/skylight/normalizers/active_support/cache_fetch_hit.rb +16 -0
  39. data/lib/skylight/normalizers/active_support/cache_generate.rb +16 -0
  40. data/lib/skylight/normalizers/active_support/cache_increment.rb +16 -0
  41. data/lib/skylight/normalizers/active_support/cache_read.rb +16 -0
  42. data/lib/skylight/normalizers/active_support/cache_read_multi.rb +16 -0
  43. data/lib/skylight/normalizers/active_support/cache_write.rb +16 -0
  44. data/lib/skylight/normalizers/default.rb +21 -0
  45. data/lib/skylight/normalizers/moped/query.rb +141 -0
  46. data/lib/skylight/probes.rb +91 -0
  47. data/lib/skylight/probes/excon.rb +25 -0
  48. data/lib/skylight/probes/excon/middleware.rb +65 -0
  49. data/lib/skylight/probes/net_http.rb +44 -0
  50. data/lib/skylight/probes/redis.rb +30 -0
  51. data/lib/skylight/probes/sequel.rb +30 -0
  52. data/lib/skylight/probes/sinatra.rb +74 -0
  53. data/lib/skylight/probes/tilt.rb +27 -0
  54. data/lib/skylight/railtie.rb +122 -0
  55. data/lib/skylight/sinatra.rb +4 -0
  56. data/lib/skylight/subscriber.rb +92 -0
  57. data/lib/skylight/trace.rb +191 -0
  58. data/lib/skylight/util.rb +16 -0
  59. data/lib/skylight/util/allocation_free.rb +17 -0
  60. data/lib/skylight/util/clock.rb +53 -0
  61. data/lib/skylight/util/gzip.rb +15 -0
  62. data/lib/skylight/util/hostname.rb +17 -0
  63. data/lib/skylight/util/http.rb +218 -0
  64. data/lib/skylight/util/inflector.rb +110 -0
  65. data/lib/skylight/util/logging.rb +87 -0
  66. data/lib/skylight/util/multi_io.rb +21 -0
  67. data/lib/skylight/util/native_ext_fetcher.rb +205 -0
  68. data/lib/skylight/util/platform.rb +67 -0
  69. data/lib/skylight/util/ssl.rb +50 -0
  70. data/lib/skylight/vendor/active_support/notifications.rb +207 -0
  71. data/lib/skylight/vendor/active_support/notifications/fanout.rb +159 -0
  72. data/lib/skylight/vendor/active_support/notifications/instrumenter.rb +72 -0
  73. data/lib/skylight/vendor/active_support/per_thread_registry.rb +52 -0
  74. data/lib/skylight/vendor/cli/highline.rb +1034 -0
  75. data/lib/skylight/vendor/cli/highline/color_scheme.rb +134 -0
  76. data/lib/skylight/vendor/cli/highline/compatibility.rb +16 -0
  77. data/lib/skylight/vendor/cli/highline/import.rb +41 -0
  78. data/lib/skylight/vendor/cli/highline/menu.rb +381 -0
  79. data/lib/skylight/vendor/cli/highline/question.rb +481 -0
  80. data/lib/skylight/vendor/cli/highline/simulate.rb +48 -0
  81. data/lib/skylight/vendor/cli/highline/string_extensions.rb +111 -0
  82. data/lib/skylight/vendor/cli/highline/style.rb +181 -0
  83. data/lib/skylight/vendor/cli/highline/system_extensions.rb +242 -0
  84. data/lib/skylight/vendor/cli/thor.rb +473 -0
  85. data/lib/skylight/vendor/cli/thor/actions.rb +318 -0
  86. data/lib/skylight/vendor/cli/thor/actions/create_file.rb +105 -0
  87. data/lib/skylight/vendor/cli/thor/actions/create_link.rb +60 -0
  88. data/lib/skylight/vendor/cli/thor/actions/directory.rb +119 -0
  89. data/lib/skylight/vendor/cli/thor/actions/empty_directory.rb +137 -0
  90. data/lib/skylight/vendor/cli/thor/actions/file_manipulation.rb +314 -0
  91. data/lib/skylight/vendor/cli/thor/actions/inject_into_file.rb +109 -0
  92. data/lib/skylight/vendor/cli/thor/base.rb +652 -0
  93. data/lib/skylight/vendor/cli/thor/command.rb +136 -0
  94. data/lib/skylight/vendor/cli/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  95. data/lib/skylight/vendor/cli/thor/core_ext/io_binary_read.rb +12 -0
  96. data/lib/skylight/vendor/cli/thor/core_ext/ordered_hash.rb +100 -0
  97. data/lib/skylight/vendor/cli/thor/error.rb +28 -0
  98. data/lib/skylight/vendor/cli/thor/group.rb +282 -0
  99. data/lib/skylight/vendor/cli/thor/invocation.rb +172 -0
  100. data/lib/skylight/vendor/cli/thor/parser.rb +4 -0
  101. data/lib/skylight/vendor/cli/thor/parser/argument.rb +74 -0
  102. data/lib/skylight/vendor/cli/thor/parser/arguments.rb +171 -0
  103. data/lib/skylight/vendor/cli/thor/parser/option.rb +121 -0
  104. data/lib/skylight/vendor/cli/thor/parser/options.rb +218 -0
  105. data/lib/skylight/vendor/cli/thor/rake_compat.rb +72 -0
  106. data/lib/skylight/vendor/cli/thor/runner.rb +322 -0
  107. data/lib/skylight/vendor/cli/thor/shell.rb +88 -0
  108. data/lib/skylight/vendor/cli/thor/shell/basic.rb +393 -0
  109. data/lib/skylight/vendor/cli/thor/shell/color.rb +148 -0
  110. data/lib/skylight/vendor/cli/thor/shell/html.rb +127 -0
  111. data/lib/skylight/vendor/cli/thor/util.rb +270 -0
  112. data/lib/skylight/vendor/cli/thor/version.rb +3 -0
  113. data/lib/skylight/vendor/thread_safe.rb +126 -0
  114. data/lib/skylight/vendor/thread_safe/non_concurrent_cache_backend.rb +133 -0
  115. data/lib/skylight/vendor/thread_safe/synchronized_cache_backend.rb +76 -0
  116. data/lib/skylight/version.rb +4 -0
  117. data/lib/skylight/vm/gc.rb +70 -0
  118. data/lib/sql_lexer.rb +6 -0
  119. data/lib/sql_lexer/lexer.rb +579 -0
  120. data/lib/sql_lexer/string_scanner.rb +11 -0
  121. data/lib/sql_lexer/version.rb +3 -0
  122. metadata +179 -0
@@ -0,0 +1,481 @@
1
+ # question.rb
2
+ #
3
+ # Created by James Edward Gray II on 2005-04-26.
4
+ # Copyright 2005 Gray Productions. All rights reserved.
5
+ #
6
+ # This is Free Software. See LICENSE and COPYING for details.
7
+
8
+ require "optparse"
9
+ require "date"
10
+ require "pathname"
11
+
12
+ class HighLine
13
+ #
14
+ # Question objects contain all the details of a single invocation of
15
+ # HighLine.ask(). The object is initialized by the parameters passed to
16
+ # HighLine.ask() and then queried to make sure each step of the input
17
+ # process is handled according to the users wishes.
18
+ #
19
+ class Question
20
+ # An internal HighLine error. User code does not need to trap this.
21
+ class NoAutoCompleteMatch < StandardError
22
+ # do nothing, just creating a unique error type
23
+ end
24
+
25
+ #
26
+ # Create an instance of HighLine::Question. Expects a _question_ to ask
27
+ # (can be <tt>""</tt>) and an _answer_type_ to convert the answer to.
28
+ # The _answer_type_ parameter must be a type recognized by
29
+ # Question.convert(). If given, a block is yielded the new Question
30
+ # object to allow custom initialization.
31
+ #
32
+ def initialize( question, answer_type )
33
+ # initialize instance data
34
+ @question = question.dup
35
+ @answer_type = answer_type
36
+ @completion = @answer_type
37
+
38
+ @character = nil
39
+ @limit = nil
40
+ @echo = true
41
+ @readline = false
42
+ @whitespace = :strip
43
+ @case = nil
44
+ @default = nil
45
+ @validate = nil
46
+ @above = nil
47
+ @below = nil
48
+ @in = nil
49
+ @confirm = nil
50
+ @gather = false
51
+ @verify_match = false
52
+ @first_answer = nil
53
+ @directory = Pathname.new(File.expand_path(File.dirname($0)))
54
+ @glob = "*"
55
+ @responses = Hash.new
56
+ @overwrite = false
57
+
58
+ # allow block to override settings
59
+ yield self if block_given?
60
+
61
+ # finalize responses based on settings
62
+ build_responses
63
+ end
64
+
65
+ # The ERb template of the question to be asked.
66
+ attr_accessor :question
67
+ # The type that will be used to convert this answer.
68
+ attr_accessor :answer_type
69
+ # For Auto-completion
70
+ attr_accessor :completion
71
+ #
72
+ # Can be set to +true+ to use HighLine's cross-platform character reader
73
+ # instead of fetching an entire line of input. (Note: HighLine's character
74
+ # reader *ONLY* supports STDIN on Windows and Unix.) Can also be set to
75
+ # <tt>:getc</tt> to use that method on the input stream.
76
+ #
77
+ # *WARNING*: The _echo_ and _overwrite_ attributes for a question are
78
+ # ignored when using the <tt>:getc</tt> method.
79
+ #
80
+ attr_accessor :character
81
+ #
82
+ # Allows you to set a character limit for input.
83
+ #
84
+ # *WARNING*: This option forces a character by character read.
85
+ #
86
+ attr_accessor :limit
87
+ #
88
+ # Can be set to +true+ or +false+ to control whether or not input will
89
+ # be echoed back to the user. A setting of +true+ will cause echo to
90
+ # match input, but any other true value will be treated as a String to
91
+ # echo for each character typed.
92
+ #
93
+ # This requires HighLine's character reader. See the _character_
94
+ # attribute for details.
95
+ #
96
+ # *Note*: When using HighLine to manage echo on Unix based systems, we
97
+ # recommend installing the termios gem. Without it, it's possible to type
98
+ # fast enough to have letters still show up (when reading character by
99
+ # character only).
100
+ #
101
+ attr_accessor :echo
102
+ #
103
+ # Use the Readline library to fetch input. This allows input editing as
104
+ # well as keeping a history. In addition, tab will auto-complete
105
+ # within an Array of choices or a file listing.
106
+ #
107
+ # *WARNING*: This option is incompatible with all of HighLine's
108
+ # character reading modes and it causes HighLine to ignore the
109
+ # specified _input_ stream.
110
+ #
111
+ attr_accessor :readline
112
+ #
113
+ # Used to control whitespace processing for the answer to this question.
114
+ # See HighLine::Question.remove_whitespace() for acceptable settings.
115
+ #
116
+ attr_accessor :whitespace
117
+ #
118
+ # Used to control character case processing for the answer to this question.
119
+ # See HighLine::Question.change_case() for acceptable settings.
120
+ #
121
+ attr_accessor :case
122
+ # Used to provide a default answer to this question.
123
+ attr_accessor :default
124
+ #
125
+ # If set to a Regexp, the answer must match (before type conversion).
126
+ # Can also be set to a Proc which will be called with the provided
127
+ # answer to validate with a +true+ or +false+ return.
128
+ #
129
+ attr_accessor :validate
130
+ # Used to control range checks for answer.
131
+ attr_accessor :above, :below
132
+ # If set, answer must pass an include?() check on this object.
133
+ attr_accessor :in
134
+ #
135
+ # Asks a yes or no confirmation question, to ensure a user knows what
136
+ # they have just agreed to. If set to +true+ the question will be,
137
+ # "Are you sure? " Any other true value for this attribute is assumed
138
+ # to be the question to ask. When +false+ or +nil+ (the default),
139
+ # answers are not confirmed.
140
+ #
141
+ attr_accessor :confirm
142
+ #
143
+ # When set, the user will be prompted for multiple answers which will
144
+ # be collected into an Array or Hash and returned as the final answer.
145
+ #
146
+ # You can set _gather_ to an Integer to have an Array of exactly that
147
+ # many answers collected, or a String/Regexp to match an end input which
148
+ # will not be returned in the Array.
149
+ #
150
+ # Optionally _gather_ can be set to a Hash. In this case, the question
151
+ # will be asked once for each key and the answers will be returned in a
152
+ # Hash, mapped by key. The <tt>@key</tt> variable is set before each
153
+ # question is evaluated, so you can use it in your question.
154
+ #
155
+ attr_accessor :gather
156
+ #
157
+ # When set to +true+ multiple entries will be collected according to
158
+ # the setting for _gather_, except they will be required to match
159
+ # each other. Multiple identical entries will return a single answer.
160
+ #
161
+ attr_accessor :verify_match
162
+ #
163
+ # When set to a non *nil* value, this will be tried as an answer to the
164
+ # question. If this answer passes validations, it will become the result
165
+ # without the user ever being prompted. Otherwise this value is discarded,
166
+ # and this Question is resolved as a normal call to HighLine.ask().
167
+ #
168
+ attr_writer :first_answer
169
+ #
170
+ # The directory from which a user will be allowed to select files, when
171
+ # File or Pathname is specified as an _answer_type_. Initially set to
172
+ # <tt>Pathname.new(File.expand_path(File.dirname($0)))</tt>.
173
+ #
174
+ attr_accessor :directory
175
+ #
176
+ # The glob pattern used to limit file selection when File or Pathname is
177
+ # specified as an _answer_type_. Initially set to <tt>"*"</tt>.
178
+ #
179
+ attr_accessor :glob
180
+ #
181
+ # A Hash that stores the various responses used by HighLine to notify
182
+ # the user. The currently used responses and their purpose are as
183
+ # follows:
184
+ #
185
+ # <tt>:ambiguous_completion</tt>:: Used to notify the user of an
186
+ # ambiguous answer the auto-completion
187
+ # system cannot resolve.
188
+ # <tt>:ask_on_error</tt>:: This is the question that will be
189
+ # redisplayed to the user in the event
190
+ # of an error. Can be set to
191
+ # <tt>:question</tt> to repeat the
192
+ # original question.
193
+ # <tt>:invalid_type</tt>:: The error message shown when a type
194
+ # conversion fails.
195
+ # <tt>:no_completion</tt>:: Used to notify the user that their
196
+ # selection does not have a valid
197
+ # auto-completion match.
198
+ # <tt>:not_in_range</tt>:: Used to notify the user that a
199
+ # provided answer did not satisfy
200
+ # the range requirement tests.
201
+ # <tt>:not_valid</tt>:: The error message shown when
202
+ # validation checks fail.
203
+ #
204
+ attr_reader :responses
205
+ #
206
+ # When set to +true+ the question is asked, but output does not progress to
207
+ # the next line. The Cursor is moved back to the beginning of the question
208
+ # line and it is cleared so that all the contents of the line disappear from
209
+ # the screen.
210
+ #
211
+ attr_accessor :overwrite
212
+
213
+ #
214
+ # Returns the provided _answer_string_ or the default answer for this
215
+ # Question if a default was set and the answer is empty.
216
+ #
217
+ def answer_or_default( answer_string )
218
+ if answer_string.length == 0 and not @default.nil?
219
+ @default
220
+ else
221
+ answer_string
222
+ end
223
+ end
224
+
225
+ #
226
+ # Called late in the initialization process to build intelligent
227
+ # responses based on the details of this Question object.
228
+ # Also used by Menu#update_responses.
229
+ #
230
+ def build_responses(message_source = answer_type, new_hash_wins = false)
231
+
232
+ append_default unless default.nil?
233
+
234
+ choice_error_str_func = lambda do
235
+ message_source.is_a?(Array) \
236
+ ? '[' + message_source.map { |s| "#{s}" }.join(', ') + ']' \
237
+ : message_source.inspect
238
+ end
239
+
240
+ old_hash = @responses
241
+
242
+ new_hash = { :ambiguous_completion =>
243
+ "Ambiguous choice. Please choose one of " +
244
+ choice_error_str_func.call + '.',
245
+ :ask_on_error =>
246
+ "? ",
247
+ :invalid_type =>
248
+ "You must enter a valid #{message_source}.",
249
+ :no_completion =>
250
+ "You must choose one of " + choice_error_str_func.call + '.',
251
+ :not_in_range =>
252
+ "Your answer isn't within the expected range " +
253
+ "(#{expected_range}).",
254
+ :mismatch =>
255
+ "Your entries didn't match.",
256
+ :not_valid =>
257
+ "Your answer isn't valid (must match " +
258
+ "#{@validate.inspect})." }
259
+
260
+ @responses = new_hash_wins ? old_hash.merge(new_hash) : new_hash.merge(old_hash)
261
+ end
262
+
263
+ #
264
+ # Returns the provided _answer_string_ after changing character case by
265
+ # the rules of this Question. Valid settings for whitespace are:
266
+ #
267
+ # +nil+:: Do not alter character case.
268
+ # (Default.)
269
+ # <tt>:up</tt>:: Calls upcase().
270
+ # <tt>:upcase</tt>:: Calls upcase().
271
+ # <tt>:down</tt>:: Calls downcase().
272
+ # <tt>:downcase</tt>:: Calls downcase().
273
+ # <tt>:capitalize</tt>:: Calls capitalize().
274
+ #
275
+ # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
276
+ #
277
+ def change_case( answer_string )
278
+ if [:up, :upcase].include?(@case)
279
+ answer_string.upcase
280
+ elsif [:down, :downcase].include?(@case)
281
+ answer_string.downcase
282
+ elsif @case == :capitalize
283
+ answer_string.capitalize
284
+ else
285
+ answer_string
286
+ end
287
+ end
288
+
289
+ #
290
+ # Transforms the given _answer_string_ into the expected type for this
291
+ # Question. Currently supported conversions are:
292
+ #
293
+ # <tt>[...]</tt>:: Answer must be a member of the passed Array.
294
+ # Auto-completion is used to expand partial
295
+ # answers.
296
+ # <tt>lambda {...}</tt>:: Answer is passed to lambda for conversion.
297
+ # Date:: Date.parse() is called with answer.
298
+ # DateTime:: DateTime.parse() is called with answer.
299
+ # File:: The entered file name is auto-completed in
300
+ # terms of _directory_ + _glob_, opened, and
301
+ # returned.
302
+ # Float:: Answer is converted with Kernel.Float().
303
+ # Integer:: Answer is converted with Kernel.Integer().
304
+ # +nil+:: Answer is left in String format. (Default.)
305
+ # Pathname:: Same as File, save that a Pathname object is
306
+ # returned.
307
+ # String:: Answer is converted with Kernel.String().
308
+ # HighLine::String:: Answer is converted with HighLine::String()
309
+ # Regexp:: Answer is fed to Regexp.new().
310
+ # Symbol:: The method to_sym() is called on answer and
311
+ # the result returned.
312
+ # <i>any other Class</i>:: The answer is passed on to
313
+ # <tt>Class.parse()</tt>.
314
+ #
315
+ # This method throws ArgumentError, if the conversion cannot be
316
+ # completed for any reason.
317
+ #
318
+ def convert( answer_string )
319
+ if @answer_type.nil?
320
+ answer_string
321
+ elsif [::String, HighLine::String].include?(@answer_type)
322
+ HighLine::String(answer_string)
323
+ elsif [Float, Integer, String].include?(@answer_type)
324
+ Kernel.send(@answer_type.to_s.to_sym, answer_string)
325
+ elsif @answer_type == Symbol
326
+ answer_string.to_sym
327
+ elsif @answer_type == Regexp
328
+ Regexp.new(answer_string)
329
+ elsif @answer_type.is_a?(Array) or [File, Pathname].include?(@answer_type)
330
+ # cheating, using OptionParser's Completion module
331
+ choices = selection
332
+ choices.extend(OptionParser::Completion)
333
+ answer = choices.complete(answer_string)
334
+ if answer.nil?
335
+ raise NoAutoCompleteMatch
336
+ end
337
+ if @answer_type.is_a?(Array)
338
+ answer.last
339
+ elsif @answer_type == File
340
+ File.open(File.join(@directory.to_s, answer.last))
341
+ else
342
+ Pathname.new(File.join(@directory.to_s, answer.last))
343
+ end
344
+ elsif [Date, DateTime].include?(@answer_type) or @answer_type.is_a?(Class)
345
+ @answer_type.parse(answer_string)
346
+ elsif @answer_type.is_a?(Proc)
347
+ @answer_type[answer_string]
348
+ end
349
+ end
350
+
351
+ # Returns an English explanation of the current range settings.
352
+ def expected_range( )
353
+ expected = [ ]
354
+
355
+ expected << "above #{@above}" unless @above.nil?
356
+ expected << "below #{@below}" unless @below.nil?
357
+ expected << "included in #{@in.inspect}" unless @in.nil?
358
+
359
+ case expected.size
360
+ when 0 then ""
361
+ when 1 then expected.first
362
+ when 2 then expected.join(" and ")
363
+ else expected[0..-2].join(", ") + ", and #{expected.last}"
364
+ end
365
+ end
366
+
367
+ # Returns _first_answer_, which will be unset following this call.
368
+ def first_answer( )
369
+ @first_answer
370
+ ensure
371
+ @first_answer = nil
372
+ end
373
+
374
+ # Returns true if _first_answer_ is set.
375
+ def first_answer?( )
376
+ not @first_answer.nil?
377
+ end
378
+
379
+ #
380
+ # Returns +true+ if the _answer_object_ is greater than the _above_
381
+ # attribute, less than the _below_ attribute and include?()ed in the
382
+ # _in_ attribute. Otherwise, +false+ is returned. Any +nil+ attributes
383
+ # are not checked.
384
+ #
385
+ def in_range?( answer_object )
386
+ (@above.nil? or answer_object > @above) and
387
+ (@below.nil? or answer_object < @below) and
388
+ (@in.nil? or @in.include?(answer_object))
389
+ end
390
+
391
+ #
392
+ # Returns the provided _answer_string_ after processing whitespace by
393
+ # the rules of this Question. Valid settings for whitespace are:
394
+ #
395
+ # +nil+:: Do not alter whitespace.
396
+ # <tt>:strip</tt>:: Calls strip(). (Default.)
397
+ # <tt>:chomp</tt>:: Calls chomp().
398
+ # <tt>:collapse</tt>:: Collapses all whitespace runs to a
399
+ # single space.
400
+ # <tt>:strip_and_collapse</tt>:: Calls strip(), then collapses all
401
+ # whitespace runs to a single space.
402
+ # <tt>:chomp_and_collapse</tt>:: Calls chomp(), then collapses all
403
+ # whitespace runs to a single space.
404
+ # <tt>:remove</tt>:: Removes all whitespace.
405
+ #
406
+ # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
407
+ #
408
+ # This process is skipped for single character input.
409
+ #
410
+ def remove_whitespace( answer_string )
411
+ if @whitespace.nil?
412
+ answer_string
413
+ elsif [:strip, :chomp].include?(@whitespace)
414
+ answer_string.send(@whitespace)
415
+ elsif @whitespace == :collapse
416
+ answer_string.gsub(/\s+/, " ")
417
+ elsif [:strip_and_collapse, :chomp_and_collapse].include?(@whitespace)
418
+ result = answer_string.send(@whitespace.to_s[/^[a-z]+/])
419
+ result.gsub(/\s+/, " ")
420
+ elsif @whitespace == :remove
421
+ answer_string.gsub(/\s+/, "")
422
+ else
423
+ answer_string
424
+ end
425
+ end
426
+
427
+ #
428
+ # Returns an Array of valid answers to this question. These answers are
429
+ # only known when _answer_type_ is set to an Array of choices, File, or
430
+ # Pathname. Any other time, this method will return an empty Array.
431
+ #
432
+ def selection( )
433
+ if @completion.is_a?(Array)
434
+ @completion
435
+ elsif [File, Pathname].include?(@completion)
436
+ Dir[File.join(@directory.to_s, @glob)].map do |file|
437
+ File.basename(file)
438
+ end
439
+ else
440
+ [ ]
441
+ end
442
+ end
443
+
444
+ # Stringifies the question to be asked.
445
+ def to_str( )
446
+ @question
447
+ end
448
+
449
+ #
450
+ # Returns +true+ if the provided _answer_string_ is accepted by the
451
+ # _validate_ attribute or +false+ if it's not.
452
+ #
453
+ # It's important to realize that an answer is validated after whitespace
454
+ # and case handling.
455
+ #
456
+ def valid_answer?( answer_string )
457
+ @validate.nil? or
458
+ (@validate.is_a?(Regexp) and answer_string =~ @validate) or
459
+ (@validate.is_a?(Proc) and @validate[answer_string])
460
+ end
461
+
462
+ private
463
+
464
+ #
465
+ # Adds the default choice to the end of question between <tt>|...|</tt>.
466
+ # Trailing whitespace is preserved so the function of HighLine.say() is
467
+ # not affected.
468
+ #
469
+ def append_default( )
470
+ if @question =~ /([\t ]+)\Z/
471
+ @question << "|#{@default}|#{$1}"
472
+ elsif @question == ""
473
+ @question << "|#{@default}| "
474
+ elsif @question[-1, 1] == "\n"
475
+ @question[-2, 0] = " |#{@default}|"
476
+ else
477
+ @question << " |#{@default}|"
478
+ end
479
+ end
480
+ end
481
+ end