cmdline 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CHANGELOG +6 -0
- data/COPYING +728 -0
- data/LICENSE +58 -0
- data/README +242 -0
- data/Rakefile +124 -0
- data/examples/example.rb +9 -0
- data/examples/long_example.rb +34 -0
- data/examples/plain_args_example.rb +10 -0
- data/examples/regexp_example.rb +9 -0
- data/examples/subcommand_example.rb +20 -0
- data/lib/cmdline.rb +251 -0
- metadata +57 -0
data/lib/cmdline.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class CommandLine
|
4
|
+
|
5
|
+
FLAG_1=0
|
6
|
+
FLAG_2=1
|
7
|
+
ACCESSOR=2
|
8
|
+
DISP_NAME=3
|
9
|
+
REQUIRED=4
|
10
|
+
DEFAULT=5
|
11
|
+
DOC=6
|
12
|
+
CHECK=7
|
13
|
+
|
14
|
+
@@add_help=true
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
def self.add_help= bool
|
19
|
+
@@add_help=bool
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
# definition
|
25
|
+
# [ :command, nil, <accessor>, <display name>, <required?>, <default>, <doc>, <check allowed commands> ]
|
26
|
+
# command is a subcommand, cf. `svn help`,
|
27
|
+
# [ <flag1>, <flag2/nil>, <accessor>, <display name>, <required?>, <default>, <doc>, <check: optional> ]
|
28
|
+
#
|
29
|
+
# commandline taking arguments, e.g. `mv src target` are specified like this:
|
30
|
+
# [ :args, nil, <accessor>, <display name>, <required>, <default>, <doc>, <check: optional> ]
|
31
|
+
# the entire rest of the commandline arg array after the first unrecognized options
|
32
|
+
# will then be available under `cmdline.<accessor>` the check proc will either be able to check the entire
|
33
|
+
# array or, if that fails with an exception, will test each element individually.
|
34
|
+
def initialize definition
|
35
|
+
self.definition= definition
|
36
|
+
@output_io ||= STDERR
|
37
|
+
@exit_on_usage=true
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def output= io
|
42
|
+
@output_io = io
|
43
|
+
end
|
44
|
+
|
45
|
+
# whether `exit` will be called to terminate the program if `usage` is
|
46
|
+
# called. Default behaviour is to call `exit`
|
47
|
+
# If this behaviour is turned off, a call to usage will result in an exception
|
48
|
+
# instead.
|
49
|
+
def exit_on_usage= bool
|
50
|
+
@exit_on_usage= bool
|
51
|
+
end
|
52
|
+
|
53
|
+
def definition= definition
|
54
|
+
definition.push(["-h", "--help", :help, false, false, nil, "print this message"]) if @@add_help
|
55
|
+
cl = class << self; self; end
|
56
|
+
# add an accessor to self for each definition.
|
57
|
+
cl.instance_eval { attr_accessor *definition.map{|arg_def| arg_def[ACCESSOR]} }
|
58
|
+
|
59
|
+
|
60
|
+
definition.each {|arg_def|
|
61
|
+
#check if cmdline takes a command
|
62
|
+
if arg_def[FLAG_1]==:command
|
63
|
+
@has_command = true
|
64
|
+
end
|
65
|
+
#set default values
|
66
|
+
set arg_def[ACCESSOR], arg_def[DEFAULT]
|
67
|
+
}
|
68
|
+
|
69
|
+
@definition=definition
|
70
|
+
|
71
|
+
class << @definition
|
72
|
+
def retrieve_flag flag
|
73
|
+
find { |arg|
|
74
|
+
arg[FLAG_1]==flag || arg[FLAG_2]==flag
|
75
|
+
}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end # definition
|
80
|
+
|
81
|
+
def usage mes=""
|
82
|
+
raise mes unless @exit_on_usage
|
83
|
+
|
84
|
+
|
85
|
+
# put together usage information for flags.
|
86
|
+
max = 0 #max flag length for formatting
|
87
|
+
has_required=false
|
88
|
+
has_options=false
|
89
|
+
us = @definition.map {|arg_def|
|
90
|
+
if arg_def[FLAG_1] == :command
|
91
|
+
flag=:command
|
92
|
+
elsif arg_def[FLAG_1] == :args
|
93
|
+
flag=:args
|
94
|
+
else
|
95
|
+
# create a usage string of the form:
|
96
|
+
# -f/-flag <value>* must start with a number
|
97
|
+
# for each definition. (commands and args are treated seperately)
|
98
|
+
flag = "#{arg_def[FLAG_1]}"
|
99
|
+
flag << "/#{arg_def[FLAG_2]}" if arg_def[FLAG_2]
|
100
|
+
flag << " <#{arg_def[DISP_NAME]}>" if arg_def[DISP_NAME]
|
101
|
+
flag << "*" if arg_def[REQUIRED]
|
102
|
+
has_required = true if arg_def[REQUIRED]
|
103
|
+
has_options = true
|
104
|
+
max = max > flag.length ? max : flag.length
|
105
|
+
end
|
106
|
+
[flag, arg_def[DOC]]
|
107
|
+
}
|
108
|
+
|
109
|
+
usage = "usage: #{$0}"
|
110
|
+
|
111
|
+
if command=@definition.retrieve_flag(:command)
|
112
|
+
fmt = command[REQUIRED] ? " %s" : " [%s]"
|
113
|
+
usage << sprintf(fmt,command[DISP_NAME])
|
114
|
+
end
|
115
|
+
|
116
|
+
if has_options
|
117
|
+
usage << (has_required ? " options" : " [options]")
|
118
|
+
end
|
119
|
+
|
120
|
+
args_doc=false
|
121
|
+
if command=@definition.retrieve_flag(:args)
|
122
|
+
fmt = command[REQUIRED] ? " %s" : " [%s]"
|
123
|
+
usage << sprintf(fmt,command[DISP_NAME])
|
124
|
+
args_doc = "#{command[DISP_NAME]}: #{command[DOC]}"
|
125
|
+
end
|
126
|
+
usage << "\n"
|
127
|
+
|
128
|
+
us.each { |arg_def|
|
129
|
+
if arg_def[0].kind_of? String
|
130
|
+
usage << sprintf(" %-#{max}s %s\n", arg_def[0], arg_def[1])
|
131
|
+
elsif arg_def[0] == :command
|
132
|
+
# command
|
133
|
+
usage << arg_def[1] if arg_def[1]
|
134
|
+
end
|
135
|
+
|
136
|
+
}
|
137
|
+
@output_io.puts usage
|
138
|
+
@output_io.puts "* required flags" if has_required
|
139
|
+
@output_io.puts "\n#{args_doc}" if args_doc
|
140
|
+
@output_io.puts
|
141
|
+
@output_io.puts mes
|
142
|
+
exit
|
143
|
+
end
|
144
|
+
|
145
|
+
def parse args=ARGV
|
146
|
+
@found = []
|
147
|
+
i=0
|
148
|
+
# handle svn like command
|
149
|
+
if definition = @definition.retrieve_flag(:command)
|
150
|
+
|
151
|
+
if definition[REQUIRED] && args.length==0
|
152
|
+
usage "missing mandatory command"
|
153
|
+
elsif test_def = @definition.retrieve_flag(args[i])
|
154
|
+
usage "missing mandatory command" if definition[REQUIRED]
|
155
|
+
else
|
156
|
+
|
157
|
+
check definition, args[i]
|
158
|
+
set definition[ACCESSOR], args[i]
|
159
|
+
|
160
|
+
i+=1
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
while i<args.length do
|
166
|
+
@found.push args[i]
|
167
|
+
if definition = @definition.retrieve_flag(args[i]) # is there a definition for this flag?
|
168
|
+
if definition[DISP_NAME]
|
169
|
+
# takes a parameter
|
170
|
+
check definition, args[i+=1]
|
171
|
+
set definition[ACCESSOR], args[i]
|
172
|
+
else
|
173
|
+
# plain flag
|
174
|
+
set definition[ACCESSOR], true
|
175
|
+
end
|
176
|
+
else # are unknown flags ok? i.e. is there an :args definition.
|
177
|
+
if definition = @definition.retrieve_flag(:args)
|
178
|
+
check_args definition, args[i, args.length-1]
|
179
|
+
set definition[ACCESSOR], args[i, args.length-1]
|
180
|
+
break
|
181
|
+
end
|
182
|
+
usage "unknown flag: #{args[i]}"
|
183
|
+
end
|
184
|
+
i+=1
|
185
|
+
end
|
186
|
+
|
187
|
+
if definition = @definition.retrieve_flag(:args) # are :args required?
|
188
|
+
if definition[REQUIRED]
|
189
|
+
args = self.send definition[ACCESSOR]
|
190
|
+
usage "missing mandatory args" unless args && args.length>1
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
usage if self.help # call usage if the -h/--help flag was set.
|
195
|
+
|
196
|
+
# check all mandatory args are present.
|
197
|
+
@definition.each {|definition|
|
198
|
+
|
199
|
+
if definition[REQUIRED] && !([:command, :args].include? definition[FLAG_1])
|
200
|
+
usage "missing mandatory flag #{definition [FLAG_1]?definition[FLAG_1]:definition[FLAG_2]}" unless ((@found.include? definition[FLAG_1]) || (@found.include? definition[FLAG_2]))
|
201
|
+
end
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
|
207
|
+
def set sym, value
|
208
|
+
self.send((sym.to_s+"=").to_sym, value)
|
209
|
+
end
|
210
|
+
|
211
|
+
#
|
212
|
+
# check the argument's value against allowed values,
|
213
|
+
# check may be a Regexp, an Array or a Proc taking the value.
|
214
|
+
#
|
215
|
+
def check definition, val
|
216
|
+
check=definition[CHECK]
|
217
|
+
return true unless check
|
218
|
+
if check.kind_of? Regexp
|
219
|
+
if !check.match val
|
220
|
+
usage "illegal value: #{val} for: #{definition[FLAG_1]}"
|
221
|
+
end
|
222
|
+
elsif check.kind_of? Proc
|
223
|
+
usage "illegal value: #{val} for: #{definition[FLAG1]}" unless definition[CHECK].call val
|
224
|
+
elsif check.kind_of? Array
|
225
|
+
usage "illegal value: #{val} for: #{definition[FLAG1]}" unless definition[CHECK].include? val
|
226
|
+
end
|
227
|
+
|
228
|
+
return true
|
229
|
+
end
|
230
|
+
|
231
|
+
def check_args definition, arr
|
232
|
+
ret = false
|
233
|
+
# might be a proc to check the entire array
|
234
|
+
if definition[CHECK].kind_of? Proc
|
235
|
+
begin
|
236
|
+
return definition[CHECK].call(arr)
|
237
|
+
rescue
|
238
|
+
end
|
239
|
+
end
|
240
|
+
# or something else to check each arg against
|
241
|
+
unless ret
|
242
|
+
arr.each {|val|
|
243
|
+
ret= check definition, val
|
244
|
+
return false unless ret
|
245
|
+
}
|
246
|
+
end
|
247
|
+
return ret
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: cmdline
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.0
|
7
|
+
date: 2007-05-10 00:00:00 +02:00
|
8
|
+
summary: "cmdline: Yet Another Command Line Tool"
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email:
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: Library used to handle command line arguments.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- lib/cmdline.rb
|
33
|
+
- examples/example.rb
|
34
|
+
- examples/long_example.rb
|
35
|
+
- examples/plain_args_example.rb
|
36
|
+
- examples/regexp_example.rb
|
37
|
+
- examples/subcommand_example.rb
|
38
|
+
- AUTHORS
|
39
|
+
- CHANGELOG
|
40
|
+
- COPYING
|
41
|
+
- LICENSE
|
42
|
+
- Rakefile
|
43
|
+
- README
|
44
|
+
test_files: []
|
45
|
+
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
extra_rdoc_files: []
|
49
|
+
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
requirements:
|
55
|
+
- none
|
56
|
+
dependencies: []
|
57
|
+
|