clio 0.0.1 → 0.2.0

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