challah 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/lib/challah/version.rb +1 -1
  3. data/lib/tasks/crud.rake +23 -53
  4. data/vendor/bundle/cache/highline-1.6.11.gem +0 -0
  5. data/vendor/bundle/gems/highline-1.6.11/AUTHORS +3 -0
  6. data/vendor/bundle/gems/highline-1.6.11/CHANGELOG +304 -0
  7. data/vendor/bundle/gems/highline-1.6.11/COPYING +340 -0
  8. data/vendor/bundle/gems/highline-1.6.11/INSTALL +55 -0
  9. data/vendor/bundle/gems/highline-1.6.11/LICENSE +7 -0
  10. data/vendor/bundle/gems/highline-1.6.11/README +63 -0
  11. data/vendor/bundle/gems/highline-1.6.11/Rakefile +53 -0
  12. data/vendor/bundle/gems/highline-1.6.11/TODO +6 -0
  13. data/vendor/bundle/gems/highline-1.6.11/examples/ansi_colors.rb +38 -0
  14. data/vendor/bundle/gems/highline-1.6.11/examples/asking_for_arrays.rb +18 -0
  15. data/vendor/bundle/gems/highline-1.6.11/examples/basic_usage.rb +75 -0
  16. data/vendor/bundle/gems/highline-1.6.11/examples/color_scheme.rb +32 -0
  17. data/vendor/bundle/gems/highline-1.6.11/examples/limit.rb +12 -0
  18. data/vendor/bundle/gems/highline-1.6.11/examples/menus.rb +65 -0
  19. data/vendor/bundle/gems/highline-1.6.11/examples/overwrite.rb +19 -0
  20. data/vendor/bundle/gems/highline-1.6.11/examples/page_and_wrap.rb +322 -0
  21. data/vendor/bundle/gems/highline-1.6.11/examples/password.rb +7 -0
  22. data/vendor/bundle/gems/highline-1.6.11/examples/trapping_eof.rb +22 -0
  23. data/vendor/bundle/gems/highline-1.6.11/examples/using_readline.rb +17 -0
  24. data/vendor/bundle/gems/highline-1.6.11/highline.gemspec +36 -0
  25. data/vendor/bundle/gems/highline-1.6.11/lib/highline/color_scheme.rb +136 -0
  26. data/vendor/bundle/gems/highline-1.6.11/lib/highline/compatibility.rb +16 -0
  27. data/vendor/bundle/gems/highline-1.6.11/lib/highline/import.rb +43 -0
  28. data/vendor/bundle/gems/highline-1.6.11/lib/highline/menu.rb +398 -0
  29. data/vendor/bundle/gems/highline-1.6.11/lib/highline/question.rb +465 -0
  30. data/vendor/bundle/gems/highline-1.6.11/lib/highline/string_extensions.rb +98 -0
  31. data/vendor/bundle/gems/highline-1.6.11/lib/highline/style.rb +184 -0
  32. data/vendor/bundle/gems/highline-1.6.11/lib/highline/system_extensions.rb +180 -0
  33. data/vendor/bundle/gems/highline-1.6.11/lib/highline.rb +978 -0
  34. data/vendor/bundle/gems/highline-1.6.11/setup.rb +1360 -0
  35. data/vendor/bundle/gems/highline-1.6.11/site/highline.css +65 -0
  36. data/vendor/bundle/gems/highline-1.6.11/site/images/logo.png +0 -0
  37. data/vendor/bundle/gems/highline-1.6.11/site/index.html +58 -0
  38. data/vendor/bundle/gems/highline-1.6.11/test/string_methods.rb +34 -0
  39. data/vendor/bundle/gems/highline-1.6.11/test/tc_color_scheme.rb +98 -0
  40. data/vendor/bundle/gems/highline-1.6.11/test/tc_highline.rb +962 -0
  41. data/vendor/bundle/gems/highline-1.6.11/test/tc_import.rb +54 -0
  42. data/vendor/bundle/gems/highline-1.6.11/test/tc_menu.rb +429 -0
  43. data/vendor/bundle/gems/highline-1.6.11/test/tc_string_extension.rb +22 -0
  44. data/vendor/bundle/gems/highline-1.6.11/test/tc_string_highline.rb +40 -0
  45. data/vendor/bundle/gems/highline-1.6.11/test/tc_style.rb +569 -0
  46. data/vendor/bundle/gems/highline-1.6.11/test/ts_all.rb +18 -0
  47. data/vendor/bundle/specifications/highline-1.6.11.gemspec +29 -0
  48. metadata +63 -8
