getoptions 0.1
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/README +117 -0
- data/lib/getoptions.rb +427 -0
- data/test/standard.rb +250 -0
- metadata +48 -0
data/README
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
== Synopsis
|
2
|
+
|
3
|
+
GetOptions - Yet another command line argument parser for Ruby.
|
4
|
+
|
5
|
+
If you are familiar with Perl's Getopt::Long specification syntax you should
|
6
|
+
feel right at home. The following specifications are currently supported:
|
7
|
+
|
8
|
+
default -- This is the default case, the option is either there or it isn't
|
9
|
+
flag! -- You can specify either --flag or --no-flag to set true or false
|
10
|
+
name|a1|a2 -- You can use '|' to set up option aliases. In this example, the
|
11
|
+
'name' option will be set if either 'name', 'a1', or 'a2' is
|
12
|
+
specified on the command line.
|
13
|
+
|
14
|
+
optional:x -- An argument with an optional argument of type x
|
15
|
+
required=x -- An argument with a required argument of type x
|
16
|
+
alist=@x -- An argument that takes a list of things of type x
|
17
|
+
|
18
|
+
The following types are currently supported:
|
19
|
+
s|string -- A string value
|
20
|
+
i|integer -- An integer value
|
21
|
+
f|float -- A floating point value
|
22
|
+
For integer and float, an exception will be thrown if ruby
|
23
|
+
can't find a way to convert the supplied argument string.
|
24
|
+
|
25
|
+
As with Getopt::Long, you specify the long form of the option, but it can
|
26
|
+
parse short options as well. For example, if you have an option named 'help',
|
27
|
+
both --help and -h would enable the option. You can also specify a small
|
28
|
+
portion of the long form, and if it is enough to uniquely identify the option,
|
29
|
+
it will work. For example, --he or --hel would map to --help as long as you
|
30
|
+
don't have --hell, --hello, ... as an option.
|
31
|
+
|
32
|
+
There are several ways to get the option data after parsing. Of course there
|
33
|
+
is the hash style, which could look something like:
|
34
|
+
|
35
|
+
options = GetOptions.new(%w(help verbose!))
|
36
|
+
puts "I'm going to go do stuff now..." if options['verbose']
|
37
|
+
|
38
|
+
You can also use a symbol (options[:verbose]) instead of a string if you want.
|
39
|
+
In addition, you can access fields using the .-style accessor syntax:
|
40
|
+
|
41
|
+
show_help() if options.help
|
42
|
+
|
43
|
+
|
44
|
+
== Examples
|
45
|
+
|
46
|
+
Kicking the tires:
|
47
|
+
|
48
|
+
$ cat myscript1.rb
|
49
|
+
require 'getoptions'
|
50
|
+
|
51
|
+
opt = GetOptions.new(%w(help debug! verbose+ prefix:s size=i host=@s))
|
52
|
+
p opt
|
53
|
+
|
54
|
+
$ ./myscript1.rb --help
|
55
|
+
help: true
|
56
|
+
|
57
|
+
$ ./myscript1.rb --debug
|
58
|
+
debug: true
|
59
|
+
|
60
|
+
$ ./myscript1.rb --no-debug
|
61
|
+
debug: false
|
62
|
+
|
63
|
+
$ ./myscript1.rb -vvvvv
|
64
|
+
verbose: 5
|
65
|
+
|
66
|
+
$ ./myscript1.rb -vv --verbose
|
67
|
+
verbose: 3
|
68
|
+
|
69
|
+
$ ./myscript1.rb --pre
|
70
|
+
prefix: nil
|
71
|
+
|
72
|
+
$ ./myscript1.rb --pre myprefix
|
73
|
+
prefix: "myprefix"
|
74
|
+
|
75
|
+
$ ./myscript1.rb --size 5
|
76
|
+
size: 5
|
77
|
+
|
78
|
+
|
79
|
+
Mixing arguments with non-arguments:
|
80
|
+
|
81
|
+
$ cat myscript2.rb
|
82
|
+
require 'getoptions'
|
83
|
+
|
84
|
+
opt = GetOptions.new(%w(help debug! verbose+ prefix:s size=i host=@s))
|
85
|
+
p opt
|
86
|
+
puts '--'
|
87
|
+
p ARGV
|
88
|
+
|
89
|
+
$ ./myscript2.rb --siz 10 file1 file2 file3
|
90
|
+
size: 10
|
91
|
+
--
|
92
|
+
["file1", "file2", "file3"]
|
93
|
+
|
94
|
+
$ ./myscript2.rb --host host1 host2 -- file1 file2 file3
|
95
|
+
host: ["host1", "host2"]
|
96
|
+
--
|
97
|
+
["file1", "file2", "file3"]
|
98
|
+
|
99
|
+
|
100
|
+
Processing your own input stream:
|
101
|
+
|
102
|
+
$ cat myscript3.rb
|
103
|
+
require 'getoptions'
|
104
|
+
|
105
|
+
input = %w(-vv -w 1 -2 -- file1)
|
106
|
+
opt = GetOptions.new(%w(verbose+ weights:@i), input)
|
107
|
+
p opt
|
108
|
+
puts '--'
|
109
|
+
p input
|
110
|
+
|
111
|
+
$ ./myscript3.rb
|
112
|
+
verbose: 2
|
113
|
+
weights: [1, -2]
|
114
|
+
--
|
115
|
+
["file1"]
|
116
|
+
|
117
|
+
|
data/lib/getoptions.rb
ADDED
@@ -0,0 +1,427 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# == Synopsis
|
5
|
+
#
|
6
|
+
# GetOptions - Yet another command line argument parser for Ruby.
|
7
|
+
#
|
8
|
+
# If you are familiar with Perl's Getopt::Long specification syntax you should
|
9
|
+
# feel right at home. The following specifications are currently supported:
|
10
|
+
#
|
11
|
+
# default -- This is the default case, the option is either there or it isn't
|
12
|
+
# flag! -- You can specify either --flag or --no-flag to set true or false
|
13
|
+
# name|a1|a2 -- You can use '|' to set up option aliases. In this example, the
|
14
|
+
# 'name' option will be set if either 'name', 'a1', or 'a2' is
|
15
|
+
# specified on the command line.
|
16
|
+
#
|
17
|
+
# optional:x -- An argument with an optional argument of type x
|
18
|
+
# required=x -- An argument with a required argument of type x
|
19
|
+
# alist=@x -- An argument that takes a list of things of type x
|
20
|
+
#
|
21
|
+
# The following types are currently supported:
|
22
|
+
# s|string -- A string value
|
23
|
+
# i|integer -- An integer value
|
24
|
+
# f|float -- A floating point value
|
25
|
+
# For integer and float, an exception will be thrown if ruby
|
26
|
+
# can't find a way to convert the supplied argument string.
|
27
|
+
#
|
28
|
+
# As with Getopt::Long, you specify the long form of the option, but it can
|
29
|
+
# parse short options as well. For example, if you have an option named 'help',
|
30
|
+
# both --help and -h would enable the option. You can also specify a small
|
31
|
+
# portion of the long form, and if it is enough to uniquely identify the option,
|
32
|
+
# it will work. For example, --he or --hel would map to --help as long as you
|
33
|
+
# don't have --hell, --hello, ... as an option.
|
34
|
+
#
|
35
|
+
# There are several ways to get the option data after parsing. Of course there
|
36
|
+
# is the hash style, which could look something like:
|
37
|
+
#
|
38
|
+
# options = GetOptions.new(%w(help verbose!))
|
39
|
+
# puts "I'm going to go do stuff now..." if options['verbose']
|
40
|
+
#
|
41
|
+
# You can also use a symbol (options[:verbose]) instead of a string if you want.
|
42
|
+
# In addition, you can access fields using the .-style accessor syntax:
|
43
|
+
#
|
44
|
+
# show_help() if options.help
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# == Examples
|
48
|
+
#
|
49
|
+
# Kicking the tires:
|
50
|
+
#
|
51
|
+
# $ cat myscript1.rb
|
52
|
+
# require 'getoptions'
|
53
|
+
#
|
54
|
+
# opt = GetOptions.new(%w(help debug! verbose+ prefix:s size=i host=@s))
|
55
|
+
# p opt
|
56
|
+
#
|
57
|
+
# $ ./myscript1.rb --help
|
58
|
+
# help: true
|
59
|
+
#
|
60
|
+
# $ ./myscript1.rb --debug
|
61
|
+
# debug: true
|
62
|
+
#
|
63
|
+
# $ ./myscript1.rb --no-debug
|
64
|
+
# debug: false
|
65
|
+
#
|
66
|
+
# $ ./myscript1.rb -vvvvv
|
67
|
+
# verbose: 5
|
68
|
+
#
|
69
|
+
# $ ./myscript1.rb -vv --verbose
|
70
|
+
# verbose: 3
|
71
|
+
#
|
72
|
+
# $ ./myscript1.rb --pre
|
73
|
+
# prefix: nil
|
74
|
+
#
|
75
|
+
# $ ./myscript1.rb --pre myprefix
|
76
|
+
# prefix: "myprefix"
|
77
|
+
#
|
78
|
+
# $ ./myscript1.rb --size 5
|
79
|
+
# size: 5
|
80
|
+
#
|
81
|
+
#
|
82
|
+
# Mixing arguments with non-arguments:
|
83
|
+
#
|
84
|
+
# $ cat myscript2.rb
|
85
|
+
# require 'getoptions'
|
86
|
+
#
|
87
|
+
# opt = GetOptions.new(%w(help debug! verbose+ prefix:s size=i host=@s))
|
88
|
+
# p opt
|
89
|
+
# puts '--'
|
90
|
+
# p ARGV
|
91
|
+
#
|
92
|
+
# $ ./myscript2.rb --siz 10 file1 file2 file3
|
93
|
+
# size: 10
|
94
|
+
# --
|
95
|
+
# ["file1", "file2", "file3"]
|
96
|
+
#
|
97
|
+
# $ ./myscript2.rb --host host1 host2 -- file1 file2 file3
|
98
|
+
# host: ["host1", "host2"]
|
99
|
+
# --
|
100
|
+
# ["file1", "file2", "file3"]
|
101
|
+
#
|
102
|
+
#
|
103
|
+
# Processing your own input stream:
|
104
|
+
#
|
105
|
+
# $ cat myscript3.rb
|
106
|
+
# require 'getoptions'
|
107
|
+
#
|
108
|
+
# input = %w(-vv -w 1 -2 -- file1)
|
109
|
+
# opt = GetOptions.new(%w(verbose+ weights:@i), input)
|
110
|
+
# p opt
|
111
|
+
# puts '--'
|
112
|
+
# p input
|
113
|
+
#
|
114
|
+
# $ ./myscript3.rb
|
115
|
+
# verbose: 2
|
116
|
+
# weights: [1, -2]
|
117
|
+
# --
|
118
|
+
# ["file1"]
|
119
|
+
#
|
120
|
+
#
|
121
|
+
|
122
|
+
require 'rdoc/usage'
|
123
|
+
require 'abbrev'
|
124
|
+
|
125
|
+
class GetOptions
|
126
|
+
|
127
|
+
class ParseError < Exception
|
128
|
+
end
|
129
|
+
|
130
|
+
# For select, reject, and other goodies
|
131
|
+
include Enumerable
|
132
|
+
|
133
|
+
# :call-seq:
|
134
|
+
# new(option_specs, input = ARGV) -> opt
|
135
|
+
#
|
136
|
+
# Parse input based on metadata in option_specs.
|
137
|
+
#
|
138
|
+
# == Examples
|
139
|
+
#
|
140
|
+
# opt = GetOptions.new(%w(help verbose! strarg=s))
|
141
|
+
# puts "I'm going to go do stuff..." if (opt.verbose)
|
142
|
+
# ...
|
143
|
+
#
|
144
|
+
def initialize(option_specs, input = ARGV)
|
145
|
+
build_dict(option_specs)
|
146
|
+
|
147
|
+
@options = {}
|
148
|
+
leftover = []
|
149
|
+
until input.empty?
|
150
|
+
arg = input.shift
|
151
|
+
|
152
|
+
case arg
|
153
|
+
# Stop if you hit --
|
154
|
+
when '--'
|
155
|
+
break
|
156
|
+
|
157
|
+
# Long form
|
158
|
+
when /^--(\S+)/
|
159
|
+
o, a = $1.split('=', 2)
|
160
|
+
input.unshift(a) if a
|
161
|
+
input = process_arguments(o, input)
|
162
|
+
|
163
|
+
# Short form
|
164
|
+
when /^-(\S+)/
|
165
|
+
o, a = $1.split('=', 2)
|
166
|
+
input.unshift(a) if a
|
167
|
+
o.scan(/./) do |c|
|
168
|
+
input = process_arguments(c, input)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Not an option, leave it
|
172
|
+
else
|
173
|
+
leftover << arg
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Put what didn't parse back into input
|
178
|
+
input.concat(leftover)
|
179
|
+
end
|
180
|
+
|
181
|
+
# :call-seq:
|
182
|
+
# opt[key] -> value
|
183
|
+
#
|
184
|
+
# Returns the value of the specified option. If the option was in
|
185
|
+
# the specification but not found in the input data, nill is returned.
|
186
|
+
#
|
187
|
+
def [](k)
|
188
|
+
raise ParseError.new("`nil' cannot be an option key") if (k.nil?)
|
189
|
+
sym = k.to_sym
|
190
|
+
key = k.to_s
|
191
|
+
|
192
|
+
case
|
193
|
+
when @options.has_key?(sym); @options[sym]
|
194
|
+
when @dict.has_key?(key); nil
|
195
|
+
else raise ParseError.new("program tried to access an unknown option: #{key.inspect}")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# :call-seq:
|
200
|
+
# has_option?(key) -> true or false
|
201
|
+
#
|
202
|
+
# Returns true if the specified key exists in the option input.
|
203
|
+
#
|
204
|
+
# == Examples
|
205
|
+
#
|
206
|
+
# opt = GetOptions.new(%w(help verbose! strarg=s))
|
207
|
+
# puts "I'm going to go do stuff..." if (opt.has_option(:verbose))
|
208
|
+
# puts "I don't exist..." if (opt.has_option(:bogus))
|
209
|
+
# ...
|
210
|
+
#
|
211
|
+
def has_option?(k)
|
212
|
+
raise ParseError.new("`nil' cannot be an option key") if (k.nil?)
|
213
|
+
@options.has_key?(k.to_sym)
|
214
|
+
end
|
215
|
+
|
216
|
+
alias to_s inspect
|
217
|
+
|
218
|
+
def inspect
|
219
|
+
@options.sort_by{|k| k.to_s}.collect do |key, val|
|
220
|
+
"%s: %s" % [key.inspect, val.inspect]
|
221
|
+
end.join($/)
|
222
|
+
end
|
223
|
+
|
224
|
+
# :call-seq:
|
225
|
+
# opt.each { |key,val| block } -> Hash
|
226
|
+
#
|
227
|
+
# Iterate over each parsed option name and value.
|
228
|
+
#
|
229
|
+
# == Examples
|
230
|
+
# opt.each do |key,val|
|
231
|
+
# puts "#{key} -> #{val.inspect}"
|
232
|
+
# end
|
233
|
+
#
|
234
|
+
def each
|
235
|
+
@options.each do |key,value|
|
236
|
+
yield key.to_s, value
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
# Wrapper to hash accessor
|
243
|
+
def method_missing(method, *args) #:nodoc:
|
244
|
+
self[method]
|
245
|
+
end
|
246
|
+
|
247
|
+
# Builds a keyword dictionary based on option specification
|
248
|
+
def build_dict(option_specs) #:nodoc:
|
249
|
+
@dict = {}
|
250
|
+
keys = []
|
251
|
+
option_specs.each do |option_spec|
|
252
|
+
# Parse the specification
|
253
|
+
m, label, oper, cont, arg = *option_spec.match(/([^=:]+)(?:([=:])([@])?(\w+))?/)
|
254
|
+
raise ParseError.new("invalid option format for '#{option_spec}'") unless m
|
255
|
+
|
256
|
+
# Figure out the specification type
|
257
|
+
is_bang_arg = label.gsub!(/!$/, '')
|
258
|
+
is_increment = label.gsub!(/\+$/, '')
|
259
|
+
forms = label.split('|')
|
260
|
+
key = forms.first
|
261
|
+
|
262
|
+
# Create an instance of OptionDefinition to hold metat data
|
263
|
+
od = OptionDefinition.new(key)
|
264
|
+
od.option_type = :boolean if is_bang_arg
|
265
|
+
od.option_type = :increment if is_increment
|
266
|
+
if (arg)
|
267
|
+
od.option_type = (oper == '=') ? :required_argument : :optional_argument
|
268
|
+
od.container_type = case cont
|
269
|
+
when '@'; :array
|
270
|
+
else :scalar
|
271
|
+
end
|
272
|
+
od.argument_type = case arg
|
273
|
+
when 'f', 'float' ; :float
|
274
|
+
when 'i', 'integer'; :integer
|
275
|
+
when 's', 'string' ; :string
|
276
|
+
else raise ParseError.new("unknown argument type '#{arg}'")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
# Process alternate key names
|
281
|
+
forms.each do |k|
|
282
|
+
@dict[k] = od.dup
|
283
|
+
keys << k
|
284
|
+
end
|
285
|
+
|
286
|
+
# Only support negation on long option names
|
287
|
+
if (is_bang_arg)
|
288
|
+
@dict["no-#{key}"] = od.dup
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# Allow abbreviated long options
|
293
|
+
keys.abbrev.each do |ab,key|
|
294
|
+
@dict[ab] = @dict[key].dup
|
295
|
+
@dict[ab].abbreviated = true unless (ab == key)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
# Parse all arguments for the current option
|
300
|
+
def process_arguments(k, input) #:nodoc:
|
301
|
+
if (opt = @dict[k])
|
302
|
+
key = opt.key
|
303
|
+
case opt.option_type
|
304
|
+
when :boolean
|
305
|
+
@options[key] = (k != "no-#{key}")
|
306
|
+
when :increment
|
307
|
+
@options[key] ||= 0
|
308
|
+
@options[key] += 1
|
309
|
+
when :optional_argument, :required_argument
|
310
|
+
args = []
|
311
|
+
loop do
|
312
|
+
break if (input.empty?)
|
313
|
+
arg = input.shift
|
314
|
+
|
315
|
+
is_arg = case arg
|
316
|
+
# If it matches a long argument name, it isn't an argument
|
317
|
+
when '--'
|
318
|
+
false
|
319
|
+
when /^--(\S+)/
|
320
|
+
o, a = $1.split('=', 2)
|
321
|
+
!@dict.has_key?(o)
|
322
|
+
# If this is a valid shorthand option string, abort
|
323
|
+
when /^-(\S+)/
|
324
|
+
o, a = $1.split('=', 2)
|
325
|
+
!o.scan(/./).all? { |c| @dict.has_key?(c) }
|
326
|
+
else
|
327
|
+
true
|
328
|
+
end
|
329
|
+
|
330
|
+
# We've hit another option, get outta here
|
331
|
+
#if (arg =~ /^-/)
|
332
|
+
unless (is_arg)
|
333
|
+
input.unshift(arg)
|
334
|
+
break
|
335
|
+
end
|
336
|
+
args << arg
|
337
|
+
# If this is a scalar type, stop after the first argument
|
338
|
+
break if opt.container_type == :scalar
|
339
|
+
end
|
340
|
+
|
341
|
+
if (args.empty?)
|
342
|
+
# No argument found, and one was required, complain about it
|
343
|
+
if (opt.option_type == :required_argument)
|
344
|
+
raise ParseError.new("missing required argument for '#{key}'")
|
345
|
+
# No argument found, but it was optional, set a default value
|
346
|
+
else
|
347
|
+
case opt.container_type
|
348
|
+
when :scalar; @options[key] = nil
|
349
|
+
when :array; @options[key] = []
|
350
|
+
end
|
351
|
+
end
|
352
|
+
else
|
353
|
+
args.each do |arg|
|
354
|
+
val = case opt.argument_type
|
355
|
+
when :float
|
356
|
+
# Try to parse float option, toss an exception if the parse failed
|
357
|
+
Float(arg) rescue
|
358
|
+
raise ParseError.new("expecting float value for option '#{key}'")
|
359
|
+
when :integer
|
360
|
+
# Try to parse integer option, toss an exception if the parse failed
|
361
|
+
Integer(arg) rescue
|
362
|
+
raise ParseError.new("expecting integer value for option '#{key}'")
|
363
|
+
else
|
364
|
+
# Assume string type (no processing needed)
|
365
|
+
arg
|
366
|
+
end
|
367
|
+
# Either set the option value (scalar) or add it to the list (array)
|
368
|
+
case opt.container_type
|
369
|
+
when :scalar; @options[key] = val
|
370
|
+
when :array; (@options[key] ||= []) << val
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
else
|
376
|
+
# If an exact match isn't found, try to make a suggestion
|
377
|
+
candidates = @dict.keys.select do |c|
|
378
|
+
(!@dict[c].is_abbreviated? && c =~ /^#{k}/)
|
379
|
+
end
|
380
|
+
matches = case candidates.size
|
381
|
+
when 0
|
382
|
+
nil
|
383
|
+
when 1
|
384
|
+
", did you mean #{candidates.first}?"
|
385
|
+
else
|
386
|
+
", close matches are: " +
|
387
|
+
candidates[0, candidates.size - 1].join(", ") +
|
388
|
+
" and " + candidates.last
|
389
|
+
end
|
390
|
+
raise ParseError.new("unknown option '#{k}'#{matches || ''}")
|
391
|
+
end
|
392
|
+
|
393
|
+
input
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
class OptionDefinition #:nodoc: all
|
398
|
+
attr_accessor :key
|
399
|
+
attr_accessor :option_type
|
400
|
+
attr_accessor :argument_type
|
401
|
+
attr_accessor :container_type
|
402
|
+
attr_accessor :abbreviated
|
403
|
+
|
404
|
+
def initialize(key)
|
405
|
+
@key = key.to_sym
|
406
|
+
@option_type = :boolean
|
407
|
+
@abbreviated = false
|
408
|
+
end
|
409
|
+
|
410
|
+
def is_abbreviated?
|
411
|
+
@abbreviated
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
end
|
416
|
+
|
417
|
+
|
418
|
+
# Spit out usage if --help is specified
|
419
|
+
if __FILE__ == $0
|
420
|
+
begin
|
421
|
+
RDoc::usage if GetOptions.new(%w(help)).help
|
422
|
+
rescue
|
423
|
+
warn $!
|
424
|
+
exit 1
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
data/test/standard.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Unit test for GetOptions
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), '../lib/getoptions')
|
6
|
+
require 'spec'
|
7
|
+
|
8
|
+
|
9
|
+
describe GetOptions do
|
10
|
+
|
11
|
+
# String tests
|
12
|
+
it "should parse strings, short type name" do
|
13
|
+
opt = GetOptions.new(%w(string=s), %w(--str test))
|
14
|
+
opt.string.should eql('test')
|
15
|
+
end
|
16
|
+
it "should parse strings, long type name" do
|
17
|
+
opt = GetOptions.new(%w(string=string), %w(--str test))
|
18
|
+
opt.string.should eql('test')
|
19
|
+
end
|
20
|
+
|
21
|
+
# Integer tests
|
22
|
+
it "should parse integers, short type name" do
|
23
|
+
opt = GetOptions.new(%w(int=i), %w(--int 5))
|
24
|
+
opt.int.should eql(5)
|
25
|
+
end
|
26
|
+
it "should parse integers, long type name" do
|
27
|
+
opt = GetOptions.new(%w(int=integer), %w(--int 5))
|
28
|
+
opt.int.should eql(5)
|
29
|
+
end
|
30
|
+
it "should throw an exception on non integers" do
|
31
|
+
lambda {
|
32
|
+
GetOptions.new(%w(int=i), %w(--int NaN))
|
33
|
+
}.should raise_error(GetOptions::ParseError, /expecting integer value/)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Float tests
|
37
|
+
it "should parse floats, short type name" do
|
38
|
+
opt = GetOptions.new(%w(float=f), %w(--float 0.5))
|
39
|
+
opt.float.should eql(0.5)
|
40
|
+
end
|
41
|
+
it "should parse floats, long type name" do
|
42
|
+
opt = GetOptions.new(%w(float=float), %w(--float 0.5))
|
43
|
+
opt.float.should eql(0.5)
|
44
|
+
end
|
45
|
+
it "should throw an exception on non floats" do
|
46
|
+
lambda {
|
47
|
+
GetOptions.new(%w(float=f), %w(--float NaN))
|
48
|
+
}.should raise_error(GetOptions::ParseError, /expecting float value/)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Flag tests
|
52
|
+
it "should parse flags set to true" do
|
53
|
+
opt = GetOptions.new(%w(flag!), %w(--flag))
|
54
|
+
opt.flag.should eql(true)
|
55
|
+
end
|
56
|
+
it "should parse flags set to false" do
|
57
|
+
opt = GetOptions.new(%w(flag!), %w(--no-flag))
|
58
|
+
opt.flag.should eql(false)
|
59
|
+
end
|
60
|
+
|
61
|
+
# List tests
|
62
|
+
it "should parse a list of strings" do
|
63
|
+
opt = GetOptions.new(%w(list=@s), %w(--list foo bar --li baz -l qux))
|
64
|
+
opt.list.should eql(%w(foo bar baz qux))
|
65
|
+
end
|
66
|
+
it "should parse a list of integers" do
|
67
|
+
opt = GetOptions.new(%w(list=@i), %w(--list 1 2 --li 3 -l 4))
|
68
|
+
opt.list.should eql([1,2,3,4])
|
69
|
+
end
|
70
|
+
it "should parse a list of integers w/ negative numbers" do
|
71
|
+
opt = GetOptions.new(%w(list=@i), %w(--list 1 -2 --li 3 -l -4))
|
72
|
+
opt.list.should eql([1,-2,3,-4])
|
73
|
+
end
|
74
|
+
it "should not parse a list of non-integers" do
|
75
|
+
lambda {
|
76
|
+
GetOptions.new(%w(list=@i), %w(--list 1 2 oops 3))
|
77
|
+
}.should raise_error(GetOptions::ParseError, /expecting integer value/)
|
78
|
+
end
|
79
|
+
it "should parse a list of floats" do
|
80
|
+
opt = GetOptions.new(%w(list=@f), %w(--list 0.1 0.2 --li 0.3 -l 0.4))
|
81
|
+
opt.list.should eql([0.1,0.2,0.3,0.4])
|
82
|
+
end
|
83
|
+
it "should parse a list of floats w/ negative numbers" do
|
84
|
+
opt = GetOptions.new(%w(list=@f), %w(--list 0.1 -0.2 --li -0.3 -l 0.4))
|
85
|
+
opt.list.should eql([0.1,-0.2,-0.3,0.4])
|
86
|
+
end
|
87
|
+
it "should not parse a list of non-floats" do
|
88
|
+
lambda {
|
89
|
+
GetOptions.new(%w(list=@f), %w(--list 0.1 0.2 oops 0.3))
|
90
|
+
}.should raise_error(GetOptions::ParseError, /expecting float value/)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Optional argument tests
|
94
|
+
it "should parse an optional string argument" do
|
95
|
+
opt = GetOptions.new(%w(string:s), %w(--str))
|
96
|
+
opt.string.should eql(nil)
|
97
|
+
end
|
98
|
+
it "should parse an optional integer argument" do
|
99
|
+
opt = GetOptions.new(%w(int:i), %w(--int))
|
100
|
+
opt.int.should eql(nil)
|
101
|
+
end
|
102
|
+
it "should parse an optional float argument" do
|
103
|
+
opt = GetOptions.new(%w(float:f), %w(--float))
|
104
|
+
opt.float.should eql(nil)
|
105
|
+
end
|
106
|
+
it "should parse an optional list argument" do
|
107
|
+
opt = GetOptions.new(%w(list:@s), %w(--list))
|
108
|
+
opt.list.should eql([])
|
109
|
+
end
|
110
|
+
|
111
|
+
# has_option test
|
112
|
+
it "should check option presence" do
|
113
|
+
opt = GetOptions.new(%w(string:s), %w(--string))
|
114
|
+
opt.has_option?(:string).should eql(true)
|
115
|
+
end
|
116
|
+
it "should fail on invalid option presence" do
|
117
|
+
opt = GetOptions.new(%w(string:s), %w(--string))
|
118
|
+
opt.has_option?(:blah).should_not eql(true)
|
119
|
+
end
|
120
|
+
it "should fail on `nil' key option check" do
|
121
|
+
lambda {
|
122
|
+
opt = GetOptions.new(%w(string:s), %w(--string))
|
123
|
+
opt.has_option?(nil).should_not eql(true)
|
124
|
+
}.should raise_error(GetOptions::ParseError, /`nil' cannot be an option key/)
|
125
|
+
end
|
126
|
+
|
127
|
+
# input array tests
|
128
|
+
it "should retain non-options in input list (no option)" do
|
129
|
+
input = %w(--flag x1 x2 x3)
|
130
|
+
opt = GetOptions.new(%w(flag), input)
|
131
|
+
input.should eql(%w(x1 x2 x3))
|
132
|
+
end
|
133
|
+
it "should retain non-options in input list (required option)" do
|
134
|
+
input = %w(--string test x1 x2 x3)
|
135
|
+
opt = GetOptions.new(%w(string=s), input)
|
136
|
+
input.should eql(%w(x1 x2 x3))
|
137
|
+
end
|
138
|
+
it "should retain non-options in input list (optional option)" do
|
139
|
+
input = %w(--string x1 x2 x3)
|
140
|
+
opt = GetOptions.new(%w(string:s), input)
|
141
|
+
input.should eql(%w(x2 x3))
|
142
|
+
end
|
143
|
+
it "should stop options parsing on --" do
|
144
|
+
input = %w(--list x1 x2 x3 -- x4 x5 x6)
|
145
|
+
opt = GetOptions.new(%w(list=@s), input)
|
146
|
+
input.should eql(%w(x4 x5 x6))
|
147
|
+
end
|
148
|
+
|
149
|
+
# Accessor tests
|
150
|
+
it "should be accessed as a hash (string key)" do
|
151
|
+
opt = GetOptions.new(%w(flag!), %w(--flag))
|
152
|
+
opt['flag'].should eql(true)
|
153
|
+
end
|
154
|
+
it "should be accessed as a hash (symbol key)" do
|
155
|
+
opt = GetOptions.new(%w(flag!), %w(--flag))
|
156
|
+
opt[:flag].should eql(true)
|
157
|
+
end
|
158
|
+
it "should fail on nil key" do
|
159
|
+
lambda {
|
160
|
+
opt = GetOptions.new(%w(flag!), %w(--flag))
|
161
|
+
opt[nil]
|
162
|
+
}.should raise_error(GetOptions::ParseError, /`nil' cannot be an option key/)
|
163
|
+
end
|
164
|
+
it "should fail on unknown key (string key)" do
|
165
|
+
lambda {
|
166
|
+
opt = GetOptions.new(%w(flag!), %w(--flag))
|
167
|
+
opt['notanoption']
|
168
|
+
}.should raise_error(GetOptions::ParseError, /program tried to access/)
|
169
|
+
end
|
170
|
+
it "should fail on unknown key (symbol key)" do
|
171
|
+
lambda {
|
172
|
+
opt = GetOptions.new(%w(flag!), %w(--flag))
|
173
|
+
opt[:notanoption]
|
174
|
+
}.should raise_error(GetOptions::ParseError, /program tried to access/)
|
175
|
+
end
|
176
|
+
|
177
|
+
# shorthand tests
|
178
|
+
it "shorthand test, multiple flags" do
|
179
|
+
opt = GetOptions.new(%w(aflag bflag cflag), %w(-ac))
|
180
|
+
opt.aflag.should eql(true)
|
181
|
+
opt.bflag.should eql(nil)
|
182
|
+
opt.cflag.should eql(true)
|
183
|
+
end
|
184
|
+
it "shorthand test, multiple arguments" do
|
185
|
+
opt = GetOptions.new(%w(astr=s bstr=s cstr=s), %w(-abc x1 x2 x3))
|
186
|
+
opt.astr.should eql('x1')
|
187
|
+
opt.bstr.should eql('x2')
|
188
|
+
opt.cstr.should eql('x3')
|
189
|
+
end
|
190
|
+
it "shorthand test, list interoperability" do
|
191
|
+
opt = GetOptions.new(%w(aflag bflag cflag list=@s), %w(--list foo -bar -ac))
|
192
|
+
opt.aflag.should eql(true)
|
193
|
+
opt.bflag.should eql(nil)
|
194
|
+
opt.cflag.should eql(true)
|
195
|
+
opt.list.should eql(%w(foo -bar))
|
196
|
+
end
|
197
|
+
it "shorthand test, list interoperability with invalid option" do
|
198
|
+
lambda {
|
199
|
+
GetOptions.new(%w(aflag bflag cflag list=@s), %w(--list foo -bar -ac -q))
|
200
|
+
}.should raise_error(GetOptions::ParseError, "unknown option 'q'")
|
201
|
+
end
|
202
|
+
|
203
|
+
# last option tests
|
204
|
+
it "last option wins (boolean), true at the end" do
|
205
|
+
opt = GetOptions.new(%w(flag!), %w(--flag --no-flag -f))
|
206
|
+
opt.flag.should eql(true)
|
207
|
+
end
|
208
|
+
it "last option wins (boolean), false at the end" do
|
209
|
+
opt = GetOptions.new(%w(flag!), %w(--flag --no-flag))
|
210
|
+
opt.flag.should eql(false)
|
211
|
+
end
|
212
|
+
it "last option wins (float)" do
|
213
|
+
opt = GetOptions.new(%w(float=f), %w(--float 0.1 -f 0.2))
|
214
|
+
opt.float.should eql(0.2)
|
215
|
+
end
|
216
|
+
it "last option wins (int)" do
|
217
|
+
opt = GetOptions.new(%w(int=i), %w(--int 1 -i 2))
|
218
|
+
opt.int.should eql(2)
|
219
|
+
end
|
220
|
+
it "last option wins (string)" do
|
221
|
+
opt = GetOptions.new(%w(string=s), %w(-s x1 --string x2))
|
222
|
+
opt.string.should eql('x2')
|
223
|
+
end
|
224
|
+
|
225
|
+
# misc make it break tests
|
226
|
+
it "should throw an exception on invalid types" do
|
227
|
+
lambda {
|
228
|
+
GetOptions.new(%w(arg=bogus), %w(--arg val))
|
229
|
+
}.should raise_error(GetOptions::ParseError, /unknown argument type/)
|
230
|
+
end
|
231
|
+
it "should throw an exception when supplying an option that doesn't exist" do
|
232
|
+
lambda {
|
233
|
+
GetOptions.new(%w(string=s), %w(--notanoption))
|
234
|
+
}.should raise_error(GetOptions::ParseError, /unknown option/)
|
235
|
+
end
|
236
|
+
it "should throw an exception when fetching an option that doesn't exist" do
|
237
|
+
lambda {
|
238
|
+
opt = GetOptions.new(%w(string=s), %w(--string test))
|
239
|
+
opt.notanoption
|
240
|
+
}.should raise_error(GetOptions::ParseError, /program tried to access an unknown/)
|
241
|
+
end
|
242
|
+
|
243
|
+
# inspect test
|
244
|
+
it "inspect method should return proper results" do
|
245
|
+
opt = GetOptions.new(%w(flag string=s int:i verbose+ list=@s),
|
246
|
+
%w(--int 5 -vvv --list 1 2 3 --flag --string test))
|
247
|
+
opt.to_s
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: getoptions
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2007-11-30 00:00:00 -08:00
|
8
|
+
summary: Yet another command line option parser in Ruby, based on Perl's Getopt::Long module.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: dparker @nospam@ liveops.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
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
|
+
- Delaney Parker
|
31
|
+
files:
|
32
|
+
- lib/getoptions.rb
|
33
|
+
- test/standard.rb
|
34
|
+
- README
|
35
|
+
test_files:
|
36
|
+
- test/standard.rb
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
requirements: []
|
46
|
+
|
47
|
+
dependencies: []
|
48
|
+
|