parseOpts 0.0.2
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/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
|