@@ -0,0 +1,465 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # question.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-04-26.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+ #
8
+ # This is Free Software. See LICENSE and COPYING for details.
9
+
10
+ require "optparse"
11
+ require "date"
12
+ require "pathname"
13
+
14
+ class HighLine
15
+ #
16
+ # Question objects contain all the details of a single invocation of
17
+ # HighLine.ask(). The object is initialized by the parameters passed to
18
+ # HighLine.ask() and then queried to make sure each step of the input
19
+ # process is handled according to the users wishes.
20
+ #
21
+ class Question
22
+ # An internal HighLine error. User code does not need to trap this.
23
+ class NoAutoCompleteMatch < StandardError
24
+ # do nothing, just creating a unique error type
25
+ end
26
+
27
+ #
28
+ # Create an instance of HighLine::Question. Expects a _question_ to ask
29
+ # (can be <tt>""</tt>) and an _answer_type_ to convert the answer to.
30
+ # The _answer_type_ parameter must be a type recognized by
31
+ # Question.convert(). If given, a block is yeilded the new Question
32
+ # object to allow custom initializaion.
33
+ #
34
+ def initialize( question, answer_type )
35
+ # initialize instance data
36
+ @question = question
37
+ @answer_type = answer_type
38
+
39
+ @character = nil
40
+ @limit = nil
41
+ @echo = true
42
+ @readline = false
43
+ @whitespace = :strip
44
+ @case = nil
45
+ @default = nil
46
+ @validate = nil
47
+ @above = nil
48
+ @below = nil
49
+ @in = nil
50
+ @confirm = nil
51
+ @gather = 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
+ #
70
+ # Can be set to +true+ to use HighLine's cross-platform character reader
71
+ # instead of fetching an entire line of input. (Note: HighLine's character
72
+ # reader *ONLY* supports STDIN on Windows and Unix.) Can also be set to
73
+ # <tt>:getc</tt> to use that method on the input stream.
74
+ #
75
+ # *WARNING*: The _echo_ and _overwrite_ attributes for a question are
76
+ # ignored when using the <tt>:getc</tt> method.
77
+ #
78
+ attr_accessor :character
79
+ #
80
+ # Allows you to set a character limit for input.
81
+ #
82
+ # *WARNING*: This option forces a character by character read.
83
+ #
84
+ attr_accessor :limit
85
+ #
86
+ # Can be set to +true+ or +false+ to control whether or not input will
87
+ # be echoed back to the user. A setting of +true+ will cause echo to
88
+ # match input, but any other true value will be treated as to String to
89
+ # echo for each character typed.
90
+ #
91
+ # This requires HighLine's character reader. See the _character_
92
+ # attribute for details.
93
+ #
94
+ # *Note*: When using HighLine to manage echo on Unix based systems, we
95
+ # recommend installing the termios gem. Without it, it's possible to type
96
+ # fast enough to have letters still show up (when reading character by
97
+ # character only).
98
+ #
99
+ attr_accessor :echo
100
+ #
101
+ # Use the Readline library to fetch input. This allows input editing as
102
+ # well as keeping a history. In addition, tab will auto-complete
103
+ # within an Array of choices or a file listing.
104
+ #
105
+ # *WARNING*: This option is incompatible with all of HighLine's
106
+ # character reading modes and it causes HighLine to ignore the
107
+ # specified _input_ stream.
108
+ #
109
+ attr_accessor :readline
110
+ #
111
+ # Used to control whitespace processing for the answer to this question.
112
+ # See HighLine::Question.remove_whitespace() for acceptable settings.
113
+ #
114
+ attr_accessor :whitespace
115
+ #
116
+ # Used to control character case processing for the answer to this question.
117
+ # See HighLine::Question.change_case() for acceptable settings.
118
+ #
119
+ attr_accessor :case
120
+ # Used to provide a default answer to this question.
121
+ attr_accessor :default
122
+ #
123
+ # If set to a Regexp, the answer must match (before type conversion).
124
+ # Can also be set to a Proc which will be called with the provided
125
+ # answer to validate with a +true+ or +false+ return.
126
+ #
127
+ attr_accessor :validate
128
+ # Used to control range checks for answer.
129
+ attr_accessor :above, :below
130
+ # If set, answer must pass an include?() check on this object.
131
+ attr_accessor :in
132
+ #
133
+ # Asks a yes or no confirmation question, to ensure a user knows what
134
+ # they have just agreed to. If set to +true+ the question will be,
135
+ # "Are you sure? " Any other true value for this attribute is assumed
136
+ # to be the question to ask. When +false+ or +nil+ (the default),
137
+ # answers are not confirmed.
138
+ #
139
+ attr_accessor :confirm
140
+ #
141
+ # When set, the user will be prompted for multiple answers which will
142
+ # be collected into an Array or Hash and returned as the final answer.
143
+ #
144
+ # You can set _gather_ to an Integer to have an Array of exactly that
145
+ # many answers collected, or a String/Regexp to match an end input which
146
+ # will not be returned in the Array.
147
+ #
148
+ # Optionally _gather_ can be set to a Hash. In this case, the question
149
+ # will be asked once for each key and the answers will be returned in a
150
+ # Hash, mapped by key. The <tt>@key</tt> variable is set before each
151
+ # question is evaluated, so you can use it in your question.
152
+ #
153
+ attr_accessor :gather
154
+ #
155
+ # When set to a non *nil* value, this will be tried as an answer to the
156
+ # question. If this answer passes validations, it will become the result
157
+ # without the user ever being prompted. Otherwise this value is discarded,
158
+ # and this Question is resolved as a normal call to HighLine.ask().
159
+ #
160
+ attr_writer :first_answer
161
+ #
162
+ # The directory from which a user will be allowed to select files, when
163
+ # File or Pathname is specified as an _answer_type_. Initially set to
164
+ # <tt>Pathname.new(File.expand_path(File.dirname($0)))</tt>.
165
+ #
166
+ attr_accessor :directory
167
+ #
168
+ # The glob pattern used to limit file selection when File or Pathname is
169
+ # specified as an _answer_type_. Initially set to <tt>"*"</tt>.
170
+ #
171
+ attr_accessor :glob
172
+ #
173
+ # A Hash that stores the various responses used by HighLine to notify
174
+ # the user. The currently used responses and their purpose are as
175
+ # follows:
176
+ #
177
+ # <tt>:ambiguous_completion</tt>:: Used to notify the user of an
178
+ # ambiguous answer the auto-completion
179
+ # system cannot resolve.
180
+ # <tt>:ask_on_error</tt>:: This is the question that will be
181
+ # redisplayed to the user in the event
182
+ # of an error. Can be set to
183
+ # <tt>:question</tt> to repeat the
184
+ # original question.
185
+ # <tt>:invalid_type</tt>:: The error message shown when a type
186
+ # conversion fails.
187
+ # <tt>:no_completion</tt>:: Used to notify the user that their
188
+ # selection does not have a valid
189
+ # auto-completion match.
190
+ # <tt>:not_in_range</tt>:: Used to notify the user that a
191
+ # provided answer did not satisfy
192
+ # the range requirement tests.
193
+ # <tt>:not_valid</tt>:: The error message shown when
194
+ # validation checks fail.
195
+ #
196
+ attr_reader :responses
197
+ #
198
+ # When set to +true+ the question is asked, but output does not progress to
199
+ # the next line. The Cursor is moved back to the beginning of the question
200
+ # line and it is cleared so that all the contents of the line disappear from
201
+ # the screen.
202
+ #
203
+ attr_accessor :overwrite
204
+
205
+ #
206
+ # Returns the provided _answer_string_ or the default answer for this
207
+ # Question if a default was set and the answer is empty.
208
+ #
209
+ def answer_or_default( answer_string )
210
+ if answer_string.length == 0 and not @default.nil?
211
+ @default
212
+ else
213
+ answer_string
214
+ end
215
+ end
216
+
217
+ #
218
+ # Called late in the initialization process to build intelligent
219
+ # responses based on the details of this Question object.
220
+ #
221
+ def build_responses( )
222
+ ### WARNING: This code is quasi-duplicated in ###
223
+ ### Menu.update_responses(). Check there too when ###
224
+ ### making changes! ###
225
+ append_default unless default.nil?
226
+ @responses = { :ambiguous_completion =>
227
+ "Ambiguous choice. " +
228
+ "Please choose one of #{@answer_type.inspect}.",
229
+ :ask_on_error =>
230
+ "? ",
231
+ :invalid_type =>
232
+ "You must enter a valid #{@answer_type}.",
233
+ :no_completion =>
234
+ "You must choose one of " +
235
+ "#{@answer_type.inspect}.",
236
+ :not_in_range =>
237
+ "Your answer isn't within the expected range " +
238
+ "(#{expected_range}).",
239
+ :not_valid =>
240
+ "Your answer isn't valid (must match " +
241
+ "#{@validate.inspect})." }.merge(@responses)
242
+ ### WARNING: This code is quasi-duplicated in ###
243
+ ### Menu.update_responses(). Check there too when ###
244
+ ### making changes! ###
245
+ end
246
+
247
+ #
248
+ # Returns the provided _answer_string_ after changing character case by
249
+ # the rules of this Question. Valid settings for whitespace are:
250
+ #
251
+ # +nil+:: Do not alter character case.
252
+ # (Default.)
253
+ # <tt>:up</tt>:: Calls upcase().
254
+ # <tt>:upcase</tt>:: Calls upcase().
255
+ # <tt>:down</tt>:: Calls downcase().
256
+ # <tt>:downcase</tt>:: Calls downcase().
257
+ # <tt>:capitalize</tt>:: Calls capitalize().
258
+ #
259
+ # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
260
+ #
261
+ def change_case( answer_string )
262
+ if [:up, :upcase].include?(@case)
263
+ answer_string.upcase
264
+ elsif [:down, :downcase].include?(@case)
265
+ answer_string.downcase
266
+ elsif @case == :capitalize
267
+ answer_string.capitalize
268
+ else
269
+ answer_string
270
+ end
271
+ end
272
+
273
+ #
274
+ # Transforms the given _answer_string_ into the expected type for this
275
+ # Question. Currently supported conversions are:
276
+ #
277
+ # <tt>[...]</tt>:: Answer must be a member of the passed Array.
278
+ # Auto-completion is used to expand partial
279
+ # answers.
280
+ # <tt>lambda {...}</tt>:: Answer is passed to lambda for conversion.
281
+ # Date:: Date.parse() is called with answer.
282
+ # DateTime:: DateTime.parse() is called with answer.
283
+ # File:: The entered file name is auto-completed in
284
+ # terms of _directory_ + _glob_, opened, and
285
+ # returned.
286
+ # Float:: Answer is converted with Kernel.Float().
287
+ # Integer:: Answer is converted with Kernel.Integer().
288
+ # +nil+:: Answer is left in String format. (Default.)
289
+ # Pathname:: Same as File, save that a Pathname object is
290
+ # returned.
291
+ # String:: Answer is converted with Kernel.String().
292
+ # HighLine::String:: Answer is converted with HighLine::String()
293
+ # Regexp:: Answer is fed to Regexp.new().
294
+ # Symbol:: The method to_sym() is called on answer and
295
+ # the result returned.
296
+ # <i>any other Class</i>:: The answer is passed on to
297
+ # <tt>Class.parse()</tt>.
298
+ #
299
+ # This method throws ArgumentError, if the conversion cannot be
300
+ # completed for any reason.
301
+ #
302
+ def convert( answer_string )
303
+ if @answer_type.nil?
304
+ answer_string
305
+ elsif [::String, HighLine::String].include?(@answer_type)
306
+ HighLine::String(answer_string)
307
+ elsif [Float, Integer, String].include?(@answer_type)
308
+ Kernel.send(@answer_type.to_s.to_sym, answer_string)
309
+ elsif @answer_type == Symbol
310
+ answer_string.to_sym
311
+ elsif @answer_type == Regexp
312
+ Regexp.new(answer_string)
313
+ elsif @answer_type.is_a?(Array) or [File, Pathname].include?(@answer_type)
314
+ # cheating, using OptionParser's Completion module
315
+ choices = selection
316
+ choices.extend(OptionParser::Completion)
317
+ answer = choices.complete(answer_string)
318
+ if answer.nil?
319
+ raise NoAutoCompleteMatch
320
+ end
321
+ if @answer_type.is_a?(Array)
322
+ answer.last
323
+ elsif @answer_type == File
324
+ File.open(File.join(@directory.to_s, answer.last))
325
+ else
326
+ Pathname.new(File.join(@directory.to_s, answer.last))
327
+ end
328
+ elsif [Date, DateTime].include?(@answer_type) or @answer_type.is_a?(Class)
329
+ @answer_type.parse(answer_string)
330
+ elsif @answer_type.is_a?(Proc)
331
+ @answer_type[answer_string]
332
+ end
333
+ end
334
+
335
+ # Returns a english explination of the current range settings.
336
+ def expected_range( )
337
+ expected = [ ]
338
+
339
+ expected << "above #{@above}" unless @above.nil?
340
+ expected << "below #{@below}" unless @below.nil?
341
+ expected << "included in #{@in.inspect}" unless @in.nil?
342
+
343
+ case expected.size
344
+ when 0 then ""
345
+ when 1 then expected.first
346
+ when 2 then expected.join(" and ")
347
+ else expected[0..-2].join(", ") + ", and #{expected.last}"
348
+ end
349
+ end
350
+
351
+ # Returns _first_answer_, which will be unset following this call.
352
+ def first_answer( )
353
+ @first_answer
354
+ ensure
355
+ @first_answer = nil
356
+ end
357
+
358
+ # Returns true if _first_answer_ is set.
359
+ def first_answer?( )
360
+ not @first_answer.nil?
361
+ end
362
+
363
+ #
364
+ # Returns +true+ if the _answer_object_ is greater than the _above_
365
+ # attribute, less than the _below_ attribute and included?()ed in the
366
+ # _in_ attribute. Otherwise, +false+ is returned. Any +nil+ attributes
367
+ # are not checked.
368
+ #
369
+ def in_range?( answer_object )
370
+ (@above.nil? or answer_object > @above) and
371
+ (@below.nil? or answer_object < @below) and
372
+ (@in.nil? or @in.include?(answer_object))
373
+ end
374
+
375
+ #
376
+ # Returns the provided _answer_string_ after processing whitespace by
377
+ # the rules of this Question. Valid settings for whitespace are:
378
+ #
379
+ # +nil+:: Do not alter whitespace.
380
+ # <tt>:strip</tt>:: Calls strip(). (Default.)
381
+ # <tt>:chomp</tt>:: Calls chomp().
382
+ # <tt>:collapse</tt>:: Collapses all whitspace runs to a
383
+ # single space.
384
+ # <tt>:strip_and_collapse</tt>:: Calls strip(), then collapses all
385
+ # whitspace runs to a single space.
386
+ # <tt>:chomp_and_collapse</tt>:: Calls chomp(), then collapses all
387
+ # whitspace runs to a single space.
388
+ # <tt>:remove</tt>:: Removes all whitespace.
389
+ #
390
+ # An unrecognized choice (like <tt>:none</tt>) is treated as +nil+.
391
+ #
392
+ # This process is skipped, for single character input.
393
+ #
394
+ def remove_whitespace( answer_string )
395
+ if @whitespace.nil?
396
+ answer_string
397
+ elsif [:strip, :chomp].include?(@whitespace)
398
+ answer_string.send(@whitespace)
399
+ elsif @whitespace == :collapse
400
+ answer_string.gsub(/\s+/, " ")
401
+ elsif [:strip_and_collapse, :chomp_and_collapse].include?(@whitespace)
402
+ result = answer_string.send(@whitespace.to_s[/^[a-z]+/])
403
+ result.gsub(/\s+/, " ")
404
+ elsif @whitespace == :remove
405
+ answer_string.gsub(/\s+/, "")
406
+ else
407
+ answer_string
408
+ end
409
+ end
410
+
411
+ #
412
+ # Returns an Array of valid answers to this question. These answers are
413
+ # only known when _answer_type_ is set to an Array of choices, File, or
414
+ # Pathname. Any other time, this method will return an empty Array.
415
+ #
416
+ def selection( )
417
+ if @answer_type.is_a?(Array)
418
+ @answer_type
419
+ elsif [File, Pathname].include?(@answer_type)
420
+ Dir[File.join(@directory.to_s, @glob)].map do |file|
421
+ File.basename(file)
422
+ end
423
+ else
424
+ [ ]
425
+ end
426
+ end
427
+
428
+ # Stringifies the question to be asked.
429
+ def to_str( )
430
+ @question
431
+ end
432
+
433
+ #
434
+ # Returns +true+ if the provided _answer_string_ is accepted by the
435
+ # _validate_ attribute or +false+ if it's not.
436
+ #
437
+ # It's important to realize that an answer is validated after whitespace
438
+ # and case handling.
439
+ #
440
+ def valid_answer?( answer_string )
441
+ @validate.nil? or
442
+ (@validate.is_a?(Regexp) and answer_string =~ @validate) or
443
+ (@validate.is_a?(Proc) and @validate[answer_string])
444
+ end
445
+
446
+ private
447
+
448
+ #
449
+ # Adds the default choice to the end of question between <tt>|...|</tt>.
450
+ # Trailing whitespace is preserved so the function of HighLine.say() is
451
+ # not affected.
452
+ #
453
+ def append_default( )
454
+ if @question =~ /([\t ]+)\Z/
455
+ @question << "|#{@default}|#{$1}"
456
+ elsif @question == ""
457
+ @question << "|#{@default}| "
458
+ elsif @question[-1, 1] == "\n"
459
+ @question[-2, 0] = " |#{@default}|"
460
+ else
461
+ @question << " |#{@default}|"
462
+ end
463
+ end
464
+ end
465
+ end
@@ -0,0 +1,98 @@
1
+ # Extensions for class String
2
+ #
3
+ # HighLine::String is a subclass of String with convenience methods added for colorization.
4
+ #
5
+ # Available convenience methods include:
6
+ # * 'color' method e.g. highline_string.color(:bright_blue, :underline)
7
+ # * colors e.g. highline_string.magenta
8
+ # * RGB colors e.g. highline_string.rgb_ff6000
9
+ # or highline_string.rgb(255,96,0)
10
+ # * background colors e.g. highline_string.on_magenta
11
+ # * RGB background colors e.g. highline_string.on_rgb_ff6000
12
+ # or highline_string.on_rgb(255,96,0)
13
+ # * styles e.g. highline_string.underline
14
+ #
15
+ # Additionally, convenience methods can be chained, for instance the following are equivalent:
16
+ # highline_string.bright_blue.blink.underline
17
+ # highline_string.color(:bright_blue, :blink, :underline)
18
+ # HighLine.color(highline_string, :bright_blue, :blink, :underline)
19
+ #
20
+ # For those less squeamish about possible conflicts, the same convenience methods can be
21
+ # added to the builtin String class, as follows:
22
+ #
23
+ # require 'highline'
24
+ # Highline.colorize_strings
25
+
26
+ class HighLine
27
+ def self.String(s)
28
+ HighLine::String.new(s)
29
+ end
30
+
31
+ module StringExtensions
32
+ def self.included(base)
33
+ HighLine::COLORS.each do |color|
34
+ base.class_eval <<-END
35
+ def #{color.downcase}
36
+ color(:#{color.downcase})
37
+ end
38
+ END
39
+ base.class_eval <<-END
40
+ def on_#{color.downcase}
41
+ on(:#{color.downcase})
42
+ end
43
+ END
44
+ HighLine::STYLES.each do |style|
45
+ base.class_eval <<-END
46
+ def #{style.downcase}
47
+ color(:#{style.downcase})
48
+ end
49
+ END
50
+ end
51
+ end
52
+
53
+ base.class_eval do
54
+ def color(*args)
55
+ self.class.new(HighLine.color(self, *args))
56
+ end
57
+ alias_method :foreground, :color
58
+
59
+ def on(arg)
60
+ color(('on_' + arg.to_s).to_sym)
61
+ end
62
+
63
+ def uncolor
64
+ self.class.new(HighLine.uncolor(self))
65
+ end
66
+
67
+ def rgb(*colors)
68
+ color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
69
+ raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
70
+ color("rgb_#{color_code}".to_sym)
71
+ end
72
+
73
+ def on_rgb(*colors)
74
+ color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
75
+ raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
76
+ color("on_rgb_#{color_code}".to_sym)
77
+ end
78
+
79
+ # TODO Chain existing method_missing
80
+ def method_missing(method, *args, &blk)
81
+ if method.to_s =~ /^(on_)?rgb_([0-9a-fA-F]{6})$/
82
+ color(method)
83
+ else
84
+ raise NoMethodError, "undefined method `#{method}' for #<#{self.class}:#{'%#x'%self.object_id}>"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ class HighLine::String < ::String
92
+ include StringExtensions
93
+ end
94
+
95
+ def self.colorize_strings
96
+ ::String.send(:include, StringExtensions)
97
+ end
98
+ end