getoptions 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|