facets 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/AUTHORS +3 -3
  2. data/README +6 -7
  3. data/lib/core/facets.rb +1 -46
  4. data/lib/core/facets/array.rb +3 -0
  5. data/lib/core/facets/array/indexable.rb +6 -1
  6. data/lib/core/facets/array/only.rb +20 -0
  7. data/lib/core/facets/dir/multiglob.rb +12 -1
  8. data/lib/core/facets/enumerable.rb +0 -1
  9. data/lib/core/facets/enumerable/collect.rb +1 -0
  10. data/lib/core/facets/enumerable/combination.rb +44 -90
  11. data/lib/core/facets/facets.rb +46 -0
  12. data/lib/core/facets/file/write.rb +46 -58
  13. data/lib/core/facets/hash.rb +2 -0
  14. data/lib/core/facets/hash/select.rb +14 -0
  15. data/lib/core/facets/integer/multiples.rb +12 -55
  16. data/lib/core/facets/kernel/val.rb +14 -0
  17. data/lib/core/facets/module/alias.rb +28 -9
  18. data/lib/core/facets/module/methods.rb +18 -0
  19. data/lib/core/facets/module/traits.rb +65 -70
  20. data/lib/core/facets/proc/compose.rb +15 -12
  21. data/lib/core/facets/stackable.rb +3 -2
  22. data/lib/core/facets/string/format.rb +4 -6
  23. data/lib/core/facets/string/tabs.rb +34 -0
  24. data/lib/core/facets/symbol.rb +1 -0
  25. data/lib/core/facets/symbol/succ.rb +1 -42
  26. data/lib/core/facets/symbol/to_proc.rb +34 -0
  27. data/lib/methods/facets/array/contains.rb +1 -0
  28. data/lib/methods/facets/facets/require_core.rb +1 -0
  29. data/lib/methods/facets/file/writelines.rb +1 -0
  30. data/lib/methods/facets/io/writelines.rb +1 -0
  31. data/lib/methods/facets/kernel/not_nil.rb +1 -0
  32. data/lib/methods/facets/module/conflict.rb +1 -0
  33. data/lib/methods/facets/module/instance_method_defined.rb +1 -0
  34. data/lib/methods/facets/module/module_method_defined.rb +1 -0
  35. data/lib/methods/facets/module/private_conflict.rb +1 -0
  36. data/lib/methods/facets/module/protected_conflict.rb +1 -0
  37. data/lib/methods/facets/module/public_conflict.rb +1 -0
  38. data/lib/methods/facets/string/expand_tabs.rb +1 -0
  39. data/lib/methods/facets/string/outdent.rb +1 -0
  40. data/lib/methods/facets/string/taballto.rb +1 -0
  41. data/lib/more/facets/arguments.rb +1 -1
  42. data/lib/more/facets/association.rb +0 -46
  43. data/lib/more/facets/autoarray.rb +0 -28
  44. data/lib/more/facets/command.rb +341 -8
  45. data/lib/more/facets/dictionary.rb +25 -131
  46. data/lib/more/facets/downloader.rb +1 -1
  47. data/lib/more/facets/infinity.rb +3 -3
  48. data/lib/more/facets/interval.rb +0 -161
  49. data/lib/more/facets/multiton.rb +16 -12
  50. data/lib/more/facets/namespace.rb +1 -1
  51. data/lib/more/facets/ostruct.rb +46 -10
  52. data/lib/more/facets/overload.rb +0 -51
  53. data/lib/more/facets/paramix.rb +0 -97
  54. data/lib/more/facets/pp_s.rb +30 -0
  55. data/lib/more/facets/progressbar.rb +18 -10
  56. data/lib/more/facets/prototype.rb +1 -40
  57. data/lib/more/facets/random.rb +1 -0
  58. data/lib/more/facets/rbsystem.rb +4 -1
  59. data/lib/more/facets/snapshot.rb +8 -1
  60. data/lib/more/facets/stylize.rb +2 -0
  61. data/meta/{project.yaml → facets-2.0.3.roll} +22 -14
  62. data/meta/manifest.txt +38 -8
  63. data/task/{config.yaml → config/general.yaml} +7 -2
  64. data/task/{rdoc.yaml → config/rdoc.yaml} +1 -1
  65. data/task/crosstest +309 -0
  66. data/task/isotest +293 -0
  67. data/task/loadtest +28 -0
  68. data/task/methods +4 -4
  69. data/task/prepare +5 -0
  70. data/task/publish +2 -2
  71. data/task/rdoc +1 -0
  72. data/task/syntax +29 -0
  73. data/task/test +0 -1
  74. data/task/testeach +42 -0
  75. data/task/testpairs +50 -0
  76. data/test/lib/rq.rb +15 -0
  77. data/test/unit/array/test_merge.rb +21 -43
  78. data/test/unit/array/test_only.rb +21 -0
  79. data/test/unit/enumerable/test_collect.rb +1 -21
  80. data/test/unit/enumerable/test_combination.rb +50 -44
  81. data/test/unit/file/test_topath.rb +48 -57
  82. data/test/unit/file/test_write.rb +82 -0
  83. data/test/unit/hash/test_select.rb +43 -0
  84. data/test/unit/integer/test_multiples.rb +28 -32
  85. data/test/unit/kernel/test_report.rb +9 -12
  86. data/test/unit/kernel/test_val.rb +50 -45
  87. data/test/unit/module/test_include.rb +56 -57
  88. data/test/unit/module/test_name.rb +42 -55
  89. data/test/unit/module/test_traits.rb +46 -47
  90. data/test/unit/string/test_filter.rb +19 -34
  91. data/test/unit/string/test_format.rb +87 -96
  92. data/test/unit/string/test_regesc.rb +18 -26
  93. data/test/unit/string/test_tabs.rb +226 -119
  94. data/test/unit/symbol/test_succ.rb +14 -23
  95. data/test/unit/symbol/test_to_proc.rb +41 -0
  96. data/test/unit/test_association.rb +38 -47
  97. data/test/unit/test_attributes.rb +24 -33
  98. data/test/unit/test_autoarray.rb +23 -32
  99. data/test/unit/test_command.rb +26 -0
  100. data/test/unit/test_dictionary.rb +123 -117
  101. data/test/unit/test_infinity.rb +41 -47
  102. data/test/unit/test_inheritor.rb +133 -142
  103. data/test/unit/test_interval.rb +129 -93
  104. data/test/unit/test_ostruct.rb +148 -101
  105. data/test/unit/test_overload.rb +8 -15
  106. data/test/unit/test_paramix.rb +67 -73
  107. data/test/unit/test_pp_s.rb +23 -0
  108. data/test/unit/test_prototype.rb +28 -38
  109. metadata +47 -11
  110. data/lib/core/facets/enumerable/instance_map.rb +0 -0
  111. data/lib/more/facets/command_options.rb +0 -328
  112. data/meta/version.txt +0 -1
  113. data/task/load +0 -39
  114. data/test/unit/test_command_options.rb +0 -29
