clio 0.2.0 → 0.3.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.
- data/CHANGES +19 -1
- data/MANIFEST +2 -1
- data/README +5 -6
- data/RELEASE +10 -5
- data/VERSION +1 -1
- data/lib/clio/commandline.rb +2 -9
- data/lib/clio/string.rb +91 -32
- data/lib/clio/usage.rb +2 -2
- data/lib/clio/usage/argument.rb +21 -19
- data/lib/clio/usage/command.rb +76 -351
- data/lib/clio/usage/option.rb +1 -1
- data/lib/clio/usage/subcommand.rb +455 -0
- data/spec/commandline/autousage.rd +0 -2
- data/spec/commandline/bracket.rd +0 -1
- data/spec/commandline/completion.rd +0 -2
- data/spec/commandline/define.rd +0 -1
- data/spec/commandline/method.rd +0 -1
- data/spec/commandline/parse.rd +0 -1
- data/spec/commandline/scenario.rd +0 -1
- data/spec/commandline/subclass.rd +3 -1
- data/spec/string/unit.rd +16 -1
- data/spec/usage/define.rd +85 -17
- data/spec/usage/parse.rd +0 -2
- metadata +4 -4
- data/lib/clio/usage/main.rb +0 -165
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
|
-
*
|
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
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
37
|
+
For now please see the RDoc API.
|
39
38
|
|
40
39
|
|
41
40
|
== LICENSE
|
data/RELEASE
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
|
2
|
-
|
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
|
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.
|
1
|
+
clio 0.3.0 beta (2008-11-19)
|
data/lib/clio/commandline.rb
CHANGED
@@ -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 #
|
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
|
252
|
+
@usage = self.class.usage #|| Usage.new
|
260
253
|
end
|
261
254
|
@usage.instance_eval(&block) if block
|
262
255
|
end
|
data/lib/clio/string.rb
CHANGED
@@ -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.
|
36
|
-
s.insert(index, ANSICode.
|
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
|
-
|
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
|
-
#
|
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
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
|
data/lib/clio/usage.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'clio/usage/
|
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
|
-
|
178
|
+
Command.new(name, &block)
|
179
179
|
end
|
180
180
|
|
181
181
|
end#module Usage
|
data/lib/clio/usage/argument.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
74
|
-
s
|
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
|
data/lib/clio/usage/command.rb
CHANGED
@@ -1,354 +1,75 @@
|
|
1
|
-
require 'clio/usage/
|
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
|
-
# =
|
7
|
+
# = Command
|
9
8
|
#
|
10
|
-
# This is the
|
11
|
-
# containing together Options and Arguments.
|
9
|
+
# This is the toplevel "main" command.
|
12
10
|
#
|
13
|
-
|
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
|
-
|
127
|
-
|
128
|
-
# Define an option.
|
129
|
-
#
|
130
|
-
# option(:output, :o)
|
13
|
+
# New Usage.
|
131
14
|
#
|
132
|
-
def
|
133
|
-
|
134
|
-
|
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
|
-
|
145
|
-
|
146
|
-
# Option shorthand.
|
20
|
+
# Define a command.
|
147
21
|
#
|
148
|
-
#
|
22
|
+
# command('remote')
|
23
|
+
# command('remote','add')
|
149
24
|
#
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
#
|
178
|
-
#
|
179
|
-
# opt.aliases(*aliases)
|
180
|
-
# @switches << opt
|
30
|
+
# cmd = Command.new(key, self)
|
31
|
+
# @commands << cmd
|
181
32
|
# end
|
182
|
-
#
|
183
|
-
#
|
33
|
+
# cmd.instance_eval(&block) if block
|
34
|
+
# cmd
|
184
35
|
#end
|
185
36
|
|
186
|
-
|
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
|
-
|
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
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
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
|
-
|
344
|
-
def full_name
|
345
|
-
if parent && parent.full_name
|
346
|
-
"#{parent.full_name} #{name}"
|
62
|
+
res = opt(*opts)
|
347
63
|
else
|
348
|
-
|
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]"
|
84
|
+
s << "[switches]"
|
364
85
|
end
|
365
|
-
|
86
|
+
# switches? vs. options
|
366
87
|
s << arguments.join(' ') unless arguments.empty?
|
367
88
|
|
368
|
-
case
|
89
|
+
case commands.size
|
369
90
|
when 0
|
370
91
|
when 1
|
371
|
-
s <<
|
92
|
+
s << commands.join('')
|
372
93
|
when 2, 3
|
373
|
-
s << '[' +
|
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
|
112
|
+
unless commands.empty?
|
392
113
|
s << ''
|
393
114
|
s << 'Commands:'
|
394
|
-
s.concat(
|
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
|
-
|
410
|
-
|
131
|
+
def parse(argv)
|
132
|
+
Parser.new(self, argv).parse #(argv)
|
133
|
+
end
|
411
134
|
|
412
|
-
#
|
413
|
-
|
414
|
-
|
415
|
-
|
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
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
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
|
430
|
-
|
431
|
-
|
432
|
-
|
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
|
160
|
+
end#class Main
|
436
161
|
|
437
|
-
end
|
162
|
+
end#module Usage
|
438
163
|
|
439
|
-
end
|
164
|
+
end#module Clio
|
440
165
|
|