clio 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. data/CHANGES +66 -0
  2. data/MANIFEST +48 -169
  3. data/README +13 -17
  4. data/RELEASE +8 -0
  5. data/VERSION +1 -0
  6. data/lib/clio/buffer.rb +93 -0
  7. data/lib/clio/commandable.rb +71 -69
  8. data/lib/clio/commandline.rb +429 -230
  9. data/lib/clio/consoleutils.rb +0 -16
  10. data/lib/clio/facets/kernel.rb +13 -0
  11. data/lib/clio/facets/string.rb +25 -0
  12. data/lib/clio/layout.rb +14 -0
  13. data/lib/clio/layout/flow.rb +1 -0
  14. data/lib/clio/layout/line.rb +23 -0
  15. data/lib/clio/layout/list.rb +33 -0
  16. data/lib/clio/layout/split.rb +122 -0
  17. data/lib/clio/layout/stack.rb +17 -0
  18. data/lib/clio/layout/table.rb +46 -0
  19. data/lib/clio/progressbar.rb +189 -210
  20. data/lib/clio/string.rb +116 -109
  21. data/lib/clio/usage.rb +184 -0
  22. data/lib/clio/usage/argument.rb +84 -0
  23. data/lib/clio/usage/command.rb +440 -0
  24. data/lib/clio/usage/interface.rb +122 -0
  25. data/lib/clio/usage/main.rb +165 -0
  26. data/lib/clio/usage/option.rb +251 -0
  27. data/lib/clio/usage/parser.rb +191 -0
  28. data/lib/clio/usage/signature.rb +55 -0
  29. data/meta/abstract +3 -0
  30. data/meta/authors +1 -0
  31. data/meta/created +1 -0
  32. data/meta/homepage +1 -0
  33. data/meta/license +1 -0
  34. data/meta/repository +1 -0
  35. data/meta/summary +1 -0
  36. data/spec/commandline/autousage.rd +56 -0
  37. data/spec/commandline/bracket.rd +64 -0
  38. data/spec/commandline/completion.rd +38 -0
  39. data/spec/commandline/define.rd +44 -0
  40. data/spec/commandline/method.rd +60 -0
  41. data/spec/commandline/parse.rd +72 -0
  42. data/spec/commandline/scenario.rd +81 -0
  43. data/spec/commandline/subclass.rd +54 -0
  44. data/spec/string/unit.rd +58 -0
  45. data/spec/usage/define.rd +44 -0
  46. data/spec/usage/parse.rd +47 -0
  47. metadata +65 -196
  48. data/HISTORY +0 -11
  49. data/METADATA +0 -18
  50. data/NEWS +0 -10
  51. data/admin/config/reap.yaml +0 -30
  52. data/admin/depot/commandline.rb +0 -219
  53. data/admin/depot/multicommand.rb +0 -403
  54. data/admin/depot/test_multicommand.rb +0 -40
  55. data/admin/log/notes.xml +0 -28
  56. data/admin/log/stats.html +0 -25
  57. data/admin/log/syntax.log +0 -0
  58. data/admin/log/testunit.log +0 -16
  59. data/admin/pack/clio-0.0.1.gem +0 -0
  60. data/admin/share/reap/example.rb +0 -7
  61. data/admin/temps/lib/clio/about.rb.erb +0 -4
  62. data/lib/clio/command.rb +0 -296
  63. data/lib/clio/option.rb +0 -36
  64. data/lib/clio/runmode.rb +0 -126
  65. data/test/test_command.rb +0 -42
  66. data/test/test_commandline.rb +0 -83
  67. data/vendor/Console/Console.cpp +0 -1203
  68. data/vendor/Console/Console.rdoc +0 -690
  69. data/vendor/Console/Console_ANSI.rdoc +0 -302
  70. data/vendor/Console/HISTORY.txt +0 -7
  71. data/vendor/Console/INSTALL.txt +0 -18
  72. data/vendor/Console/Makefile +0 -162
  73. data/vendor/Console/README.txt +0 -26
  74. data/vendor/Console/doc/classes/Win32.html +0 -115
  75. data/vendor/Console/doc/classes/Win32/Console.html +0 -650
  76. data/vendor/Console/doc/classes/Win32/Console.src/M000001.html +0 -31
  77. data/vendor/Console/doc/classes/Win32/Console.src/M000002.html +0 -23
  78. data/vendor/Console/doc/classes/Win32/Console.src/M000003.html +0 -23
  79. data/vendor/Console/doc/classes/Win32/Console.src/M000004.html +0 -27
  80. data/vendor/Console/doc/classes/Win32/Console.src/M000005.html +0 -23
  81. data/vendor/Console/doc/classes/Win32/Console.src/M000006.html +0 -28
  82. data/vendor/Console/doc/classes/Win32/Console.src/M000007.html +0 -23
  83. data/vendor/Console/doc/classes/Win32/Console.src/M000008.html +0 -24
  84. data/vendor/Console/doc/classes/Win32/Console.src/M000009.html +0 -44
  85. data/vendor/Console/doc/classes/Win32/Console.src/M000010.html +0 -23
  86. data/vendor/Console/doc/classes/Win32/Console.src/M000011.html +0 -33
  87. data/vendor/Console/doc/classes/Win32/Console.src/M000012.html +0 -26
  88. data/vendor/Console/doc/classes/Win32/Console.src/M000013.html +0 -27
  89. data/vendor/Console/doc/classes/Win32/Console.src/M000014.html +0 -28
  90. data/vendor/Console/doc/classes/Win32/Console.src/M000015.html +0 -23
  91. data/vendor/Console/doc/classes/Win32/Console.src/M000016.html +0 -23
  92. data/vendor/Console/doc/classes/Win32/Console.src/M000017.html +0 -23
  93. data/vendor/Console/doc/classes/Win32/Console.src/M000018.html +0 -29
  94. data/vendor/Console/doc/classes/Win32/Console.src/M000019.html +0 -23
  95. data/vendor/Console/doc/classes/Win32/Console.src/M000020.html +0 -23
  96. data/vendor/Console/doc/classes/Win32/Console.src/M000021.html +0 -28
  97. data/vendor/Console/doc/classes/Win32/Console.src/M000022.html +0 -23
  98. data/vendor/Console/doc/classes/Win32/Console.src/M000023.html +0 -28
  99. data/vendor/Console/doc/classes/Win32/Console.src/M000024.html +0 -35
  100. data/vendor/Console/doc/classes/Win32/Console.src/M000025.html +0 -28
  101. data/vendor/Console/doc/classes/Win32/Console.src/M000026.html +0 -28
  102. data/vendor/Console/doc/classes/Win32/Console.src/M000027.html +0 -28
  103. data/vendor/Console/doc/classes/Win32/Console.src/M000028.html +0 -31
  104. data/vendor/Console/doc/classes/Win32/Console.src/M000029.html +0 -23
  105. data/vendor/Console/doc/classes/Win32/Console.src/M000030.html +0 -23
  106. data/vendor/Console/doc/classes/Win32/Console.src/M000031.html +0 -23
  107. data/vendor/Console/doc/classes/Win32/Console.src/M000032.html +0 -27
  108. data/vendor/Console/doc/classes/Win32/Console.src/M000033.html +0 -27
  109. data/vendor/Console/doc/classes/Win32/Console.src/M000034.html +0 -25
  110. data/vendor/Console/doc/classes/Win32/Console/ANSI.html +0 -103
  111. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.html +0 -220
  112. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000035.html +0 -32
  113. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000036.html +0 -205
  114. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000037.html +0 -40
  115. data/vendor/Console/doc/classes/Win32/Console/ANSI/IO.src/M000038.html +0 -25
  116. data/vendor/Console/doc/classes/Win32/Console/API.html +0 -758
  117. data/vendor/Console/doc/classes/Win32/Console/API.src/M000039.html +0 -27
  118. data/vendor/Console/doc/classes/Win32/Console/API.src/M000040.html +0 -27
  119. data/vendor/Console/doc/classes/Win32/Console/API.src/M000041.html +0 -27
  120. data/vendor/Console/doc/classes/Win32/Console/API.src/M000042.html +0 -32
  121. data/vendor/Console/doc/classes/Win32/Console/API.src/M000043.html +0 -32
  122. data/vendor/Console/doc/classes/Win32/Console/API.src/M000044.html +0 -28
  123. data/vendor/Console/doc/classes/Win32/Console/API.src/M000045.html +0 -26
  124. data/vendor/Console/doc/classes/Win32/Console/API.src/M000046.html +0 -26
  125. data/vendor/Console/doc/classes/Win32/Console/API.src/M000047.html +0 -27
  126. data/vendor/Console/doc/classes/Win32/Console/API.src/M000048.html +0 -30
  127. data/vendor/Console/doc/classes/Win32/Console/API.src/M000049.html +0 -29
  128. data/vendor/Console/doc/classes/Win32/Console/API.src/M000050.html +0 -27
  129. data/vendor/Console/doc/classes/Win32/Console/API.src/M000051.html +0 -28
  130. data/vendor/Console/doc/classes/Win32/Console/API.src/M000052.html +0 -30
  131. data/vendor/Console/doc/classes/Win32/Console/API.src/M000053.html +0 -27
  132. data/vendor/Console/doc/classes/Win32/Console/API.src/M000054.html +0 -29
  133. data/vendor/Console/doc/classes/Win32/Console/API.src/M000055.html +0 -29
  134. data/vendor/Console/doc/classes/Win32/Console/API.src/M000056.html +0 -28
  135. data/vendor/Console/doc/classes/Win32/Console/API.src/M000057.html +0 -27
  136. data/vendor/Console/doc/classes/Win32/Console/API.src/M000058.html +0 -47
  137. data/vendor/Console/doc/classes/Win32/Console/API.src/M000059.html +0 -32
  138. data/vendor/Console/doc/classes/Win32/Console/API.src/M000060.html +0 -47
  139. data/vendor/Console/doc/classes/Win32/Console/API.src/M000061.html +0 -34
  140. data/vendor/Console/doc/classes/Win32/Console/API.src/M000062.html +0 -32
  141. data/vendor/Console/doc/classes/Win32/Console/API.src/M000063.html +0 -32
  142. data/vendor/Console/doc/classes/Win32/Console/API.src/M000064.html +0 -35
  143. data/vendor/Console/doc/classes/Win32/Console/API.src/M000065.html +0 -26
  144. data/vendor/Console/doc/classes/Win32/Console/API.src/M000066.html +0 -27
  145. data/vendor/Console/doc/classes/Win32/Console/API.src/M000067.html +0 -29
  146. data/vendor/Console/doc/classes/Win32/Console/API.src/M000068.html +0 -27
  147. data/vendor/Console/doc/classes/Win32/Console/API.src/M000069.html +0 -27
  148. data/vendor/Console/doc/classes/Win32/Console/API.src/M000070.html +0 -28
  149. data/vendor/Console/doc/classes/Win32/Console/API.src/M000071.html +0 -27
  150. data/vendor/Console/doc/classes/Win32/Console/API.src/M000072.html +0 -26
  151. data/vendor/Console/doc/classes/Win32/Console/API.src/M000073.html +0 -27
  152. data/vendor/Console/doc/classes/Win32/Console/API.src/M000074.html +0 -31
  153. data/vendor/Console/doc/classes/Win32/Console/API.src/M000075.html +0 -27
  154. data/vendor/Console/doc/classes/Win32/Console/API.src/M000076.html +0 -32
  155. data/vendor/Console/doc/classes/Win32/Console/API.src/M000077.html +0 -27
  156. data/vendor/Console/doc/classes/Win32/Console/API.src/M000078.html +0 -32
  157. data/vendor/Console/doc/classes/Win32/Console/API.src/M000079.html +0 -32
  158. data/vendor/Console/doc/classes/Win32/Console/API.src/M000080.html +0 -32
  159. data/vendor/Console/doc/classes/Win32/Console/Constants.html +0 -360
  160. data/vendor/Console/doc/created.rid +0 -1
  161. data/vendor/Console/doc/files/Console_ANSI_rdoc.html +0 -407
  162. data/vendor/Console/doc/files/Console_cpp.html +0 -104
  163. data/vendor/Console/doc/files/Console_rdoc.html +0 -964
  164. data/vendor/Console/doc/files/lib/Win32/Console/ANSI_rb.html +0 -123
  165. data/vendor/Console/doc/files/lib/Win32/Console_rb.html +0 -297
  166. data/vendor/Console/doc/fr_class_index.html +0 -32
  167. data/vendor/Console/doc/fr_file_index.html +0 -31
  168. data/vendor/Console/doc/fr_method_index.html +0 -106
  169. data/vendor/Console/doc/index.html +0 -24
  170. data/vendor/Console/doc/rdoc-style.css +0 -172
  171. data/vendor/Console/extconf.rb +0 -18
  172. data/vendor/Console/lib/Term/ansicolor.rb +0 -76
  173. data/vendor/Console/lib/Win32/Console.rb +0 -970
  174. data/vendor/Console/lib/Win32/Console/ANSI.rb +0 -305
  175. data/vendor/Console/test/test_cursor.rb +0 -9
  176. data/vendor/Console/test/test_mouse.rb +0 -6
  177. data/vendor/Console/test/test_readinput.rb +0 -62
  178. data/vendor/Console/test/test_readoutput.rb +0 -52
  179. data/vendor/Console/test/test_sendevent.rb +0 -17
  180. data/vendor/Console/test/test_title.rb +0 -14
  181. data/vendor/Console/test/test_write.rb +0 -36