@@ -27,7 +27,7 @@ module Stackable
27
27
  slice(0)
28
28
  end
29
29
 
30
- alias :shift :pull
30
+ alias_method :shift, :pull
31
31
 
32
32
  #
33
33
 
@@ -35,7 +35,7 @@ module Stackable
35
35
  insert(0,x)
36
36
  end
37
37
 
38
- alias :unshift :poke
38
+ alias_method :unshift, :poke
39
39
 
40
40
  #
41
41
 
@@ -44,3 +44,4 @@ module Stackable
44
44
  end
45
45
 
46
46
  end
47
+
@@ -17,13 +17,12 @@
17
17
  #
18
18
  class String
19
19
 
20
- # CREDIT George Moschovitis
21
-
22
20
  # Returns short abstract of long strings (first 'count'
23
21
  # characters, chopped at the nearest word, appended by '...')
24
22
  # force_cutoff: break forcibly at 'count' chars. Does not accept
25
23
  # count < 2
26
-
24
+ #
25
+ # CREDIT George Moschovitis
27
26
  def brief(count = 128, force_cutoff = false, ellipsis="...")
28
27
  return nil if count < 2
29
28
 
@@ -148,9 +147,6 @@ class String
148
147
  # return wrapped_string
149
148
  # end
150
149
 
