clio 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,10 +1,22 @@
1
+ == 0.3.0 / 2008-11-19
2
+
3
+ * 5 Other Enhancements
4
+
5
+ * improved usage specs (#2e805f40a05afcccdf59bad087b759d1fda60354)
6
+ * string.rb, fixed gsub (#f7449ced8d9757aefb8dedb04e65821fd174a31d)
7
+ * renamed Usage::Main to Usage::Command and Usage::Command to Usage::Subcommand (#42ccad02a7f5a68461e70c4ef775a8751facbddb)
8
+ * remove QED from end of specs (#0a820c7c44db3d1a6e7b1950152fabdaae006381)
9
+ * Merge: 0a820c7... f7449ce...
10
+ improved string spec (#b0579c898f02be2a3644e3f4bc233f9795f9a122)
11
+
12
+
1
13
  == 0.2.0 / 2008-11-15
2
14
 
3
15
  * 1 Major Enhancements
4
16
 
5
17
  * commandline now has a full parser (#251ff8fb0d6e56dd6e90d6e859e840717af004e4)
6
18
 
7
- * 46 Other Enhancements
19
+ * 52 Other Enhancements
8
20
 
9
21
  * capitialized main files (#1ac75f6de90bab8a696e657b4b33f936c969bbe2)
10
22
  * moved multicommand prototype to depot (#efe1d718e191394fa73064e4527a113374c55931)
@@ -52,6 +64,12 @@
52
64
  * clio/string.rb, fixed require (#4a519dd76be6e66454424edbe9eb790c786fc582)
53
65
  * all specs now pass (#4b90a0b08a6a97ab29453b647ef969a7384f2d5d)
54
66
  * avoid class with Clio::String and use ::String where needed (#471a0b1480207324ecf17ffe2943dac29fedba7e)
67
+ * updated reap configs (#361162622b25a25b5600a55f523ee80d2f719208)
68
+ * update README and VERSION (0.2.0) (#01d804e3789b5d58fd7e6243a11ea0ba65f96296)
69
+ * argument.rb, added splat option (#4d37a8906945c223100cc0d617a8ecbe9f25b863)
70
+ * support for argument added splat option (#8176e5cee31f2a8fa73e0f151f504a40f0a9a21a)
71
+ * added some website assets (#16e6b765fd606f5c09d43b52f6d0104aa55fc56f)
72
+ * added doc/spec to .gitignore (#1fc846f54b304da8956fecc84d9287641a5da052)
55
73
 
56
74
 
57
75
  == 0.0.1 / 2008-08-29
data/MANIFEST CHANGED
@@ -14,6 +14,7 @@ spec/commandline/scenario.rd
14
14
  spec/string
15
15
  spec/string/unit.rd
16
16
  spec/commandable
17
+ MANIFEST
17
18
  CHANGES
18
19
  RELEASE
19
20
  README
@@ -31,11 +32,11 @@ lib/clio/facets
31
32
  lib/clio/facets/kernel.rb
32
33
  lib/clio/facets/string.rb
33
34
  lib/clio/usage
34
- lib/clio/usage/main.rb
35
35
  lib/clio/usage/signature.rb
36
36
  lib/clio/usage/command.rb
37
37
  lib/clio/usage/parser.rb
38
38
  lib/clio/usage/argument.rb
39
+ lib/clio/usage/subcommand.rb
39
40
  lib/clio/usage/interface.rb
40
41
  lib/clio/usage/option.rb
41
42
  lib/clio/commandline.rb
data/README CHANGED
@@ -6,11 +6,10 @@
6
6
  == INTRODUCTION
7
7
 
8
8
  Clio is a great way to build commandline tools.
9
- It provides an advanced options parser with
10
- a variety of notations suited to almost any
11
- perfered style, and provides a very rich and
12
- and easy to use library for generating console
13
- output.
9
+ It provides an advanced options parser with a variety
10
+ of notations suited to almost any perfered style,
11
+ and provides a very rich and and easy to use library
12
+ for generating console output.
14
13
 
15
14
 
16
15
  == RELEASE NOTES
@@ -35,7 +34,7 @@ Clio .tgz package and type:
35
34
 
36
35
  == USAGE
37
36
 
38
- Please see the RDoc API.
37
+ For now please see the RDoc API.
39
38
 
40
39
 
41
40
  == LICENSE
data/RELEASE CHANGED
@@ -1,8 +1,13 @@
1
- This is the initial release of Clio. While useable,
2
- it is still very much APLHA code. The API is still
3
- in flux and needs a lot more testing before I'd
4
- put it to gereral use.
1
+ Clio is much cloer to a stable status. This release
2
+ has a fairly large set of passing specifications.
5
3
 
6
- ### 0.0.1 // 2008-08-29
4
+ ### 0.3.0 // 2008-08-29
7
5
 
6
+ 1 Major Change
7
+
8
+ * Rename Usage Main to Command and Command to Subcommand.
9
+
10
+ 1 Minor Change
11
+
12
+ * Fixed many small bugs.
8
13
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- clio 0.2.0 beta (2008-11-15)
1
+ clio 0.3.0 beta (2008-11-19)
@@ -1,4 +1,3 @@
1
- require 'clio/facets/kernel' # for deep_copy
2
1
  require 'clio/usage'
3
2
  #require 'shellwords'
4
3
 
@@ -183,7 +182,7 @@ module Clio
183
182
  #def inherited(subclass)
184
183
  #p usage.to_s
185
184
  #p subclass.usage.to_s
186
- # subclass.usage = self.usage.clone #deep_copy
185
+ # subclass.usage = self.usage.clone #deep copy?
187
186
  #p subclass.usage.to_s
188
187
  # end
189
188
 
@@ -203,12 +202,6 @@ module Clio
203
202
  @usage = u
204
203
  end
205
204
 
206
- # if ancestors[1] < Command
207
- # @usage = ancestors[0].usage.deep_copy
208
- # else
209
- # @usage = Usage.new
210
- # end
211
-
212
205
  #
213
206
  def subcommand(name, help=nil, &block)
214
207
  usage.subcommand(name, help, &block)
@@ -256,7 +249,7 @@ module Clio
256
249
  if self.class == Commandline
257
250
  @usage = Usage.new
258
251
  else
259
- @usage = self.class.usage #|| Usage.new #.deep_copy
252
+ @usage = self.class.usage #|| Usage.new
260
253
  end
261
254
  @usage.instance_eval(&block) if block
262
255
  end
@@ -32,8 +32,8 @@ module Clio
32
32
  s = text.dup
33
33
  m = marks.sort{ |a,b| b[0] <=> a[0] }
34
34
  m.each do |index, codes|
35
- codes.each do |code|
36
- s.insert(index, ANSICode.send(code))
35
+ codes.reverse_each do |code|
36
+ s.insert(index, ANSICode.__send__(code))
37
37
  end
38
38
  end
39
39
  s
@@ -41,20 +41,6 @@ module Clio
41
41
 
42
42
  def size ; text.size ; end
43
43
 
44
- ###
45
- def color!(ansicolor)
46
- marks[0] << ansicolor
47
- marks[size] << :clear
48
- end
49
-
50
- ###
51
- def color(ansicolor)
52
- m = marks.dup
53
- m[0] << ansicolor
54
- m[size] << :clear
55
- self.class.new(text, m)
56
- end
57
-
58
44
  ###
59
45
  def upcase ; self.class.new(text.upcase, marks) ; end
60
46
  def upcase! ; text.upcase! ; end
@@ -69,7 +55,8 @@ module Clio
69
55
  when String
70
56
  ntext = text + other.text
71
57
  nmarks = marks.dup
72
- other.marks.each{ |i, c| m[i] << c }
58
+ omarks = shift_marks(0, text.size, other.marks)
59
+ omarks.each{ |i, c| nmarks[i].concat(c) }
73
60
  else
74
61
  ntext = text + other.to_s
75
62
  nmarks = marks.dup
@@ -117,38 +104,110 @@ module Clio
117
104
 
118
105
  alias_method :[], :slice
119
106
 
120
- # TODO: block support and \1, \2 support.
107
+ # This is more limited than the normal String method.
108
+ # It does not yet support a block, and +replacement+
109
+ # won't substitue for \1, \2, etc.
110
+ #
111
+ # TODO: block support.
112
+ def sub!(pattern,replacement)
113
+ mark_changes = []
114
+ text = @text.sub(pattern) do |s|
115
+ index = $~.begin(0)
116
+ delta = (replacement.size - s.size)
117
+ mark_changes << [index, delta]
118
+ replacement
119
+ end
120
+ marks = @marks
121
+ mark_changes.each do |index, delta|
122
+ marks = shift_marks(index, delta, marks)
123
+ end
124
+ @text = text
125
+ @marks = marks
126
+ self
127
+ end
128
+
129
+ #
121
130
  def sub(pattern,replacement)
122
- if md = pattern.match(@text)
123
- delta = replacement.size - md.size
124
- marks2 = shift_marks(md.end, delta)
125
- text2 = text.sub(pattern,replacement)
126
- self.class.new(text2, marks2)
127
- else
128
- self.class.new(text, marks)
131
+ dup.sub!(pattern, replacement)
132
+ end
133
+
134
+ #
135
+ def gsub!(pattern,replacement)
136
+ mark_changes = []
137
+ text = @text.gsub(pattern) do |s|
138
+ index = $~.begin(0)
139
+ delta = (replacement.size - s.size)
140
+ mark_changes << [index, delta]
141
+ replacement
142
+ end
143
+ marks = @marks
144
+ mark_changes.each do |index, delta|
145
+ marks = shift_marks(index, delta, marks)
129
146
  end
147
+ @text = text
148
+ @marks = marks
149
+ self
130
150
  end
131
151
 
132
152
  #
133
- def gsub
153
+ def gsub(pattern_replacement)
154
+ dup.gsub(pattern, replacement)
155
+ end
156
+
157
+ ###
158
+ def ansi(code)
159
+ m = marks.dup
160
+ m[0] << code
161
+ m[size] << :clear
162
+ self.class.new(text, m)
134
163
  end
164
+ alias_method :color, :ansi
165
+
166
+ ###
167
+ def ansi!(code)
168
+ marks[0] << ansicolor
169
+ marks[size] << :clear
170
+ end
171
+ alias_method :color!, :ansi!
172
+
173
+ def red ; color(:red) ; end
174
+ def green ; color(:green) ; end
175
+ def blue ; color(:blue) ; end
176
+ def black ; color(:black) ; end
177
+ def magenta ; color(:magenta) ; end
178
+ def yellow ; color(:yellow) ; end
179
+ def cyan ; color(:cyan) ; end
180
+
181
+ def red! ; color!(:red) ; end
182
+ def green! ; color!(:green) ; end
183
+ def blue! ; color!(:blue) ; end
184
+ def black! ; color!(:black) ; end
185
+ def magenta! ; color!(:magenta) ; end
186
+ def yellow! ; color!(:yellow) ; end
187
+ def cyan! ; color!(:cyan) ; end
135
188
 
136
189
  private
137
190
 
138
- def shift_marks(index, delta)
191
+ #
192
+ def shift_marks(index, delta, marks=nil)
139
193
  new_marks = {}
140
- marks.each do |i, v|
194
+ (marks || @marks).each do |i, v|
141
195
  case i <=> index
142
- when 0, -1
196
+ when -1
143
197
  new_marks[i] = v
144
- when 1
198
+ when 0, 1
145
199
  new_marks[i+delta] = v
146
200
  end
147
201
  end
148
202
  new_marks
149
203
  end
150
204
 
151
- end
205
+ #
206
+ def shift_marks!(index, delta)
207
+ @marks.replace(shift_marks(index, delta))
208
+ end
209
+
210
+ end # class String
152
211
 
153
- end
212
+ end # module Clio
154
213
 
@@ -1,4 +1,4 @@
1
- require 'clio/usage/main'
1
+ require 'clio/usage/command'
2
2
  require 'clio/usage/parser'
3
3
 
4
4
  module Clio
@@ -175,7 +175,7 @@ module Clio
175
175
  module Usage
176
176
 
177
177
  def self.new(name=nil, &block)
178
- Main.new(name, &block)
178
+ Command.new(name, &block)
179
179
  end
180
180
 
181
181
  end#module Usage
@@ -4,19 +4,18 @@ module Clio
4
4
 
5
5
  # = Usage Argument
6
6
  #
7
+ # TODO: Should argument have name in addition to type?
7
8
  class Argument
8
9
  #attr :parent
9
- attr :name
10
+ #attr :name
10
11
  attr :type
11
12
  attr :help
12
13
  attr :splat
13
14
 
14
15
  # New Argument.
15
- #def initialize(name, parent=nil, &block)
16
- def initialize(name, &block)
17
- @name = name.to_s
18
- @type = name.upcase
19
- #@parent = parent
16
+ def initialize(type, &block)
17
+ @type = type
18
+ #@name = type.downcase if type.upcase != type
20
19
  @splat = false
21
20
  @help = ''
22
21
  instance_eval(&block) if block
@@ -24,15 +23,15 @@ module Clio
24
23
 
25
24
  #
26
25
  def initialize_copy(o)
27
- @name = o.name.dup
26
+ #@name = o.name.dup
28
27
  @type = o.type.dup
29
28
  @help = o.help.dup
30
29
  end
31
30
 
32
31
  # Same as +name+ but given as a symbol.
33
- def key
34
- name.to_sym
35
- end
32
+ #def key
33
+ # name.to_sym
34
+ #end
36
35
 
37
36
  # Specify the type of the argument.
38
37
  # This is an arbitrary description of the type.
@@ -47,6 +46,12 @@ module Clio
47
46
  self
48
47
  end
49
48
 
49
+ #def name(string=nil)
50
+ # return @name unless string
51
+ # @name = string.to_s
52
+ # self
53
+ #end
54
+
50
55
  #
51
56
  def splat(true_or_false=nil)
52
57
  return @splat if true_or_false.nil?
@@ -60,20 +65,17 @@ module Clio
60
65
  end
61
66
 
62
67
  def to_s
63
- if name.upcase == type
64
- s = "<#{name}"
65
- else
66
- s = "<#{name}:#{type}"
67
- end
68
+ s = "<#{type}"
68
69
  s << (splat ? "...>" : ">")
69
70
  s
70
71
  end
71
72
 
72
73
  def inspect
73
- s = "<#{name}"
74
- s << ":#{type.inspect}" if type
75
- s << ">"
76
- s
74
+ to_s
75
+ #s = "<#{name}"
76
+ #s << ":#{type.inspect}" if type
77
+ #s << ">"
78
+ #s
77
79
  end
78
80
 
79
81
  end #class Argument
@@ -1,354 +1,75 @@
1
- require 'clio/usage/option'
2
- require 'clio/usage/argument'
1
+ require 'clio/usage/subcommand'
3
2
 
4
3
  module Clio
5
4
 
6
5
  module Usage #:nodoc:
7
6
 
8
- # = Commandline Usage Command
7
+ # = Command
9
8
  #
10
- # This is the heart of usage; subclassed by Main and
11
- # containing together Options and Arguments.
9
+ # This is the toplevel "main" command.
12
10
  #
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
11
+ class Command < Subcommand
125
12
 
126
- alias_method :commands, :subcommands
127
-
128
- # Define an option.
129
- #
130
- # option(:output, :o)
13
+ # New Usage.
131
14
  #
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
15
+ def initialize(name=nil, &block)
16
+ name ||= File.basename($0)
17
+ super(name, &block)
142
18
  end
143
19
 
144
- alias_method :switch, :option
145
-
146
- # Option shorthand.
20
+ # Define a command.
147
21
  #
148
- # opt('--output=FILE -o', 'output directory')
22
+ # command('remote')
23
+ # command('remote','add')
149
24
  #
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}
25
+ #def command(name, &block)
26
+ # raise "Command cannot have both arguments and subcommands (eg. #{name})." unless arguments.empty?
27
+ # key = name.to_s.strip
28
+ # if cmd = @commands.find{|c| c === key}
176
29
  # else
177
- # opt = Option.new(name, self)
178
- # opt.greedy = true
179
- # opt.aliases(*aliases)
180
- # @switches << opt
30
+ # cmd = Command.new(key, self)
31
+ # @commands << cmd
181
32
  # end
182
- # opt.instance_eval(&block) if block
183
- # opt
33
+ # cmd.instance_eval(&block) if block
34
+ # cmd
184
35
  #end
185
36
 
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
37
+ =begin
38
+ #alias_method :[], :command
205
39
 
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
40
 
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
41
+ # ARRAY NOTATION
289
42
  #-------------------------------------------------------------
290
43
 
291
44
  #
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
45
+ def [](*args)
46
+ res = nil
47
+ head, *tail = *args
48
+ case head.to_s
49
+ when /^-/
50
+ x = []
51
+ opts = args.map do |o|
52
+ o = o.to_s
53
+ if i = o.index('=')
54
+ x << o[i+1..-1]
55
+ o[0...i]
56
+ else
57
+ o
58
+ end
59
+ end
60
+ x = x.uniq
342
61
 
343
- # Full callable command name.
344
- def full_name
345
- if parent && parent.full_name
346
- "#{parent.full_name} #{name}"
62
+ res = opt(*opts)
347
63
  else
348
- "#{name}"
64
+ args.each do |name|
65
+ res = command(name)
66
+ end
349
67
  end
68
+ return res
350
69
  end
70
+ =end
351
71
 
72
+ =begin
352
73
  # Usage text.
353
74
  #
354
75
  def to_s
@@ -360,17 +81,17 @@ module Clio
360
81
  when 1, 2, 3
361
82
  s.concat(options.collect{ |o| "[#{o.to_s.strip}]" })
362
83
  else
363
- s << "[switches]" # switches? vs. options
84
+ s << "[switches]"
364
85
  end
365
-
86
+ # switches? vs. options
366
87
  s << arguments.join(' ') unless arguments.empty?
367
88
 
368
- case subcommands.size
89
+ case commands.size
369
90
  when 0
370
91
  when 1
371
- s << subcommands.join('')
92
+ s << commands.join('')
372
93
  when 2, 3
373
- s << '[' + subcommands.join(' | ') + ']'
94
+ s << '[' + commands.join(' | ') + ']'
374
95
  else
375
96
  s << 'command'
376
97
  end
@@ -388,10 +109,10 @@ module Clio
388
109
  end
389
110
  s << "Usage:"
390
111
  s << " " + to_s
391
- unless subcommands.empty?
112
+ unless commands.empty?
392
113
  s << ''
393
114
  s << 'Commands:'
394
- s.concat(subcommands.collect{ |x| " %-20s %s" % [x.name, x.help] }.sort)
115
+ s.concat(commands.collect{ |x| " %-20s %s" % [x.key, x.help] }.sort)
395
116
  end
396
117
  unless arguments.empty?
397
118
  s << ''
@@ -405,36 +126,40 @@ module Clio
405
126
  end
406
127
  s.flatten.join("\n")
407
128
  end
129
+ =end
408
130
 
409
- # PARSE
410
- #-------------------------------------------------------------
131
+ def parse(argv)
132
+ Parser.new(self, argv).parse #(argv)
133
+ end
411
134
 
412
- # Parse usage.
413
- def parse(argv, index=0)
414
- @parser ||= Parser.new(self, argv, index)
415
- @parser.parse
135
+ # Cache usage into a per-user cache file for reuse.
136
+ # This can be used to greatly speed up tab completion.
137
+ #
138
+ def cache
139
+ File.open(cache_file, 'w'){ |f| f << to_yaml }
416
140
  end
417
141
 
418
142
  private
419
143
 
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
144
+ # TODO: Use XDG
145
+
146
+ def cache_file
147
+ File.join(File.expand_path('~'), '.cache', 'clio', "#{name}.yaml")
427
148
  end
428
149
 
429
- def option_name(name)
430
- name = name.to_s
431
- name = name.gsub(/^[-]+/, '')
432
- return name.chomp('?') #.to_sym
150
+ def self.cache_file
151
+ File.join(File.expand_path('~'), '.cache', 'clio', "#{name}.yaml")
152
+ end
153
+
154
+ def self.load_cache
155
+ if File.file?(cache_file)
156
+ YAML.load(File.new(cache_file))
157
+ end
433
158
  end
434
159
 
435
- end #class Command
160
+ end#class Main
436
161
 
437
- end #module Usage
162
+ end#module Usage
438
163
 
439
- end #module Clio
164
+ end#module Clio
440
165