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.
Files changed (7) hide show
  1. data/CHANGELOG +9 -0
  2. data/LICENSE +19 -0
  3. data/README +65 -0
  4. data/Rakefile +40 -0
  5. data/lib/parseOpts.rb +287 -0
  6. data/test/test_parseOpts.rb +271 -0
  7. metadata +58 -0
data/CHANGELOG ADDED
@@ -0,0 +1,9 @@
1
+ Changelog
2
+ =========
3
+
4
+ 15/04/09:
5
+ parseArgs-0.0.1 released
6
+
7
+ 04/05/09:
8
+ Projects renamed parseOpts to avoid clash with existing parseArgs
9
+ parseOpts-0.0.2 released
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