151
- # CREDIT Gavin Kistner
152
- # CREDIT Dayne Broderson
153
-
154
150
  # Word wrap a string not exceeding max width.
155
151
  #
156
152
  # puts "this is a test".word_wrap(4)
@@ -161,6 +157,8 @@ class String
161
157
  # is a
162
158
  # test
163
159
  #
160
+ # CREDIT Gavin Kistner
161
+ # CREDIT Dayne Broderson
164
162
  def word_wrap( col_width=80 )
165
163
  self.dup.word_wrap!( col_width )
166
164
  end
@@ -20,6 +20,32 @@ class String
20
20
  gsub(/^ */, ' ' * n)
21
21
  end
22
22
 
23
+ alias_method :taballto, :tab
24
+
25
+ # Expands tabs to +n+ spaces. Non-destructive. If +n+ is 0, then tabs are
26
+ # simply removed. Raises an exception if +n+ is negative.
27
+ #
28
+ # Thanks to GGaramuno for a more efficient algorithm. Very nice.
29
+ #
30
+ # CREDIT Noah Gibbs
31
+ # CREDIT Gavin Sinclair
32
+ # CREDIT GGaramuno
33
+
34
+ def expand_tabs(n=8)
35
+ n = n.to_int
36
+ raise ArgumentError, "n must be >= 0" if n < 0
37
+ return gsub(/\t/, "") if n == 0
38
+ return gsub(/\t/, " ") if n == 1
39
+ str = self.dup
40
+ while
41
+ str.gsub!(/^([^\t\n]*)(\t+)/) { |f|
42
+ val = ( n * $2.size - ($1.size % n) )
43
+ $1 << (' ' * val)
44
+ }
45
+ end
46
+ str
47
+ end
48
+
23
49
  # Preserves relative tabbing.
24
50
  # The first non-empty line ends up with n spaces before nonspace.
25
51
 
@@ -42,6 +68,14 @@ class String
42
68
  end
43
69
  end
44
70
 
71
+ # Outdent just indents a negative number of spaces.
72
+ #
73
+ # CREDIT Noah Gibbs
74
+
75
+ def outdent(n)
76
+ indent(-n)
77
+ end
78
+
45
79
  # Provides a margin controlled string.
46
80
  #
47
81
  # x = %Q{
@@ -3,3 +3,4 @@ require 'facets/symbol/succ.rb'
3
3
  require 'facets/symbol/not.rb'
4
4
  require 'facets/symbol/generate.rb'
5
5
  require 'facets/symbol/chomp.rb'
6
+ require 'facets/symbol/to_proc.rb'
@@ -1,21 +1,3 @@
1
- # TITLE:
2
- #
3
- # Symbol Generation
4
- #
5
- # DESCRIPTION:
6
- #
7
- # Symbol generation extensions.
8
- #
9
- # AUTHORS:
10
- #
11
- # CREDIT Thomas Sawyer
12
- #
13
- # NOTES:
14
- #
15
- # TODO Is Symbol#chomp worth having? Are the any other
16
- # String methods that Symbols really should have too?
17
-
18
- #
19
1
  class Symbol
20
2
 
21
3
  # Successor method for symobol. This simply converts
@@ -26,7 +8,7 @@ class Symbol
26
8
  #
27
9
  #--
28
10
  # In the future I would like this to work more like
29
- # a simple chracerter dial.
11
+ # a simple character dial.
30
12
  #++
31
13
 
32
14
  def succ
