skylight 0.0.7 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/bin/skylight +5 -0
  3. data/lib/skylight.rb +2 -0
  4. data/lib/skylight/cli.rb +84 -0
  5. data/lib/skylight/config.rb +53 -6
  6. data/lib/skylight/instrumenter.rb +4 -1
  7. data/lib/skylight/json_proto.rb +0 -3
  8. data/lib/skylight/middleware.rb +1 -0
  9. data/lib/skylight/normalize.rb +30 -5
  10. data/lib/skylight/normalize/process_action.rb +1 -1
  11. data/lib/skylight/normalize/render_collection.rb +2 -6
  12. data/lib/skylight/normalize/render_partial.rb +2 -5
  13. data/lib/skylight/normalize/render_template.rb +2 -5
  14. data/lib/skylight/normalize/sql.rb +2 -4
  15. data/lib/skylight/railtie.rb +30 -33
  16. data/lib/skylight/sanity_checker.rb +73 -0
  17. data/lib/skylight/subscriber.rb +1 -15
  18. data/lib/skylight/trace.rb +30 -5
  19. data/lib/skylight/util/http.rb +97 -0
  20. data/lib/skylight/vendor/highline.rb +1012 -0
  21. data/lib/skylight/vendor/highline/color_scheme.rb +134 -0
  22. data/lib/skylight/vendor/highline/compatibility.rb +16 -0
  23. data/lib/skylight/vendor/highline/import.rb +41 -0
  24. data/lib/skylight/vendor/highline/menu.rb +398 -0
  25. data/lib/skylight/vendor/highline/question.rb +475 -0
  26. data/lib/skylight/vendor/highline/simulate.rb +48 -0
  27. data/lib/skylight/vendor/highline/string_extensions.rb +131 -0
  28. data/lib/skylight/vendor/highline/style.rb +181 -0
  29. data/lib/skylight/vendor/highline/system_extensions.rb +218 -0
  30. data/lib/skylight/vendor/thor.rb +473 -0
  31. data/lib/skylight/vendor/thor/actions.rb +318 -0
  32. data/lib/skylight/vendor/thor/actions/create_file.rb +105 -0
  33. data/lib/skylight/vendor/thor/actions/create_link.rb +60 -0
  34. data/lib/skylight/vendor/thor/actions/directory.rb +119 -0
  35. data/lib/skylight/vendor/thor/actions/empty_directory.rb +137 -0
  36. data/lib/skylight/vendor/thor/actions/file_manipulation.rb +314 -0
  37. data/lib/skylight/vendor/thor/actions/inject_into_file.rb +109 -0
  38. data/lib/skylight/vendor/thor/base.rb +652 -0
  39. data/lib/skylight/vendor/thor/command.rb +136 -0
  40. data/lib/skylight/vendor/thor/core_ext/hash_with_indifferent_access.rb +80 -0
  41. data/lib/skylight/vendor/thor/core_ext/io_binary_read.rb +12 -0
  42. data/lib/skylight/vendor/thor/core_ext/ordered_hash.rb +100 -0
  43. data/lib/skylight/vendor/thor/error.rb +28 -0
  44. data/lib/skylight/vendor/thor/group.rb +282 -0
  45. data/lib/skylight/vendor/thor/invocation.rb +172 -0
  46. data/lib/skylight/vendor/thor/parser.rb +4 -0
  47. data/lib/skylight/vendor/thor/parser/argument.rb +74 -0
  48. data/lib/skylight/vendor/thor/parser/arguments.rb +171 -0
  49. data/lib/skylight/vendor/thor/parser/option.rb +121 -0
  50. data/lib/skylight/vendor/thor/parser/options.rb +218 -0
  51. data/lib/skylight/vendor/thor/rake_compat.rb +72 -0
  52. data/lib/skylight/vendor/thor/runner.rb +322 -0
  53. data/lib/skylight/vendor/thor/shell.rb +88 -0
  54. data/lib/skylight/vendor/thor/shell/basic.rb +393 -0
  55. data/lib/skylight/vendor/thor/shell/color.rb +148 -0
  56. data/lib/skylight/vendor/thor/shell/html.rb +127 -0
  57. data/lib/skylight/vendor/thor/util.rb +270 -0
  58. data/lib/skylight/vendor/thor/version.rb +3 -0
  59. data/lib/skylight/version.rb +1 -1
  60. data/lib/skylight/worker.rb +3 -58
  61. metadata +56 -18
