parseOpts 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -0
- data/LICENSE +19 -0
- data/README +65 -0
- data/Rakefile +40 -0
- data/lib/parseOpts.rb +287 -0
- data/test/test_parseOpts.rb +271 -0
- metadata +58 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009 Jon Coppeard
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
=parseOpts
|
2
|
+
|
3
|
+
parseOpts is (yes, another) ruby library for parsing commandline options and arguments.
|
4
|
+
|
5
|
+
It has the following features:
|
6
|
+
|
7
|
+
- parses options (switches) as well as arguments
|
8
|
+
- options and arguments are specified in an easy to read, declarative format
|
9
|
+
- automatically generates a usage message if incorrect arguments are given
|
10
|
+
- it is small (currently < 300 lines of code)
|
11
|
+
|
12
|
+
==Description
|
13
|
+
|
14
|
+
A specification written in ruby describes the allowable command line inputs.
|
15
|
+
|
16
|
+
Individual command line parameters are divided into options and arguments.
|
17
|
+
|
18
|
+
Options are command line switches, and start with at least one '-' character. They can occur in any
|
19
|
+
order, and may or may not take an argument. They may occur multiple times if allowed.
|
20
|
+
|
21
|
+
Arguments are parameters that may be constrained, either as a choice of options from a list, or by a
|
22
|
+
regular expression. It is possible to specificy how often an argument can occur.
|
23
|
+
|
24
|
+
All options are parsed befor any arguments. All mandatory options and arguments must be present in
|
25
|
+
the command line otherwise parsing fails.
|
26
|
+
|
27
|
+
==Usage
|
28
|
+
|
29
|
+
For a simple example, see the following (from examples/example_grep.rb):
|
30
|
+
|
31
|
+
require "parseOpts"
|
32
|
+
|
33
|
+
opts = ParseOpts.run do
|
34
|
+
opt '-v|--invert-match', 'Select non-matching lines'
|
35
|
+
opt '-m|--max-count NUM', 'Stop reading a file after NUM matches'
|
36
|
+
arg 'pattern', 'Regular expression to match'
|
37
|
+
arg 'file+', 'File to search in'
|
38
|
+
end
|
39
|
+
|
40
|
+
$invert_match = opts['-v']
|
41
|
+
$max_count = opts['-m'] ? opts['-m'].to_i : nil
|
42
|
+
$pattern = Regexp.new(opts['pattern'])
|
43
|
+
$files = opts['file']
|
44
|
+
|
45
|
+
Running the script with no arguments generates the following usage message:
|
46
|
+
|
47
|
+
usage: example_grep.rb options* pattern file+
|
48
|
+
|
49
|
+
Options:
|
50
|
+
-v, --invert-match: Select non-matching lines
|
51
|
+
-m, --max-count NUM: Stop reading a file after NUM matches
|
52
|
+
|
53
|
+
Arguments:
|
54
|
+
pattern: Regular expression to match
|
55
|
+
file: File to search in
|
56
|
+
|
57
|
+
==Ideas for future work
|
58
|
+
|
59
|
+
- define classes for commonly used types to parse argument strings (eg integer, float, etc)
|
60
|
+
- format help so lines wrap nicely
|
61
|
+
- allow sets of arguments and options in any order (allows subcommands)
|
62
|
+
|
63
|
+
==Contact
|
64
|
+
|
65
|
+
Please contact jon at coppeard dot net with bug reports and suggestions.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require './lib/parseOpts'
|
6
|
+
|
7
|
+
source_files = Dir['lib/*.rb'] + Dir['test/*.rb'] + [ 'Rakefile' ]
|
8
|
+
package_files = %w[README CHANGELOG LICENSE] + source_files
|
9
|
+
|
10
|
+
Rake::TestTask.new :test do |t|
|
11
|
+
t.test_files = [ "test/test*" ]
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Build documentation"
|
15
|
+
task :rdoc => source_files
|
16
|
+
Rake::RDocTask.new( :rdoc ) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = "api"
|
18
|
+
rdoc.title = "parseOpts - a library to parse commandline options and arguments"
|
19
|
+
rdoc.option_string << '--line-numbers --inline-source --main README'
|
20
|
+
rdoc.rdoc_files.include 'README'
|
21
|
+
rdoc.rdoc_files.include 'lib/parseOpts.rb'
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Build the gem"
|
25
|
+
task :gem => package_files
|
26
|
+
spec = Gem::Specification.new do |spec|
|
27
|
+
spec.name = 'parseOpts'
|
28
|
+
spec.version = ParseOpts::VERSION
|
29
|
+
spec.summary = "Library to parse commandline options and arguments"
|
30
|
+
spec.description = ""
|
31
|
+
spec.author = "Jon Coppeard"
|
32
|
+
spec.email = "jon at coppeard dot net"
|
33
|
+
spec.files = package_files
|
34
|
+
spec.has_rdoc = true
|
35
|
+
spec.test_file = 'test/test_parseOpts.rb'
|
36
|
+
spec.rubyforge_project = 'parseOpts'
|
37
|
+
end
|
38
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
39
|
+
pkg.need_tar = true
|
40
|
+
end
|
data/lib/parseOpts.rb
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
# parseOpts parses commandline options and arguments.
|
2
|
+
#
|
3
|
+
# For more information, please see the {README}[link:files/README.html]
|
4
|
+
class ParseOpts
|
5
|
+
|
6
|
+
VERSION = "0.0.2"
|
7
|
+
|
8
|
+
class OptSpec # :nodoc: all
|
9
|
+
|
10
|
+
attr_reader :matches, :arg, :default, :desc, :multiple
|
11
|
+
|
12
|
+
def initialize(matches, arg, desc, multiple, default)
|
13
|
+
raise ArgumentError, "Options must start with -" unless matches.all? {|m| m =~ /^-/ }
|
14
|
+
raise ArgumentError, 'Default not allowed unless argument is present' if default && !arg
|
15
|
+
@matches, @arg, @desc, @multiple, @default =
|
16
|
+
matches, arg, desc, multiple, default
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
@matches[0]
|
21
|
+
end
|
22
|
+
|
23
|
+
def init
|
24
|
+
@matched = false
|
25
|
+
@value = if @multiple
|
26
|
+
@arg ? [] : 0
|
27
|
+
else
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def match?(args)
|
33
|
+
(!@matched || @multiple) && (@matches.include?(args[0])) && (!@arg || args.size >= 2)
|
34
|
+
end
|
35
|
+
|
36
|
+
def process(args)
|
37
|
+
args.shift
|
38
|
+
r = @arg ? args.shift : true
|
39
|
+
if @multiple && @arg
|
40
|
+
@value << r
|
41
|
+
elsif @multiple
|
42
|
+
@value += 1
|
43
|
+
else
|
44
|
+
@value = r
|
45
|
+
end
|
46
|
+
@matched = true
|
47
|
+
end
|
48
|
+
|
49
|
+
def value
|
50
|
+
!@matched && @default ? @default : @value
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class ArgSpec # :nodoc: all
|
56
|
+
|
57
|
+
QuantOptions =
|
58
|
+
{
|
59
|
+
"" => [ false, false ],
|
60
|
+
"?" => [ true, false ],
|
61
|
+
"*" => [ true, true ],
|
62
|
+
"+" => [ false, true ]
|
63
|
+
}
|
64
|
+
|
65
|
+
attr_reader :name, :desc, :multiple, :optional, :quant, :default
|
66
|
+
|
67
|
+
def initialize(name, quant, desc, pred, default)
|
68
|
+
@name, @quant, @desc, @pred, @default = name, quant, desc, pred, default
|
69
|
+
raise ArgumentError, "Unknown quantifier" unless QuantOptions.has_key?(quant)
|
70
|
+
@optional, @multiple = *QuantOptions[quant]
|
71
|
+
raise ArgumentError, "Default not allowed for mandatory argument" if @default && !@optional
|
72
|
+
end
|
73
|
+
|
74
|
+
def init
|
75
|
+
@value = @multiple ? [] : nil
|
76
|
+
@matched = false
|
77
|
+
end
|
78
|
+
|
79
|
+
def match?(args)
|
80
|
+
@pred ? @pred.call(args[0]) : true
|
81
|
+
end
|
82
|
+
|
83
|
+
def process(args)
|
84
|
+
@value = if @multiple
|
85
|
+
a = [args.shift]
|
86
|
+
a << args.shift while args.size > 0 && match?(args)
|
87
|
+
a
|
88
|
+
else
|
89
|
+
args.shift
|
90
|
+
end
|
91
|
+
@matched = true
|
92
|
+
end
|
93
|
+
|
94
|
+
def value
|
95
|
+
@default && !@matched ? @default : @value
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
# An exception raised by ParseOpts::parse when the command line arguments don't conform to the
|
101
|
+
# specification.
|
102
|
+
class BadUsageError < Exception; end
|
103
|
+
|
104
|
+
# Create a new object that parses the command line specified by the given block.
|
105
|
+
#
|
106
|
+
# The block is evaluated in the context of the new object instance and should call its summary,
|
107
|
+
# opt and arg methods.
|
108
|
+
def initialize (&block)
|
109
|
+
@summary = nil
|
110
|
+
@optList, @argList = [], []
|
111
|
+
instance_eval(&block)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Set the summary text that is output in the usage message.
|
115
|
+
def summary(string)
|
116
|
+
@summary = string
|
117
|
+
end
|
118
|
+
|
119
|
+
# Add an option.
|
120
|
+
#
|
121
|
+
# [spec] A string specifying the option name and alternatives, and whether the option can take an
|
122
|
+
# argument. Alternatives are specified by listing them separated by a '|' character and
|
123
|
+
# an argument is specified by following that with a space and the argument name.
|
124
|
+
#
|
125
|
+
# The first word of the specification is the name, and is used as the hash key to return
|
126
|
+
# its value.
|
127
|
+
#
|
128
|
+
# For example: <tt>"-l|--long-name argName"</tt> will recognise both <tt>-l</tt> and
|
129
|
+
# <tt>--long-name</tt>, and will take an argument. The key used for the result hash is
|
130
|
+
# "-l".
|
131
|
+
#
|
132
|
+
# [desc] Human readable description of the option.
|
133
|
+
# [params] An optional hash of additional parameters.
|
134
|
+
#
|
135
|
+
# Allowed additonal parameters are:
|
136
|
+
# [:multiple] Indicates that this option is allowed to occur more than once. In this case the
|
137
|
+
# value returned for this option will be an array.
|
138
|
+
# [:default] The default value if this option is not passed. Only allowed when the option takes
|
139
|
+
# an argument
|
140
|
+
def opt(spec, desc, params = {})
|
141
|
+
words = spec.split(/ /)
|
142
|
+
raise "Bad format for option spec '#{spec}'" unless words.size <= 2
|
143
|
+
arg = words[1]
|
144
|
+
matches = words[0].split(/\|/)
|
145
|
+
default = params.delete(:default)
|
146
|
+
multiple = params.delete(:multiple)
|
147
|
+
raise ArgumentError, "Unknown keyword arguments passed: #{params.keys.join(", ")}" unless
|
148
|
+
params.size == 0
|
149
|
+
@optList << OptSpec.new(matches, arg, desc, multiple, default)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Add an argument.
|
153
|
+
#
|
154
|
+
# [spec] The name of the argument, possibly followed by a quantifier. The name itself is used
|
155
|
+
# as the hash key to return the argument's value(s)
|
156
|
+
# [desc] Human readable description of the argument.
|
157
|
+
# [params] An optional hash of additional parameters.
|
158
|
+
#
|
159
|
+
# Possible argument quantifiers are:
|
160
|
+
# [?] Indicates that this argument may occur zero or once only
|
161
|
+
# [*] Indicates that this argument may occur zero or more times
|
162
|
+
# [+] Indicates that this argument may occur one or more times
|
163
|
+
#
|
164
|
+
# If no quantifier is given, the argument must occur exactly once. If an argument can occur more
|
165
|
+
# than once, the value returned for it will be an array of the values passed.
|
166
|
+
#
|
167
|
+
# Allowed keyword arguments are:
|
168
|
+
# [:choice] An array contating the allowed values of this argument.
|
169
|
+
#
|
170
|
+
# [:match] An object constraining the values of this argument. The matching is done with ruby's
|
171
|
+
# <tt>===</tt> operator, so any object that supports this will work - e.g. a regular
|
172
|
+
# expression.
|
173
|
+
# [:default] A default value if the argument is not present.
|
174
|
+
def arg(spec, desc, params = {})
|
175
|
+
name = spec.sub(/(\?|\*|\+)$/, "")
|
176
|
+
quant = $1 || ""
|
177
|
+
pred = if params.has_key?(:choice)
|
178
|
+
choices = params.delete(:choice)
|
179
|
+
desc += "\n One of: " + choices.join(' ')
|
180
|
+
lambda {|x| choices.include?(x) }
|
181
|
+
elsif params.has_key?(:match)
|
182
|
+
match = params.delete(:match)
|
183
|
+
lambda {|x| match === x }
|
184
|
+
else
|
185
|
+
nil
|
186
|
+
end
|
187
|
+
default = params.delete(:default)
|
188
|
+
raise ArgumentError, "Unknown keyword arguments passed: #{params.keys.join(", ")}" unless
|
189
|
+
params.size == 0
|
190
|
+
@argList << ArgSpec.new(name, quant, desc, pred, default)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Parse the command line arguments given and return a hash where the keys are the names of the
|
194
|
+
# options and arguments and the values are those that have been extracted from the command line.
|
195
|
+
#
|
196
|
+
# Options are parsed first, and may be present in any order. Option parsing stops when there are
|
197
|
+
# no more optons, or if <tt>"--"</tt> is encountered.
|
198
|
+
#
|
199
|
+
# The remaining input is parsed as arguments.
|
200
|
+
#
|
201
|
+
# This method raised BadUsageError if the parameters do not conform to the specification given
|
202
|
+
# when the object was created.
|
203
|
+
def parse(args)
|
204
|
+
allSpecs = @optList + @argList
|
205
|
+
allSpecs.each {|spec| spec.init }
|
206
|
+
parse_next_opt(args) while args.size > 0 && args[0] =~ /^-/ && args[0] != '--'
|
207
|
+
args.shift if args[0] == '--'
|
208
|
+
@argPos = 0
|
209
|
+
while args.size > 0 && @argPos < @argList.size do
|
210
|
+
parse_next_arg(@argList[@argPos], args)
|
211
|
+
@argPos += 1
|
212
|
+
end
|
213
|
+
raise BadUsageError if args.size > 0 || @argList[@argPos..-1].find {|s| !s.optional }
|
214
|
+
result = {}
|
215
|
+
allSpecs.each {|spec| result[spec.name] = spec.value if spec.value}
|
216
|
+
return result
|
217
|
+
end
|
218
|
+
|
219
|
+
# Generate a usage message explaining the allowed syntax of the command line.
|
220
|
+
def usage_message
|
221
|
+
name = $0 =~ /[^\/]+$/ ? $& : ''
|
222
|
+
usageArgs = @argList.collect{|s| s.name + s.quant }
|
223
|
+
usageArgs.unshift('options*') if @optList.size > 0
|
224
|
+
usageArgs.unshift(name)
|
225
|
+
|
226
|
+
lines = [ "usage: " + usageArgs.join(' ') ]
|
227
|
+
lines += [ "", @summary ] if @summary
|
228
|
+
|
229
|
+
if @optList.size > 0
|
230
|
+
lines += [ "", "Options:" ] + @optList.map do |opt|
|
231
|
+
line = " " + opt.matches.join(", ")
|
232
|
+
line += " " + opt.arg if opt.arg
|
233
|
+
line += ": " + opt.desc
|
234
|
+
if opt.default
|
235
|
+
d = opt.default
|
236
|
+
d = d.kind_of?(Array) ? d.join(' ') : d.to_s
|
237
|
+
line += "\n Default: " + d
|
238
|
+
end
|
239
|
+
line
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
if @argList.size > 0
|
244
|
+
lines += [ "", "Arguments:" ] + @argList.map do |arg|
|
245
|
+
line = " " + arg.name + ": " + arg.desc
|
246
|
+
if arg.default
|
247
|
+
d = arg.default
|
248
|
+
d = d.kind_of?(Array) ? d.join(' ') : d.to_s
|
249
|
+
line += "\n Default: " + d
|
250
|
+
end
|
251
|
+
line
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
lines.join("\n")
|
256
|
+
end
|
257
|
+
|
258
|
+
# Convenience method to construct an parser object as specified by a block and call its parse
|
259
|
+
# method with the argument array given, or ARGV if it is ommitted.
|
260
|
+
#
|
261
|
+
# If parsing fails, the usage message is displayed on stderr and exit is called.
|
262
|
+
def ParseOpts.run (args = ARGV, &block)
|
263
|
+
parser = ParseOpts.new(&block)
|
264
|
+
begin
|
265
|
+
parser.parse(args)
|
266
|
+
rescue BadUsageError
|
267
|
+
$stderr.puts parser.usage_message
|
268
|
+
exit(1)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
private
|
273
|
+
|
274
|
+
def parse_next_opt(args)
|
275
|
+
optSpec = @optList.find {|s| s.match? args } or raise BadUsageError, args[0]
|
276
|
+
optSpec.process(args)
|
277
|
+
end
|
278
|
+
|
279
|
+
def parse_next_arg(argSpec, args)
|
280
|
+
if !argSpec.match? args
|
281
|
+
raise BadUsageError unless argSpec.optional
|
282
|
+
else
|
283
|
+
argSpec.process(args)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
@@ -0,0 +1,271 @@
|
|
1
|
+
#!/bin/ruby
|
2
|
+
|
3
|
+
require 'runit/testcase'
|
4
|
+
require 'runit/cui/testrunner'
|
5
|
+
require 'runit/testsuite'
|
6
|
+
require 'parseOpts'
|
7
|
+
|
8
|
+
class ParseOptsTests < RUNIT::TestCase
|
9
|
+
|
10
|
+
def words(string)
|
11
|
+
string.split /\s+/
|
12
|
+
end
|
13
|
+
|
14
|
+
def assert_ok(expected, string)
|
15
|
+
assert_no_exception do
|
16
|
+
assert_equal(expected, @parser.parse(words(string)))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def assert_bad(string)
|
21
|
+
assert_exception(ParseOpts::BadUsageError) { @parser.parse(words(string)) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_empty
|
25
|
+
@parser = ParseOpts.new {}
|
26
|
+
assert_ok({}, '')
|
27
|
+
assert_bad('-x')
|
28
|
+
assert_bad('x')
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_singleOption
|
32
|
+
@parser = ParseOpts.new do
|
33
|
+
opt '-t', 'test'
|
34
|
+
end
|
35
|
+
assert_ok({}, '')
|
36
|
+
assert_ok({'-t' => true}, '-t')
|
37
|
+
assert_bad('-t bar')
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_optionWithArg
|
41
|
+
@parser = ParseOpts.new do
|
42
|
+
opt '-t FOO', 'test'
|
43
|
+
end
|
44
|
+
assert_ok({}, '')
|
45
|
+
assert_ok({'-t' => 'bar'}, '-t bar')
|
46
|
+
assert_bad('-t')
|
47
|
+
assert_bad('-t bar baz')
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_multipleSingleOption
|
51
|
+
@parser = ParseOpts.new do
|
52
|
+
opt '-t', 'test', :multiple => true
|
53
|
+
end
|
54
|
+
assert_ok({'-t' => 0}, '')
|
55
|
+
assert_ok({'-t' => 1}, '-t')
|
56
|
+
assert_ok({'-t' => 2}, '-t -t')
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_multipleOptionWithArg
|
60
|
+
@parser = ParseOpts.new do
|
61
|
+
opt '-t FOO', 'test', :multiple => true
|
62
|
+
end
|
63
|
+
assert_ok({'-t' => []}, '')
|
64
|
+
assert_ok({'-t' => ['bar']}, '-t bar')
|
65
|
+
assert_ok({'-t' => ['bar', 'baz']}, '-t bar -t baz')
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_altOptions
|
69
|
+
@parser = ParseOpts.new do
|
70
|
+
opt '-a|--aaa', 'test'
|
71
|
+
opt '-b|--bbb|--whatever FOO', 'test'
|
72
|
+
end
|
73
|
+
assert_ok({'-a' => true}, '-a')
|
74
|
+
assert_ok({'-a' => true}, '--aaa')
|
75
|
+
assert_ok({'-b' => 'bar'}, '-b bar')
|
76
|
+
assert_ok({'-b' => 'bar'}, '--bbb bar')
|
77
|
+
assert_ok({'-b' => 'baz'}, '--whatever baz')
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_combinationsOfOptions
|
81
|
+
@parser = ParseOpts.new do
|
82
|
+
opt '-a', 'test'
|
83
|
+
opt '-b ARG', 'test'
|
84
|
+
opt '-c', 'test', :multiple => true
|
85
|
+
opt '-d ARG', 'test', :multiple => true
|
86
|
+
end
|
87
|
+
assert_ok({'-a' => true, '-c' => 0, '-d' => []}, '-a')
|
88
|
+
assert_ok({'-b' => 'foo', '-c' => 0, '-d' => []}, '-b foo')
|
89
|
+
assert_ok({'-c' => 2, '-d' => []}, '-c -c')
|
90
|
+
assert_ok({'-c' => 0, '-d' => ['bar', 'baz']}, '-d bar -d baz')
|
91
|
+
|
92
|
+
expected = {'-a' => true, '-b' => 'foo', '-c' => 2, '-d' => ['bar', 'baz']}
|
93
|
+
assert_ok(expected, '-a -b foo -c -c -d bar -d baz')
|
94
|
+
assert_ok(expected, '-b foo -a -c -c -d bar -d baz')
|
95
|
+
assert_ok(expected, '-c -b foo -a -c -d bar -d baz')
|
96
|
+
assert_ok(expected, '-d bar -c -b foo -a -c -d baz')
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_optionsWithDefaultArgs
|
100
|
+
@parser = ParseOpts.new do
|
101
|
+
opt '-b ARG', 'test', :default => 'def'
|
102
|
+
opt '-d ARG', 'test', :multiple => true, :default => ['foo']
|
103
|
+
end
|
104
|
+
|
105
|
+
assert_ok({'-b' => 'def', '-d' => ['foo']}, '')
|
106
|
+
assert_ok({'-b' => 'bar', '-d' => ['baz']}, '-b bar -d baz')
|
107
|
+
|
108
|
+
assert_exception(ArgumentError) { ParseOpts.new { opt '-a', '', :default => 'foo' } }
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_optionsWithDefaultArgs2
|
112
|
+
@parser = ParseOpts.new do
|
113
|
+
opt '-b ARG', 'test', :default => 13
|
114
|
+
opt '-d ARG', 'test', :multiple => true, :default => [17]
|
115
|
+
end
|
116
|
+
|
117
|
+
assert_ok({'-b' => 13, '-d' => [17]}, '')
|
118
|
+
assert_ok({'-b' => 'bar', '-d' => ['baz']}, '-b bar -d baz')
|
119
|
+
|
120
|
+
assert_exception(ArgumentError) { ParseOpts.new { opt '-a', '', :default => 'foo' } }
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_argRequired
|
124
|
+
@parser = ParseOpts.new do
|
125
|
+
arg 'arg', 'test'
|
126
|
+
end
|
127
|
+
assert_bad('')
|
128
|
+
assert_ok({'arg' => 'foo'}, 'foo')
|
129
|
+
assert_bad('foo bar')
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_argOptional
|
133
|
+
@parser = ParseOpts.new do
|
134
|
+
arg 'arg?', 'test'
|
135
|
+
end
|
136
|
+
assert_ok({}, '')
|
137
|
+
assert_ok({'arg' => 'foo'}, 'foo')
|
138
|
+
assert_bad('foo bar')
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_argZeroOrMore
|
142
|
+
@parser = ParseOpts.new do
|
143
|
+
arg 'arg*', 'test'
|
144
|
+
end
|
145
|
+
assert_ok({'arg' => []}, '')
|
146
|
+
assert_ok({'arg' => ['foo']}, 'foo')
|
147
|
+
assert_ok({'arg' => ['foo', 'bar']}, 'foo bar')
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_argOneOrMore
|
151
|
+
@parser = ParseOpts.new do
|
152
|
+
arg 'arg+', 'test'
|
153
|
+
end
|
154
|
+
assert_bad('')
|
155
|
+
assert_ok({'arg' => ['foo']}, 'foo')
|
156
|
+
assert_ok({'arg' => ['foo', 'bar']}, 'foo bar')
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_argRegexpMatch
|
160
|
+
@parser = ParseOpts.new do
|
161
|
+
arg 'arg', 'test', :match => /^\w-\d$/
|
162
|
+
end
|
163
|
+
assert_ok({'arg' => 'k-9'}, 'k-9')
|
164
|
+
assert_bad('foo')
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_argArrayChoice
|
168
|
+
@parser = ParseOpts.new do
|
169
|
+
arg 'arg', 'test', :choice => ['foo', 'bar']
|
170
|
+
end
|
171
|
+
assert_ok({'arg' => 'bar'}, 'bar')
|
172
|
+
assert_bad('baz')
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_argsWithDefaults
|
176
|
+
@parser = ParseOpts.new do
|
177
|
+
arg 'a?', 'test', :default => 'foo'
|
178
|
+
end
|
179
|
+
|
180
|
+
assert_ok({'a' => 'foo'}, '')
|
181
|
+
assert_ok({'a' => 'bar'}, 'bar')
|
182
|
+
|
183
|
+
@parser = ParseOpts.new do
|
184
|
+
arg 'a*', 'test', :default => ['bar']
|
185
|
+
end
|
186
|
+
|
187
|
+
assert_ok({'a' => ['bar']}, '')
|
188
|
+
assert_ok({'a' => ['foo']}, 'foo')
|
189
|
+
|
190
|
+
assert_exception(ArgumentError) { ParseOpts.new { arg 'a', '', :default => 'foo' } }
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_combinationsOfArgs
|
194
|
+
@parser = ParseOpts.new do
|
195
|
+
arg 'a', 'test', :match => /^a$/
|
196
|
+
arg 'b?', 'test', :match => /^b$/
|
197
|
+
arg 'c*', 'test', :match => /^c$/
|
198
|
+
arg 'd+', 'test', :match => /^d$/
|
199
|
+
end
|
200
|
+
|
201
|
+
assert_ok({'a' => 'a', 'b' => 'b', 'c' => ['c'], 'd' => ['d']},
|
202
|
+
'a b c d')
|
203
|
+
assert_ok({'a' => 'a', 'c' => [], 'd' => ['d']},
|
204
|
+
'a d')
|
205
|
+
assert_ok({'a' => 'a', 'b' => 'b', 'c' => ['c', 'c'], 'd' => ['d', 'd']},
|
206
|
+
'a b c c d d')
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_optionsAndArgs
|
210
|
+
@parser = ParseOpts.new do
|
211
|
+
opt '-a', 'test opt a'
|
212
|
+
opt '-b ARG', 'test opt b'
|
213
|
+
opt '-c', 'test opt c', :multiple => true
|
214
|
+
opt '-d ARG', 'test opt d', :multiple => true
|
215
|
+
arg 'e', 'test arg e', :match => /^e$/
|
216
|
+
arg 'f?', 'test arg f', :match => /^f$/
|
217
|
+
arg 'g*', 'test arg g', :match => /^g$/
|
218
|
+
arg 'h+', 'test arg h', :match => /^h$/
|
219
|
+
end
|
220
|
+
|
221
|
+
assert_ok({'-a' => true, '-b' => 'foo', '-c' => 2, '-d' => ['bar', 'baz'],
|
222
|
+
'e' => 'e', 'f' => 'f', 'g' => ['g'], 'h' => ['h']},
|
223
|
+
'-a -b foo -c -c -d bar -d baz e f g h')
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_usageMessage
|
227
|
+
@parser = ParseOpts.new do
|
228
|
+
opt '-a', 'test opt a'
|
229
|
+
opt '-b ARG', 'test opt b', :default => "xxx"
|
230
|
+
opt '-c|--cc', 'test opt c', :multiple => true
|
231
|
+
opt '-d|--dd ARG', 'test opt d', :multiple => true, :default => ["yyy", "zzz"]
|
232
|
+
arg 'e', 'test arg e', :match => /^e$/
|
233
|
+
arg 'f?', 'test arg f', :match => /^f$/, :default => "aaa"
|
234
|
+
arg 'g*', 'test arg g', :match => /^g$/, :default => ["bbb", "ccc"]
|
235
|
+
arg 'h+', 'test arg h', :match => /^h$/
|
236
|
+
end
|
237
|
+
|
238
|
+
expectedUsage = <<END
|
239
|
+
usage: rake_test_loader.rb options* e f? g* h+
|
240
|
+
|
241
|
+
Options:
|
242
|
+
-a: test opt a
|
243
|
+
-b ARG: test opt b
|
244
|
+
Default: xxx
|
245
|
+
-c, --cc: test opt c
|
246
|
+
-d, --dd ARG: test opt d
|
247
|
+
Default: yyy zzz
|
248
|
+
|
249
|
+
Arguments:
|
250
|
+
e: test arg e
|
251
|
+
f: test arg f
|
252
|
+
Default: aaa
|
253
|
+
g: test arg g
|
254
|
+
Default: bbb ccc
|
255
|
+
h: test arg h
|
256
|
+
END
|
257
|
+
|
258
|
+
assert_equal(expectedUsage, @parser.usage_message + "\n")
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_run
|
262
|
+
result = ParseOpts.run(['foo']) do
|
263
|
+
opt '-a', 'test opt a'
|
264
|
+
arg 'b', 'test arg b'
|
265
|
+
end
|
266
|
+
assert_equal('foo', result.delete('b'))
|
267
|
+
assert_equal({}, result)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
RUNIT::CUI::TestRunner.run(ParseOptsTests.suite)
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: parseOpts
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jon Coppeard
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-06 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: ""
|
17
|
+
email: jon at coppeard dot net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- CHANGELOG
|
27
|
+
- LICENSE
|
28
|
+
- lib/parseOpts.rb
|
29
|
+
- test/test_parseOpts.rb
|
30
|
+
- Rakefile
|
31
|
+
has_rdoc: true
|
32
|
+
homepage:
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
version:
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
rubyforge_project: parseOpts
|
53
|
+
rubygems_version: 1.3.1
|
54
|
+
signing_key:
|
55
|
+
specification_version: 2
|
56
|
+
summary: Library to parse commandline options and arguments
|
57
|
+
test_files:
|
58
|
+
- test/test_parseOpts.rb
|