@@ -0,0 +1,440 @@
1
+ require 'clio/usage/option'
2
+ require 'clio/usage/argument'
3
+
4
+ module Clio
5
+
6
+ module Usage #:nodoc:
7
+
8
+ # = Commandline Usage Command
9
+ #
10
+ # This is the heart of usage; subclassed by Main and
11
+ # containing together Options and Arguments.
12
+ #
13
+ # usage = Usage.new
14
+ #
15
+ class Command
16
+
17
+ # Parent command. This is needed
18
+ # to support cascading options.
19
+ #--
20
+ # NOTE: If it were possible to have this it would be better.
21
+ #++
22
+ attr :parent
23
+
24
+ # Name of the command.
25
+ attr :name
26
+
27
+ # Array of subcommands.
28
+ attr :subcommands
29
+
30
+ # Array of arguments. Arguments and subcommands
31
+ # are mutually exclusive, ie. either @arguments
32
+ # or @subcommands will be empty.
33
+ #
34
+ # TODO: Could use single attribute for both subcommands
35
+ # and arguments and use a flag to designate which type.
36
+ attr :arguments
37
+
38
+ # Array of options.
39
+ attr :options
40
+
41
+ # Help text.
42
+ attr :help
43
+
44
+ # Widely accepted alternate term for options.
45
+ alias_method :switches, :options
46
+
47
+ #
48
+ def initialize(name, parent=nil, &block)
49
+ @name = name.to_s
50
+ @parent = parent
51
+ @subcommands = []
52
+ @options = []
53
+ @arguments = []
54
+ @help = ''
55
+ instance_eval(&block) if block
56
+ end
57
+
58
+ #
59
+ def initialize_copy(c)
60
+ @parent = c.parent
61
+ @name = c.name.dup
62
+ @options = c.options.dup
63
+ @arguments = c.arguments.dup
64
+ @subcommands = c.subcommands.dup
65
+ @help = c.help.dup
66
+ end
67
+
68
+ def key ; @name.to_sym ; end
69
+
70
+ # METHOD MISSING
71
+ #-------------------------------------------------------------
72
+
73
+ def method_missing(key, *args, &blk)
74
+ key = key.to_s
75
+ case key
76
+ when /\?$/
77
+ option(key.chomp('?'), *args, &blk)
78
+ else
79
+ #k = full_name ? "#{full_name} #{key}" : "#{key}"
80
+ c = command(key, &blk)
81
+ args.each{ |a| c[a] }
82
+ c
83
+ end
84
+ end
85
+
86
+ #
87
+ def help!(*args)
88
+ Hash[*args].each do |key, desc|
89
+ self[key, desc]
90
+ end
91
+ end
92
+
93
+ # Define or retrieve a command.
94
+ #
95
+ # subcommand('remote')
96
+ #
97
+ # A shortcut to accessing subcommands of subcommands, the following
98
+ # statements are equivalent:
99
+ #
100
+ # subcommand('remote').subcommand('add')
101
+ #
102
+ # subcommand('remote add')
103
+ #
104
+ def subcommand(name, help=nil, &block)
105
+ name, names = *name.to_s.strip.split(/\s+/)
106
+ if names
107
+ names = [name, *names]
108
+ cmd = names.inject(self) do |c, n|
109
+ c.subcommand(n)
110
+ end
111
+ else
112
+ cmd = subcommands.find{ |c| c === name }
113
+ unless cmd
114
+ cmd = Command.new(name, self)
115
+ subcommands << cmd
116
+ end
117
+ end
118
+ cmd.help(help) if help
119
+ cmd.instance_eval(&block) if block
120
+ cmd
121
+ end
122
+
123
+ alias_method :cmd, :subcommand
124
+ alias_method :command, :subcommand
125
+
126
+ alias_method :commands, :subcommands
127
+
128
+ # Define an option.
129
+ #
130
+ # option(:output, :o)
131
+ #
132
+ def option(name, *aliases, &block)
133
+ opt = options.find{|o| o === name}
134
+ if not opt
135
+ opt = Option.new(name) #, self)
136
+ #opt.aliases(*aliases)
137
+ @options << opt
138
+ end
139
+ opt.aliases(*aliases) unless aliases.empty?
140
+ opt.instance_eval(&block) if block
141
+ opt
142
+ end
143
+
144
+ alias_method :switch, :option
145
+
146
+ # Option shorthand.
147
+ #
148
+ # opt('--output=FILE -o', 'output directory')
149
+ #
150
+ def opt(name, help=nil)
151
+ name, *aliases = name.split(/\s+/)
152
+ name, type = *name.split('=')
153
+ mult = false
154
+ if type && type[0,1] == '*'
155
+ mult = true
156
+ type = type[1..-1]
157
+ end
158
+ name = option_name(name).to_sym
159
+ o = option(name, *aliases)
160
+ o.help(help) if help
161
+ o.argument(type) if type
162
+ o.multiple(mult)
163
+ self
164
+ end
165
+
166
+ alias_method :swt, :opt
167
+
168
+ # A switch is like an option, but it is greedy.
169
+ # When parsed it will pick-up any match subsequent
170
+ # the switch's parent command. In other words,
171
+ # switches are consumed by a command even if they
172
+ # appear in a subcommand's arguments.
173
+ #
174
+ #def switch(name, *aliases, &block)
175
+ # if opt = @switches.find{|o| o === name}
176
+ # else
177
+ # opt = Option.new(name, self)
178
+ # opt.greedy = true
179
+ # opt.aliases(*aliases)
180
+ # @switches << opt
181
+ # end
182
+ # opt.instance_eval(&block) if block
183
+ # opt
184
+ #end
185
+
186
+ # Switch shorthand.
187
+ #
188
+ # swt('--output=FILE -o', 'output directory')
189
+ #
190
+ #def swt(name, help=nil)
191
+ # name, *aliases = name.split(/\s+/)
192
+ # name, type = *name.split('=')
193
+ # mult = false
194
+ # if type && type[0,1] == '*'
195
+ # mult = true
196
+ # type = type[1..-1]
197
+ # end
198
+ # name = clean_name(name)
199
+ # o = switch(name, *aliases)
200
+ # o.help(help) if help
201
+ # o.argument(type) if type
202
+ # o.multiple(mult)
203
+ # self
204
+ #end
205
+
206
+ # Define an argument.
207
+ # Takes a name, optional index and block.
208
+ #
209
+ # Indexing of arguments starts at 1, not 0.
210
+ #
211
+ # Examples
212
+ #
213
+ # argument(:path)
214
+ # argument(1, :path)
215
+ #
216
+ def argument(*n_type, &block)
217
+ index = Integer===n_type[0] ? n_type.shift : @arguments.size + 1
218
+ type = n_type.shift
219
+ help = n_type.shift
220
+
221
+ index = index - 1
222
+ type = type.to_s.sub(/^\</,'').chomp('>')
223
+
224
+ if type[0,1] == '*'
225
+ type.sub!('*', '')
226
+ splat = true
227
+ elsif type[-1,1] == '*'
228
+ type.sub!(/[*]$/, '')
229
+ splat = true
230
+ else
231
+ splat = false
232
+ end
233
+
234
+ raise "Command cannot have both arguments (eg. #{type}) and subcommands." unless subcommands.empty?
235
+
236
+ if arg = @arguments[index]
237
+ arg.type(type) if type
238
+ arg.help(help) if help
239
+ arg.splat(splat) if splat
240
+ arg.instance_eval(&block) if block
241
+ else
242
+ if type || block
243
+ arg = Argument.new(type, &block) #self, &block)
244
+ arg.help(help) if help
245
+ arg.splat(splat) if splat
246
+ @arguments[index] = arg
247
+ end
248
+ end
249
+ return arg
250
+ end
251
+
252
+ alias_method :arg, :argument
253
+
254
+ # Argument shorthand.
255
+ #
256
+ # arg('PIN', 'pin number')
257
+ #
258
+ #def arg(type=nil, help=nil)
259
+ # type = type.to_s.sub(/^\</,'').chomp('>')
260
+ # argument(type).help(help)
261
+ # self
262
+ #end
263
+
264
+ #
265
+ def help(string=nil)
266
+ @help.replace(string.to_s) if string
267
+ @help
268
+ end
269
+
270
+ # SHORTHAND NOTATION
271
+ #-------------------------------------------------------------
272
+
273
+ # Super shorthand notation.
274
+ #
275
+ # cli['document']['--output=FILE -o']['<files>']
276
+ #
277
+ def [](*x)
278
+ case x[0].to_s[0,1]
279
+ when '-'
280
+ opt(*x)
281
+ when '<'
282
+ arg(*x)
283
+ else
284
+ subcommand(*x)
285
+ end
286
+ end
287
+
288
+ # QUERY METHODS
289
+ #-------------------------------------------------------------
290
+
291
+ #
292
+ def completion
293
+ if subcommands.empty?
294
+ options.collect{|o| o.to_s.strip } +
295
+ arguments.collect{|c| c.name}
296
+ else
297
+ options.collect{|o| o.to_s.strip } +
298
+ subcommands.collect{|c| c.name}
299
+ end
300
+ end
301
+
302
+ # Option defined?
303
+ #
304
+ def option?(name)
305
+ opt = options.find{|o| o === name}
306
+ if parent && !opt
307
+ opt = parent.option?(name)
308
+ end
309
+ opt
310
+ #return opt if opt
311
+ #options.each do |o|
312
+ # return o if o.aliases.include?(key)
313
+ #end
314
+ #nil
315
+ end
316
+
317
+ alias_method :switch?, :option
318
+
319
+ # Greedy Option defined?
320
+ #
321
+ #def greedy_option?(key)
322
+ # switches.find{|o| o === key}
323
+ #end
324
+
325
+ #
326
+ def ===(other_name)
327
+ name == other_name.to_s
328
+ end
329
+
330
+ #
331
+ def inspect
332
+ s = ''
333
+ s << "#<#{self.class}:#{object_id} #{@name}"
334
+ s << " @arguments=#{@arguments.inspect} " unless @arguments.empty?
335
+ s << " @options=#{@options.inspect} " unless @options.empty?
336
+ #s << "@switches=#{@switches.inspect} " unless @switches.empty?
337
+ s << " @help=#{@help.inspect}" unless @help.empty?
338
+ #s << "@commands=#{@commands.inspect} " unless @commands.empty?
339
+ s << ">"
340
+ s
341
+ end
342
+
343
+ # Full callable command name.
344
+ def full_name
345
+ if parent && parent.full_name
346
+ "#{parent.full_name} #{name}"
347
+ else
348
+ "#{name}"
349
+ end
350
+ end
351
+
352
+ # Usage text.
353
+ #
354
+ def to_s
355
+ #s = [full_name]
356
+ s = [name]
357
+
358
+ case options.size
359
+ when 0
360
+ when 1, 2, 3
361
+ s.concat(options.collect{ |o| "[#{o.to_s.strip}]" })
362
+ else
363
+ s << "[switches]" # switches? vs. options
364
+ end
365
+
366
+ s << arguments.join(' ') unless arguments.empty?
367
+
368
+ case subcommands.size
369
+ when 0
370
+ when 1
371
+ s << subcommands.join('')
372
+ when 2, 3
373
+ s << '[' + subcommands.join(' | ') + ']'
374
+ else
375
+ s << 'command'
376
+ end
377
+
378
+ s.flatten.join(' ')
379
+ end
380
+
381
+ # Help text.
382
+ #
383
+ def to_s_help
384
+ s = []
385
+ unless help.empty?
386
+ s << help
387
+ s << ''
388
+ end
389
+ s << "Usage:"
390
+ s << " " + to_s
391
+ unless subcommands.empty?
392
+ s << ''
393
+ s << 'Commands:'
394
+ s.concat(subcommands.collect{ |x| " %-20s %s" % [x.name, x.help] }.sort)
395
+ end
396
+ unless arguments.empty?
397
+ s << ''
398
+ s << "Arguments:"
399
+ s.concat(arguments.collect{ |x| " %-20s %s" % [x, x.help] })
400
+ end
401
+ unless options.empty?
402
+ s << ''
403
+ s << 'Switches:'
404
+ s.concat(options.collect{ |x| " %-20s %s" % [x, x.help] })
405
+ end
406
+ s.flatten.join("\n")
407
+ end
408
+
409
+ # PARSE
410
+ #-------------------------------------------------------------
411
+
412
+ # Parse usage.
413
+ def parse(argv, index=0)
414
+ @parser ||= Parser.new(self, argv, index)
415
+ @parser.parse
416
+ end
417
+
418
+ private
419
+
420
+ def option_key(key)
421
+ name = option_name(key) #.to_s
422
+ if name.size == 1
423
+ "-#{name}".to_sym
424
+ else
425
+ "--#{name}".to_sym
426
+ end
427
+ end
428
+
429
+ def option_name(name)
430
+ name = name.to_s
431
+ name = name.gsub(/^[-]+/, '')
432
+ return name.chomp('?') #.to_sym
433
+ end
434
+
435
+ end #class Command
436
+
437
+ end #module Usage
438
+
439
+ end #module Clio
440
+
@@ -0,0 +1,122 @@
1
+ module Clio
2
+
3
+ module Usage
4
+
5
+ # = Command Interface (toplevel signature)
6
+ #
7
+ # The end result provide by Usage::Parser#parse.
8
+ # This class consists of an array of command signatures
9
+ # and parse errors.
10
+ #
11
+ class Interface
12
+
13
+ attr :signatures
14
+ attr :errors
15
+
16
+ alias_method :parse_errors, :errors
17
+
18
+ #
19
+ def initialize(signatures=[], errors=[])
20
+ @signatures = signatures
21
+ @errors = errors
22
+ end
23
+
24
+ # TODO: Join by what character?
25
+ def command
26
+ return nil if commands.empty?
27
+ return commands.join(' ')
28
+ end
29
+
30
+ #
31
+ def commands
32
+ #parse unless parsed?
33
+ @commands ||= (
34
+ a = []
35
+ @signatures[1..-1].each do |s|
36
+ a << s.command.to_s
37
+ end
38
+ a
39
+ )
40
+ end
41
+
42
+ #
43
+ def options
44
+ #parse unless parsed?
45
+ @options ||= (
46
+ h = {}
47
+ @signatures.each do |s|
48
+ h.merge!(s.options)
49
+ end
50
+ h
51
+ )
52
+ end
53
+ alias_method :switches, :options
54
+
55
+ #
56
+ def arguments
57
+ #parse unless parsed?
58
+ @arguments ||= (
59
+ m = []
60
+ @signatures.each do |s|
61
+ m.concat(s.arguments)
62
+ end
63
+ m
64
+ )
65
+ end
66
+
67
+ # Return parameters array of [*arguments, options]
68
+ def parameters
69
+ arguments + [options]
70
+ end
71
+
72
+ #def signatures
73
+ # parse unless parsed?
74
+ # a = [[usage, arguments, options]]
75
+ # a += command.signatures if command
76
+ # a
77
+ #end
78
+
79
+ # Were the commandline arguments valid?
80
+ # This simply checks to see if there were
81
+ # any parse errors.
82
+ def valid?
83
+ #parse unless @parsed
84
+ errors.empty?
85
+ end
86
+
87
+ # Index on each subcommand, with 0 being the toplevel command.
88
+ def [](i)
89
+ @signatures[i]
90
+ end
91
+
92
+ #
93
+ def to_a
94
+ #parse unless parsed?
95
+ @signatures.collect{ |s| s.to_a }
96
+ end
97
+
98
+ #
99
+ def method_missing(s, *a)
100
+ s = s.to_s
101
+ case s
102
+ #when /[=]$/
103
+ # n = s.chomp('=')
104
+ # usage.option(n).type(*a)
105
+ # #parser.parse
106
+ # res = parser.options[n.to_sym]
107
+ #when /[!]$/
108
+ # n = s.chomp('!')
109
+ # res = parser.parse
110
+ when /[?]$/
111
+ options[s.chomp('?').to_sym]
112
+ else
113
+ options[s.to_sym]
114
+ end
115
+ end
116
+
117
+ end#class Interface
118
+
119
+ end#module Usage
120
+
121
+ end#module Clio
122
+