@@ -35,26 +17,3 @@ class Symbol
35
17
 
36
18
  end
37
19
 
38
-
39
- # _____ _
40
- # |_ _|__ ___| |_
41
- # | |/ _ \/ __| __|
42
- # | | __/\__ \ |_
43
- # |_|\___||___/\__|
44
- #
45
- =begin test
46
-
47
- require 'test/unit'
48
-
49
- class TestSymbol < Test::Unit::TestCase
50
-
51
- def test_succ
52
- assert_equal( :b, :a.succ )
53
- assert_equal( :aab, :aaa.succ )
54
- assert_equal( :"2", :"1".succ )
55
- end
56
-
57
- end
58
-
59
- =end
60
-
@@ -0,0 +1,34 @@
1
+ class Symbol
2
+
3
+ # Turn a symbol into a proc calling the method to
4
+ # which it refers.
5
+ #
6
+ # up = :upcase.to_proc
7
+ # up.call("hello") #=> HELLO
8
+ #
9
+ # More useful is the fact that this allows <tt>&</tt>
10
+ # to be used to coerce Symbol into Proc.
11
+ #
12
+ # %w{foo bar qux}.map(&:upcase) #=> ["FOO","BAR","QUX"]
13
+ # [1, 2, 3].inject(&:+) #=> 6
14
+ #
15
+ # And other conveniences such as:
16
+ #
17
+ # %{john terry fiona}.map(&:capitalize) # -> %{John Terry Fiona}
18
+ # sum = numbers.inject(&:+)
19
+ #
20
+ # TODO This will be deprecated as of Ruby 1.9, since it will become standard Ruby.
21
+ #
22
+ # CREDIT Florian Gross (orignal)
23
+ # CREDIT Nobuhiro Imai (current)
24
+
25
+ def to_proc
26
+ Proc.new{|*args| args.shift.__send__(self, *args)}
27
+ end
28
+
29
+ #def to_proc
30
+ # proc { |obj, *args| obj.send(self, *args) }
31
+ #end
32
+
33
+ end
34
+
@@ -0,0 +1 @@
1
+ require 'facets/array/indexable.rb'
@@ -0,0 +1 @@
1
+ require 'facets/facets.rb'
@@ -0,0 +1 @@
1
+ require 'facets/file/write.rb'
@@ -0,0 +1 @@
1
+ require 'facets/io/write.rb'
@@ -0,0 +1 @@
1
+ require 'facets/kernel/val.rb'
@@ -0,0 +1 @@
1
+ require 'facets/module/traits.rb'
@@ -0,0 +1 @@
1
+ require 'facets/module/methods.rb'
@@ -0,0 +1 @@
1
+ require 'facets/module/methods.rb'
@@ -0,0 +1 @@
1
+ require 'facets/module/traits.rb'
@@ -0,0 +1 @@
1
+ require 'facets/module/traits.rb'
@@ -0,0 +1 @@
1
+ require 'facets/module/traits.rb'
@@ -0,0 +1 @@
1
+ require 'facets/string/tabs.rb'
@@ -0,0 +1 @@
1
+ require 'facets/string/tabs.rb'
@@ -0,0 +1 @@
1
+ require 'facets/string/tabs.rb'
@@ -78,7 +78,7 @@ class Console::Arguments
78
78
  @options
79
79
  end
80
80
 
81
- # Returns [operands, ottions], which is good for plugging
81
+ # Returns [operands, options], which is good for plugging
82
82
  # directly into a method.
83
83
 
84
84
  def parameters
@@ -155,49 +155,3 @@ end
155
155
  # remove_method :>>
156
156
  # end
157
157
  #++