@@ -0,0 +1,475 @@
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
+ #
229
+ def build_responses( )
230
+ ### WARNING: This code is quasi-duplicated in ###
231
+ ### Menu.update_responses(). Check there too when ###
232
+ ### making changes! ###
233
+ append_default unless default.nil?
234
+ @responses = { :ambiguous_completion =>
235
+ "Ambiguous choice. " +
236
+ "Please choose one of #{@answer_type.inspect}.",
237
+ :ask_on_error =>
238
+ "? ",
239
+ :invalid_type =>
240
+ "You must enter a valid #{@answer_type}.",
241
+ :no_completion =>
242
+ "You must choose one of " +
243
+ "#{@answer_type.inspect}.",
244
+ :not_in_range =>
245
+ "Your answer isn't within the expected range " +
246
+ "(#{expected_range}).",
247
+ :mismatch =>
248
+ "Your entries didn't match.",
249
+ :not_valid =>
250
+ "Your answer isn't valid (must match " +
251
+ "#{@validate.inspect})." }.merge(@responses)
252
+ ### WARNING: This code is quasi-duplicated in ###
253
+ ### Menu.update_responses(). Check there too when ###
254
+ ### making changes! ###
255
+ end
256
+
257
+ #
258
+ # Returns the provided _answer_string_ after changing character case by
259
+ # the rules of this Question. Valid settings for whitespace are:
260
+ #
261
+ # +nil+:: Do not alter character case.
262
+ # (Default.)
263
+ # <tt>:up</tt>:: Calls upcase().
264
+ # <tt>:upcase</tt>:: Calls upcase().
265
+ # <tt>:down</tt>:: Calls downcase().
266
+ # <tt>:downcase</tt>:: Calls downcase().
267
+ # <tt>:capitalize</tt>:: Calls capitalize().
268
+ #
269
+ # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
270
+ #
271
+ def change_case( answer_string )
272
+ if [:up, :upcase].include?(@case)
273
+ answer_string.upcase
274
+ elsif [:down, :downcase].include?(@case)
275
+ answer_string.downcase
276
+ elsif @case == :capitalize
277
+ answer_string.capitalize
278
+ else
279
+ answer_string
280
+ end
281
+ end
282
+
283
+ #
284
+ # Transforms the given _answer_string_ into the expected type for this
285
+ # Question. Currently supported conversions are:
286
+ #
287
+ # <tt>[...]</tt>:: Answer must be a member of the passed Array.
288
+ # Auto-completion is used to expand partial
289
+ # answers.
290
+ # <tt>lambda {...}</tt>:: Answer is passed to lambda for conversion.
291
+ # Date:: Date.parse() is called with answer.
292
+ # DateTime:: DateTime.parse() is called with answer.
293
+ # File:: The entered file name is auto-completed in
294
+ # terms of _directory_ + _glob_, opened, and
295
+ # returned.
296
+ # Float:: Answer is converted with Kernel.Float().
297
+ # Integer:: Answer is converted with Kernel.Integer().
298
+ # +nil+:: Answer is left in String format. (Default.)
299
+ # Pathname:: Same as File, save that a Pathname object is
300
+ # returned.
301
+ # String:: Answer is converted with Kernel.String().
302
+ # HighLine::String:: Answer is converted with HighLine::String()
303
+ # Regexp:: Answer is fed to Regexp.new().
304
+ # Symbol:: The method to_sym() is called on answer and
305
+ # the result returned.
306
+ # <i>any other Class</i>:: The answer is passed on to
307
+ # <tt>Class.parse()</tt>.
308
+ #
309
+ # This method throws ArgumentError, if the conversion cannot be
310
+ # completed for any reason.
311
+ #
312
+ def convert( answer_string )
313
+ if @answer_type.nil?
314
+ answer_string
315
+ elsif [::String, HighLine::String].include?(@answer_type)
316
+ HighLine::String(answer_string)
317
+ elsif [Float, Integer, String].include?(@answer_type)
318
+ Kernel.send(@answer_type.to_s.to_sym, answer_string)
319
+ elsif @answer_type == Symbol
320
+ answer_string.to_sym
321
+ elsif @answer_type == Regexp
322
+ Regexp.new(answer_string)
323
+ elsif @answer_type.is_a?(Array) or [File, Pathname].include?(@answer_type)
324
+ # cheating, using OptionParser's Completion module
325
+ choices = selection
326
+ choices.extend(OptionParser::Completion)
327
+ answer = choices.complete(answer_string)
328
+ if answer.nil?
329
+ raise NoAutoCompleteMatch
330
+ end
331
+ if @answer_type.is_a?(Array)
332
+ answer.last
333
+ elsif @answer_type == File
334
+ File.open(File.join(@directory.to_s, answer.last))
335
+ else
336
+ Pathname.new(File.join(@directory.to_s, answer.last))
337
+ end
338
+ elsif [Date, DateTime].include?(@answer_type) or @answer_type.is_a?(Class)
339
+ @answer_type.parse(answer_string)
340
+ elsif @answer_type.is_a?(Proc)
341
+ @answer_type[answer_string]
342
+ end
343
+ end
344
+
345
+ # Returns an English explanation of the current range settings.
346
+ def expected_range( )
347
+ expected = [ ]
348
+
349
+ expected << "above #{@above}" unless @above.nil?
350
+ expected << "below #{@below}" unless @below.nil?
351
+ expected << "included in #{@in.inspect}" unless @in.nil?
352
+
353
+ case expected.size
354
+ when 0 then ""
355
+ when 1 then expected.first
356
+ when 2 then expected.join(" and ")
357
+ else expected[0..-2].join(", ") + ", and #{expected.last}"
358
+ end
359
+ end
360
+
361
+ # Returns _first_answer_, which will be unset following this call.
362
+ def first_answer( )
363
+ @first_answer
364
+ ensure
365
+ @first_answer = nil
366
+ end
367
+
368
+ # Returns true if _first_answer_ is set.
369
+ def first_answer?( )
370
+ not @first_answer.nil?
371
+ end
372
+
373
+ #
374
+ # Returns +true+ if the _answer_object_ is greater than the _above_
375
+ # attribute, less than the _below_ attribute and include?()ed in the
376
+ # _in_ attribute. Otherwise, +false+ is returned. Any +nil+ attributes
377
+ # are not checked.
378
+ #
379
+ def in_range?( answer_object )
380
+ (@above.nil? or answer_object > @above) and
381
+ (@below.nil? or answer_object < @below) and
382
+ (@in.nil? or @in.include?(answer_object))
383
+ end
384
+
385
+ #
386
+ # Returns the provided _answer_string_ after processing whitespace by
387
+ # the rules of this Question. Valid settings for whitespace are:
388
+ #
389
+ # +nil+:: Do not alter whitespace.
390
+ # <tt>:strip</tt>:: Calls strip(). (Default.)
391
+ # <tt>:chomp</tt>:: Calls chomp().
392
+ # <tt>:collapse</tt>:: Collapses all whitespace runs to a
393
+ # single space.
394
+ # <tt>:strip_and_collapse</tt>:: Calls strip(), then collapses all
395
+ # whitespace runs to a single space.
396
+ # <tt>:chomp_and_collapse</tt>:: Calls chomp(), then collapses all
397
+ # whitespace runs to a single space.
398
+ # <tt>:remove</tt>:: Removes all whitespace.
399
+ #
400
+ # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
401
+ #
402
+ # This process is skipped for single character input.
403
+ #
404
+ def remove_whitespace( answer_string )
405
+ if @whitespace.nil?
406
+ answer_string
407
+ elsif [:strip, :chomp].include?(@whitespace)
408
+ answer_string.send(@whitespace)
409
+ elsif @whitespace == :collapse
410
+ answer_string.gsub(/\s+/, " ")
411
+ elsif [:strip_and_collapse, :chomp_and_collapse].include?(@whitespace)
412
+ result = answer_string.send(@whitespace.to_s[/^[a-z]+/])
413
+ result.gsub(/\s+/, " ")
414
+ elsif @whitespace == :remove
415
+ answer_string.gsub(/\s+/, "")
416
+ else
417
+ answer_string
418
+ end
419
+ end
420
+
421
+ #
422
+ # Returns an Array of valid answers to this question. These answers are
423
+ # only known when _answer_type_ is set to an Array of choices, File, or
424
+ # Pathname. Any other time, this method will return an empty Array.
425
+ #
426
+ def selection( )
427
+ if @completion.is_a?(Array)
428
+ @completion
429
+ elsif [File, Pathname].include?(@completion)
430
+ Dir[File.join(@directory.to_s, @glob)].map do |file|
431
+ File.basename(file)
432
+ end
433
+ else
434
+ [ ]
435
+ end
436
+ end
437
+
438
+ # Stringifies the question to be asked.
439
+ def to_str( )
440
+ @question
441
+ end
442
+
443
+ #
444
+ # Returns +true+ if the provided _answer_string_ is accepted by the
445
+ # _validate_ attribute or +false+ if it's not.
446
+ #
447
+ # It's important to realize that an answer is validated after whitespace
448
+ # and case handling.
449
+ #
450
+ def valid_answer?( answer_string )
451
+ @validate.nil? or
452
+ (@validate.is_a?(Regexp) and answer_string =~ @validate) or
453
+ (@validate.is_a?(Proc) and @validate[answer_string])
454
+ end
455
+
456
+ private
457
+
458
+ #
459
+ # Adds the default choice to the end of question between <tt>|...|</tt>.
460
+ # Trailing whitespace is preserved so the function of HighLine.say() is
461
+ # not affected.
462
+ #
463
+ def append_default( )
464
+ if @question =~ /([\t ]+)\Z/
465
+ @question << "|#{@default}|#{$1}"
466
+ elsif @question == ""
467
+ @question << "|#{@default}| "
468
+ elsif @question[-1, 1] == "\n"
469
+ @question[-2, 0] = " |#{@default}|"
470
+ else
471
+ @question << " |#{@default}|"
472
+ end
473
+ end
474
+ end
475
+ end