cmdline 0.0.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/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
|
+
|