facets 2.0.2 → 2.0.3

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 (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