158
-
159
-
160
- # _____ _
161
- # |_ _|__ ___| |_
162
- # | |/ _ \/ __| __|
163
- # | | __/\__ \ |_
164
- # |_|\___||___/\__|
165
- #
166
- =begin test
167
-
168
- require 'test/unit'
169
-
170
- class TC01 < Test::Unit::TestCase
171
-
172
- def setup
173
- @complex_hierarchy = [
174
- 'parent' >> 'child',
175
- 'childless',
176
- 'another_parent' >> [
177
- 'subchildless',
178
- 'subparent' >> 'subchild'
179
- ]
180
- ]
181
- end
182
-
183
- def test_ohash
184
- k,v = [],[]
185
- ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ]
186
- ohash.each { |e1,e2| k << e1 ; v << e2 }
187
- assert_equal( ['A','B','C'], k )
188
- assert_equal( ['3','2','1'], v )
189
- end
190
-
191
- def test_complex
192
- complex = [ 'Drop Menu' >> [ 'Button 1', 'Button 2', 'Button 3' ], 'Help' ]
193
- assert_equal( 'Drop Menu', complex[0].index )
194
- end
195
-
196
- def test_associations
197
- complex = [ :a >> :b, :a >> :c ]
198
- assert_equal( [ :b, :c ], :a.associations )
199
- end
200
-
201
- end
202
-
203
- =end
@@ -57,31 +57,3 @@ class Autoarray < Array
57
57
  end
58
58
 
59
59
  end
60
-
61
-
62
- # _____ _
63
- # |_ _|__ ___| |_
64
- # | |/ _ \/ __| __|
65
- # | | __/\__ \ |_
66
- # |_|\___||___/\__|
67
- #
68
-
69
- =begin test
70
-
71
- require 'test/unit'
72
-
73
- class TC_Autoarray
74
-
75
- def test_001
76
- a = Autoarray.new
77
- assert_equal( 12, a[1][2][3] = 12 )
78
- assert_equal( [nil, [nil, nil, [nil, nil, nil, 12]]], a )
79
- assert_equal( [], a[2][3][4] )
80
- assert_equal( [nil, [nil, nil, [nil, nil, nil, 12]]], a )
81
- assert_equal( "Negative", a[1][-2][1] = "Negative" )
82
- assert_equal( [nil, [nil, [nil, "Negative"], [nil, nil, nil, 12]]], a )
83
- end
84
-
85
- end
86
-
87
- =end
@@ -19,15 +19,21 @@
19
19
  # PURPOSE.
20
20
  #
21
21
  # AUTHORS:
22
- # - Thomas Sawyer
22
+ #
23
+ # - 7rans
23
24
  # - Tyler Rick
24
25
  #
25
26
  # TODOs:
27
+ #
26
28
  # - Add help/documentation features.
27
- # - Problem wiht exit -1 when testing. See IMPORTANT!!! remark below.
29
+ # - Problem with exit -1 when testing. See IMPORTANT!!! remark below.
30
+ #
31
+ # LOG:
32
+ #
33
+ # - 2007.10.31 TRANS
34
+ # Re-added support for __option notation.
28
35
 
29
36
  require 'shellwords'
30
- require 'facets/command_options'
31
37
  #require 'facets/annotations' # for help ?
32
38
 
33
39
  module Console
@@ -72,10 +78,10 @@ module Console
72
78
  module Syntax
73
79
 
74
80
  # Starts the command execution.
75
- def execute( *args )
81
+ def execute(*args)
76
82
  cmd = new()
77
83
  #cmd.instance_variable_set("@global_options",global_options)
78
- cmd.execute( *args )
84
+ cmd.execute(*args)
79
85
  end
80
86
  alias_method :start, :execute
81
87
 
@@ -90,7 +96,7 @@ module Console
90
96
  def options(name, klass=nil, &block)
91
97
  raise ArgumentError if klass && block
92
98
  if block
93
- command_options[name.to_sym] = Class.new(CommandOptions, &block)
99
+ command_options[name.to_sym] = Class.new(Options, &block)
94
100
  else
95
101
  command_options[name.to_sym] = klass
96
102
  end
@@ -119,10 +125,10 @@ module Console
119
125
 
120
126
  #
121
127
 
