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.
Files changed (4) hide show
  1. data/README +117 -0
  2. data/lib/getoptions.rb +427 -0
  3. data/test/standard.rb +250 -0
  4. 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
+
@@ -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
+
@@ -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
+