122
- def execute(line)
128
+ def execute(line=ARGV)
123
129
  argv = line
124
130
 
125
- g_opts = CommandOptions.new(self)
131
+ g_opts = Command::Options.new(self)
126
132
  g_keys = self.class.global_options
127
133
 
128
134
  # Deal with global options.
@@ -259,4 +265,331 @@ module Console
259
265
  extend Help::ClassMethods
260
266
  =end
261
267
 
268
+
269
+ # = Command::Options
270
+ #
271
+ # CommandOptions provides the basis for Command to Object Mapping (COM).
272
+ # It is an commandline options parser that uses method definitions
273
+ # as means of interprting command arguments.
274
+ #
275
+ # == Synopsis
276
+ #
277
+ # Let's make an executable called 'mycmd'.
278
+ #
279
+ # #!/usr/bin/env ruby
280
+ #
281
+ # require 'facets/command_options'
282
+ #
283
+ # class MyOptions < CommandOptions
284
+ # attr_accessor :file
285
+ #
286
+ # def v!
287
+ # @verbose = true
288
+ # end
289
+ # end
290
+ #
291
+ # opts = MyOptions.parse("-v --file hello.rb")
292
+ #
293
+ # opts.verbose #=> true
294
+ # opts.file #=> "hello.rb"
295
+ #
296
+ #--
297
+ # == Global Options
298
+ #
299
+ # You can define <i>global options</i> which are options that will be
300
+ # processed no matter where they occur in the command line. In the above
301
+ # examples only the options occuring before the subcommand are processed
302
+ # globally. Anything occuring after the subcommand belonds strictly to
303
+ # the subcommand. For instance, if we had added the following to the above
304
+ # example:
305
+ #
306
+ # global_option :_v
307
+ #
308
+ # Then -v could appear anywhere in the command line, even on the end,
309
+ # and still work as expected.
310
+ #
311
+ # % mycmd jump -h 3 -v
312
+ #++
313
+ #
314
+ # == Missing Options
315
+ #
316
+ # You can use #option_missing to catch any options that are not explicility
317
+ # defined.
318
+ #
319
+ # The method signature should look like:
320
+ #
321
+ # option_missing(option_name, args)
322
+ #
323
+ # Example:
324
+ # def option_missing(option_name, args)
325
+ # p args if $debug
326
+ # case option_name
327
+ # when 'p'
328
+ # @a = args[0].to_i
329
+ # @b = args[1].to_i
330
+ # 2
331
+ # else
332
+ # raise InvalidOptionError(option_name, args)
333
+ # end
334
+ # end
335
+ #
336
+ # Its return value should be the effective "arity" of that options -- that is,
337
+ # how many arguments it consumed ("-p a b", for example, would consume 2 args:
338
+ # "a" and "b"). An arity of 1 is assumed if nil or false is returned.
339
+
340
+ class Command::Options
341
+
342
+ def self.parse(*line_and_options)
343
+ o = new
344
+ o.parse(*line_and_options)
345
+ o
346
+ end
347
+
348
+ def initialize(delegate=nil)
349
+ @__self__ = delegate || self
350
+ end
351
+
352
+ # Parse line for options in the context self.
353
+ #
354
+ # Options:
355
+ #
356
+ # :pass => true || false
357
+ #
358
+ # Setting this to true prevents the parse_missing routine from running.
359
+ #
360
+ # :only => [ global options, ... ]
361
+ #
362
+ # When processing global options, we only want to parse selected options.
363
+ # This also set +pass+ to true.
364
+ #
365
+ # :stop => true || false
366
+ #
367
+ # If we are parsing options for the *main* command and we are allowing
368
+ # subcommands, then we want to stop as soon as we get to the first non-option,
369
+ # because that non-option will be the name of our subcommand and all options that
370
+ # follow should be parsed later when we handle the subcommand.
371
+ # This also set +pass+ to true.
372
+
373
+ def parse(*line_and_options)
374
+ __self__ = @__self__
375
+
376
+ if Hash === line_and_options.last
377
+ options = line_and_options.pop
378
+ line = line_and_options.first
379
+ else
380
+ options = {}
381
+ line = line_and_options.first
382
+ end
383
+
384
+ case line
385
+ when String
386
+ argv = Shellwords.shellwords(line)
387
+ when Array
388
+ argv = line.dup
389
+ else
390
+ argv = ARGV.dup
391
+ end
392
+
393
+ only = options[:only] # only parse these options
394
+ stop = options[:stop] # stop at first non-option
395
+ pass = options[:pass] || only || stop # don't run options_missing
396
+
397
+ if $debug
398
+ puts(only ? "\nGlobal parsing..." : "\nParsing...")
399
+ end
400
+
401
+ puts "# line: #{argv.inspect}" if $debug
402
+
403
+ # Split single letter option groupings into separate options.
404
+ # ie. -xyz => -x -y -z
405
+ argv = argv.collect { |arg|
406
+ if md = /^-(\w{2,})/.match( arg )
407
+ md[1].split(//).collect { |c| "-#{c}" }
408
+ else
409
+ arg
410
+ end
411
+ }.flatten
412
+
413
+ index = 0
414
+
415
+ until index >= argv.size
416
+ arg = argv.at(index)
417
+ break if arg == '--' # POSIX compliance
418
+ if arg[0,1] == '-'
419
+ puts "# option: #{arg}" if $debug
420
+ cnt = (arg[0,2] == '--' ? 2 : 1)
421
+ #opt = Option.new(arg)
422
+ #name = opt.methodize
423
+ name = arg.sub(/^-{1,2}/,'')
424
+ skip = only && only.include?(name)
425
+ unam = ('__'*cnt)+name
426
+ if __self__.respond_to?(unam)
427
+ puts "# method: #{uname}" if $debug
428
+ meth = method(unam)
429
+ arity = meth.arity
430
+ if arity < 0
431
+ meth.call(*argv.slice(index+1..-1)) unless skip
432
+ arity[index..-1] = nil # Get rid of the *name* and values
433
+ elsif arity == 0
434
+ meth.call unless skip
435
+ argv.delete_at(index) # Get rid of the *name* of the option
436
+ else
437
+ meth.call(*argv.slice(index+1, arity)) unless skip
438
+ #argv.delete_at(index) # Get rid of the *name* of the option
439
+ #arity.times{ argv.delete_at(index) } # Get rid of the *value* of the option
440
+ arity[index,arity] = nil
441
+ end
442
+ elsif __self__.respond_to?(name+'=')
443
+ puts "# method: #{name}=" if $debug
444
+ __self__.send(name+'=', *argv.slice(index+1, 1)) unless skip
445
+ argv.delete_at(index) # Get rid of the *name* of the option
446
+ argv.delete_at(index) # Get rid of the *value* of the option
447
+ elsif __self__.respond_to?(name+'!')
448
+ puts "# method: #{name}!" if $debug
449
+ __self__.send(name+'!') unless skip
450
+ argv.delete_at(index) # Get rid of the *name* of the option
451
+ else
452
+ index += 1
453
+ end
454
+ else
455
+ index += 1
456
+ break if stop
457
+ end
458
+ end
459
+ # parse missing ?
460
+ argv = parse_missing(argv) unless pass
461
+ # return the remaining argv
462
+ puts "# return: #{argv.inspect}" if $debug
463
+ return argv
464
+ end
465
+
466
+ #
467
+
468
+ def parse_missing(argv)
469
+ argv.each_with_index do |a,i|
470
+ if a =~ /^-/
471
+ #raise InvalidOptionError.new(a) unless @__self__.respond_to?(:option_missing)
472
+ kept = @__self__.option_missing(a, *argv[i+1,1])
473
+ argv.delete_at(i) if kept # delete if value kept
474
+ argv.delete_at(i) # delete option
475
+ end
476
+ end
477
+ return argv
478
+ end
479
+
480
+ #
481
+
482
+ def option_missing(opt, arg=nil)
483
+ raise InvalidOptionError.new(opt)
484
+ # #$stderr << "Unknown option '#{arg}'.\n"
485
+ # #exit -1
486
+ end
487
+
488
+ #
489
+
490
+ def to_h
491
+ #writers = public_methods.sellect{ |m| m =~ /=$/ }
492
+ instance_variables.inject({}) do |h, v|
493
+ h[v[1,-1]] = instance_variable_get(v); h
494
+ end
495
+ end
496
+
497
+ # Provides a very basic usage help string.
498
+ #
499
+ # TODO Add support for __options.
500
+ def usage
501
+ str = []
502
+ public_methods(false).sort.each do |meth|
503
+ meth = meth.to_s
504
+ case meth
505
+ when /^_/
506
+ opt = meth.sub(/^_+/, '')
507
+ meth = method(meth)
508
+ if meth.arity == 0
509
+ str << (opt.size > 1 ? "[--#{opt}]" : "[-#{opt}]")
510
+ elsif meth.arity == 1
511
+ str << (opt.size > 1 ? "[--#{opt} value]" : "[-#{opt} value]")
512
+ elsif meth.arity > 0
513
+ v = []; meth.arity.times{ |i| v << 'value' + (i + 1).to_s }
514
+ str << (opt.size > 1 ? "[--#{opt} #{v.join(' ')}]" : "[-#{opt} #{v.join(' ')}]")
515
+ else
516
+ str << (opt.size > 1 ? "[--#{opt} *values]" : "[-#{opt} *values]")
517
+ end
518
+ when /=$/
519
+ opt = meth.chomp('=')
520
+ str << (opt.size > 1 ? "[--#{opt} value]" : "[-#{opt} value]")
521
+ when /!$/
522
+ opt = meth.chomp('!')
523
+ str << (opt.size > 1 ? "[--#{opt}]" : "[-#{opt}]")
524
+ end
525
+ end
526
+ return str.join(" ")
527
+ end
528
+
529
+ #
530
+
531
+ def self.usage_class(usage)
532
+ c = Class.new(self)
533
+ argv = Shellwords.shellwords(usage)
534
+ argv.each_with_index do |name, i|
535
+ if name =~ /^-/
536
+ if argv[i+1] =~ /^[(.*?)]/
537
+ c.class_eval %{
538
+ attr_accessor :#{name}
539
+ }
540
+ else
541
+ c.class_eval %{
542
+ attr_reader :#{name}
543
+ def #{name}! ; @#{name} = true ; end
544
+ }
545
+ end
546
+ end
547
+ end
548
+ return c
549
+ end
550
+
551
+ # # Single Option
552
+ #
553
+ # class Option < String
554
+ #
555
+ # def initialize(option)
556
+ # @flag = option
557
+ # @long = (/^--/ =~ option)
558
+ # super(option.sub(/^-{1,2}/,''))
559
+ # end
560
+ #
561
+ # def long?
562
+ # @long
563
+ # end
564
+ #
565
+ # def short?
566
+ # !@long
567
+ # end
568
+ #
569
+ # #def demethodize
570
+ # # sub('__','--').sub('_','-')
571
+ # #end
572
+ #
573
+ # def methodize
574
+ # @flag.sub(/^-{1,2}/,'')
575
+ # end
576
+ #
577
+ # end
578
+
579
+ end
580
+
581
+ # For CommandOptions, but defined external to it, so
582
+ # that it is easy to access from user defined commands.
583
+ # (This lookup issue should be fixed in Ruby 1.9+, and then
584
+ # the class can be moved back into Command namespace.)
585
+
586
+ class InvalidOptionError < StandardError
587
+ def initialize(option_name)
588
+ @option_name = option_name
589
+ end
590
+ def message
591
+ "Unknown option '#{@option_name}'."
592
+ end
593
+ end
594
+
262
595
  end