rubysl-optparse 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5c18e9580638817c6183b8bcf5e0582e96e6d551
4
+ data.tar.gz: 4deb5325eebec24c3525ca76aaa04946780d384b
5
+ SHA512:
6
+ metadata.gz: 1d72e8313fa24a8d64394cb05e2895216165b1fa1011cd4635e55be6fcc09a64c55d5b9395f4286edf2088b99a8e038c40481ff5102f0f13cc03fb19db7b9661
7
+ data.tar.gz: bf2211201021203cc296453b9a98604e74a0e4d127b5d3fbcabcd4a4c118628a710511cd88152625f899d58ad5fd31669a29b14039e29b10775dadb96e36e31f
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ env:
3
+ - RUBYLIB=lib
4
+ script: bundle exec mspec
5
+ rvm:
6
+ - 1.8.7
7
+ - rbx-nightly-18mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rubysl-optparse.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rubysl::Optparse
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rubysl-optparse'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rubysl-optparse
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/optparse.rb ADDED
@@ -0,0 +1 @@
1
+ require "rubysl/optparse"
@@ -0,0 +1,17 @@
1
+ require 'optparse'
2
+ require 'date'
3
+
4
+ OptionParser.accept(DateTime) do |s,|
5
+ begin
6
+ DateTime.parse(s) if s
7
+ rescue ArgumentError
8
+ raise OptionParser::InvalidArgument, s
9
+ end
10
+ end
11
+ OptionParser.accept(Date) do |s,|
12
+ begin
13
+ Date.parse(s) if s
14
+ rescue ArgumentError
15
+ raise OptionParser::InvalidArgument, s
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'shellwords'
4
+ require 'optparse'
5
+
6
+ OptionParser.accept(Shellwords) {|s,| Shellwords.shellwords(s)}
@@ -0,0 +1,10 @@
1
+ require 'optparse'
2
+ require 'time'
3
+
4
+ OptionParser.accept(Time) do |s,|
5
+ begin
6
+ (Time.httpdate(s) rescue Time.parse(s)) if s
7
+ rescue
8
+ raise OptionParser::InvalidArgument, s
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'optparse'
4
+ require 'uri'
5
+
6
+ OptionParser.accept(URI) {|s,| URI.parse(s) if s}
@@ -0,0 +1,70 @@
1
+ # OptionParser internal utility
2
+
3
+ class << OptionParser
4
+ def show_version(*pkg)
5
+ progname = ARGV.options.program_name
6
+ result = false
7
+ show = proc do |klass, cname, version|
8
+ str = "#{progname}"
9
+ unless klass == ::Object and cname == :VERSION
10
+ version = version.join(".") if Array === version
11
+ str << ": #{klass}" unless klass == Object
12
+ str << " version #{version}"
13
+ end
14
+ [:Release, :RELEASE].find do |rel|
15
+ if klass.const_defined?(rel)
16
+ str << " (#{klass.const_get(rel)})"
17
+ end
18
+ end
19
+ puts str
20
+ result = true
21
+ end
22
+ if pkg.size == 1 and pkg[0] == "all"
23
+ self.search_const(::Object, /\AV(?:ERSION|ersion)\z/) do |klass, cname, version|
24
+ unless cname[1] == ?e and klass.const_defined?(:Version)
25
+ show.call(klass, cname.intern, version)
26
+ end
27
+ end
28
+ else
29
+ pkg.each do |pkg|
30
+ begin
31
+ pkg = pkg.split(/::|\//).inject(::Object) {|m, c| m.const_get(c)}
32
+ v = case
33
+ when pkg.const_defined?(:Version)
34
+ pkg.const_get(n = :Version)
35
+ when pkg.const_defined?(:VERSION)
36
+ pkg.const_get(n = :VERSION)
37
+ else
38
+ n = nil
39
+ "unknown"
40
+ end
41
+ show.call(pkg, n, v)
42
+ rescue NameError
43
+ end
44
+ end
45
+ end
46
+ result
47
+ end
48
+
49
+ def each_const(path, klass = ::Object)
50
+ path.split(/::|\//).inject(klass) do |klass, name|
51
+ raise NameError, path unless Module === klass
52
+ klass.constants.grep(/#{name}/i) do |c|
53
+ klass.const_defined?(c) or next
54
+ c = klass.const_get(c)
55
+ end
56
+ end
57
+ end
58
+
59
+ def search_const(klass, name)
60
+ klasses = [klass]
61
+ while klass = klasses.shift
62
+ klass.constants.each do |cname|
63
+ klass.const_defined?(cname) or next
64
+ const = klass.const_get(cname)
65
+ yield klass, cname, const if name === cname
66
+ klasses << const if Module === const and const != ::Object
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,2 @@
1
+ require "rubysl/optparse/version"
2
+ require "rubysl/optparse/optparse"
@@ -0,0 +1,1796 @@
1
+ #
2
+ # optparse.rb - command-line option analysis with the OptionParser class.
3
+ #
4
+ # Author:: Nobu Nakada
5
+ # Documentation:: Nobu Nakada and Gavin Sinclair.
6
+ #
7
+ # See OptionParser for documentation.
8
+ #
9
+
10
+
11
+ # == Developer Documentation (not for RDoc output)
12
+ #
13
+ # === Class tree
14
+ #
15
+ # - OptionParser:: front end
16
+ # - OptionParser::Switch:: each switches
17
+ # - OptionParser::List:: options list
18
+ # - OptionParser::ParseError:: errors on parsing
19
+ # - OptionParser::AmbiguousOption
20
+ # - OptionParser::NeedlessArgument
21
+ # - OptionParser::MissingArgument
22
+ # - OptionParser::InvalidOption
23
+ # - OptionParser::InvalidArgument
24
+ # - OptionParser::AmbiguousArgument
25
+ #
26
+ # === Object relationship diagram
27
+ #
28
+ # +--------------+
29
+ # | OptionParser |<>-----+
30
+ # +--------------+ | +--------+
31
+ # | ,-| Switch |
32
+ # on_head -------->+---------------+ / +--------+
33
+ # accept/reject -->| List |<|>-
34
+ # | |<|>- +----------+
35
+ # on ------------->+---------------+ `-| argument |
36
+ # : : | class |
37
+ # +---------------+ |==========|
38
+ # on_tail -------->| | |pattern |
39
+ # +---------------+ |----------|
40
+ # OptionParser.accept ->| DefaultList | |converter |
41
+ # reject |(shared between| +----------+
42
+ # | all instances)|
43
+ # +---------------+
44
+ #
45
+ # == OptionParser
46
+ #
47
+ # === Introduction
48
+ #
49
+ # OptionParser is a class for command-line option analysis. It is much more
50
+ # advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
51
+ # solution.
52
+ #
53
+ # === Features
54
+ #
55
+ # 1. The argument specification and the code to handle it are written in the
56
+ # same place.
57
+ # 2. It can output an option summary; you don't need to maintain this string
58
+ # separately.
59
+ # 3. Optional and mandatory arguments are specified very gracefully.
60
+ # 4. Arguments can be automatically converted to a specified class.
61
+ # 5. Arguments can be restricted to a certain set.
62
+ #
63
+ # All of these features are demonstrated in the examples below.
64
+ #
65
+ # === Minimal example
66
+ #
67
+ # require 'optparse'
68
+ #
69
+ # options = {}
70
+ # OptionParser.new do |opts|
71
+ # opts.banner = "Usage: example.rb [options]"
72
+ #
73
+ # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
74
+ # options[:verbose] = v
75
+ # end
76
+ # end.parse!
77
+ #
78
+ # p options
79
+ # p ARGV
80
+ #
81
+ # === Complete example
82
+ #
83
+ # The following example is a complete Ruby program. You can run it and see the
84
+ # effect of specifying various options. This is probably the best way to learn
85
+ # the features of +optparse+.
86
+ #
87
+ # require 'optparse'
88
+ # require 'optparse/time'
89
+ # require 'ostruct'
90
+ # require 'pp'
91
+ #
92
+ # class OptparseExample
93
+ #
94
+ # CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
95
+ # CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
96
+ #
97
+ # #
98
+ # # Return a structure describing the options.
99
+ # #
100
+ # def self.parse(args)
101
+ # # The options specified on the command line will be collected in *options*.
102
+ # # We set default values here.
103
+ # options = OpenStruct.new
104
+ # options.library = []
105
+ # options.inplace = false
106
+ # options.encoding = "utf8"
107
+ # options.transfer_type = :auto
108
+ # options.verbose = false
109
+ #
110
+ # opts = OptionParser.new do |opts|
111
+ # opts.banner = "Usage: example.rb [options]"
112
+ #
113
+ # opts.separator ""
114
+ # opts.separator "Specific options:"
115
+ #
116
+ # # Mandatory argument.
117
+ # opts.on("-r", "--require LIBRARY",
118
+ # "Require the LIBRARY before executing your script") do |lib|
119
+ # options.library << lib
120
+ # end
121
+ #
122
+ # # Optional argument; multi-line description.
123
+ # opts.on("-i", "--inplace [EXTENSION]",
124
+ # "Edit ARGV files in place",
125
+ # " (make backup if EXTENSION supplied)") do |ext|
126
+ # options.inplace = true
127
+ # options.extension = ext || ''
128
+ # options.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
129
+ # end
130
+ #
131
+ # # Cast 'delay' argument to a Float.
132
+ # opts.on("--delay N", Float, "Delay N seconds before executing") do |n|
133
+ # options.delay = n
134
+ # end
135
+ #
136
+ # # Cast 'time' argument to a Time object.
137
+ # opts.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
138
+ # options.time = time
139
+ # end
140
+ #
141
+ # # Cast to octal integer.
142
+ # opts.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
143
+ # "Specify record separator (default \\0)") do |rs|
144
+ # options.record_separator = rs
145
+ # end
146
+ #
147
+ # # List of arguments.
148
+ # opts.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
149
+ # options.list = list
150
+ # end
151
+ #
152
+ # # Keyword completion. We are specifying a specific set of arguments (CODES
153
+ # # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
154
+ # # the shortest unambiguous text.
155
+ # code_list = (CODE_ALIASES.keys + CODES).join(',')
156
+ # opts.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
157
+ # " (#{code_list})") do |encoding|
158
+ # options.encoding = encoding
159
+ # end
160
+ #
161
+ # # Optional argument with keyword completion.
162
+ # opts.on("--type [TYPE]", [:text, :binary, :auto],
163
+ # "Select transfer type (text, binary, auto)") do |t|
164
+ # options.transfer_type = t
165
+ # end
166
+ #
167
+ # # Boolean switch.
168
+ # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
169
+ # options.verbose = v
170
+ # end
171
+ #
172
+ # opts.separator ""
173
+ # opts.separator "Common options:"
174
+ #
175
+ # # No argument, shows at tail. This will print an options summary.
176
+ # # Try it and see!
177
+ # opts.on_tail("-h", "--help", "Show this message") do
178
+ # puts opts
179
+ # exit
180
+ # end
181
+ #
182
+ # # Another typical switch to print the version.
183
+ # opts.on_tail("--version", "Show version") do
184
+ # puts OptionParser::Version.join('.')
185
+ # exit
186
+ # end
187
+ # end
188
+ #
189
+ # opts.parse!(args)
190
+ # options
191
+ # end # parse()
192
+ #
193
+ # end # class OptparseExample
194
+ #
195
+ # options = OptparseExample.parse(ARGV)
196
+ # pp options
197
+ #
198
+ # === Further documentation
199
+ #
200
+ # The above examples should be enough to learn how to use this class. If you
201
+ # have any questions, email me (gsinclair@soyabean.com.au) and I will update
202
+ # this document.
203
+ #
204
+ class OptionParser
205
+ # :stopdoc:
206
+ RCSID = %w$Id: optparse.rb 22469 2009-02-20 11:43:35Z shyouhei $[1..-1].each {|s| s.freeze}.freeze
207
+ Version = (RCSID[1].split('.').collect {|s| s.to_i}.extend(Comparable).freeze if RCSID[1])
208
+ LastModified = (Time.gm(*RCSID[2, 2].join('-').scan(/\d+/).collect {|s| s.to_i}) if RCSID[2])
209
+ Release = RCSID[2]
210
+
211
+ NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
212
+ RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
213
+ OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
214
+ # :startdoc:
215
+
216
+ #
217
+ # Keyword completion module. This allows partial arguments to be specified
218
+ # and resolved against a list of acceptable values.
219
+ #
220
+ module Completion
221
+ def complete(key, icase = false, pat = nil)
222
+ pat ||= Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'),
223
+ icase)
224
+ canon, sw, k, v, cn = nil
225
+ candidates = []
226
+ each do |k, *v|
227
+ (if Regexp === k
228
+ kn = nil
229
+ k === key
230
+ else
231
+ kn = defined?(k.id2name) ? k.id2name : k
232
+ pat === kn
233
+ end) or next
234
+ v << k if v.empty?
235
+ candidates << [k, v, kn]
236
+ end
237
+ candidates = candidates.sort_by {|k, v, kn| kn.size}
238
+ if candidates.size == 1
239
+ canon, sw, * = candidates[0]
240
+ elsif candidates.size > 1
241
+ canon, sw, cn = candidates.shift
242
+ candidates.each do |k, v, kn|
243
+ next if sw == v
244
+ if String === cn and String === kn
245
+ if cn.rindex(kn, 0)
246
+ canon, sw, cn = k, v, kn
247
+ next
248
+ elsif kn.rindex(cn, 0)
249
+ next
250
+ end
251
+ end
252
+ throw :ambiguous, key
253
+ end
254
+ end
255
+ if canon
256
+ block_given? or return key, *sw
257
+ yield(key, *sw)
258
+ end
259
+ end
260
+
261
+ def convert(opt = nil, val = nil, *)
262
+ val
263
+ end
264
+ end
265
+
266
+
267
+ #
268
+ # Map from option/keyword string to object with completion.
269
+ #
270
+ class OptionMap < Hash
271
+ include Completion
272
+ end
273
+
274
+
275
+ #
276
+ # Individual switch class. Not important to the user.
277
+ #
278
+ # Defined within Switch are several Switch-derived classes: NoArgument,
279
+ # RequiredArgument, etc.
280
+ #
281
+ class Switch
282
+ attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
283
+
284
+ #
285
+ # Guesses argument style from +arg+. Returns corresponding
286
+ # OptionParser::Switch class (OptionalArgument, etc.).
287
+ #
288
+ def self.guess(arg)
289
+ case arg
290
+ when ""
291
+ t = self
292
+ when /\A=?\[/
293
+ t = Switch::OptionalArgument
294
+ when /\A\s+\[/
295
+ t = Switch::PlacedArgument
296
+ else
297
+ t = Switch::RequiredArgument
298
+ end
299
+ self >= t or incompatible_argument_styles(arg, t)
300
+ t
301
+ end
302
+
303
+ def self.incompatible_argument_styles(arg, t)
304
+ raise ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}"
305
+ end
306
+
307
+ def self.pattern
308
+ NilClass
309
+ end
310
+
311
+ def initialize(pattern = nil, conv = nil,
312
+ short = nil, long = nil, arg = nil,
313
+ desc = ([] if short or long), block = Proc.new)
314
+ raise if Array === pattern
315
+ @pattern, @conv, @short, @long, @arg, @desc, @block =
316
+ pattern, conv, short, long, arg, desc, block
317
+ end
318
+
319
+ #
320
+ # Parses +arg+ and returns rest of +arg+ and matched portion to the
321
+ # argument pattern. Yields when the pattern doesn't match substring.
322
+ #
323
+ def parse_arg(arg)
324
+ pattern or return nil, arg
325
+ unless m = pattern.match(arg)
326
+ yield(InvalidArgument, arg)
327
+ return arg, nil
328
+ end
329
+ if String === m
330
+ m = [s = m]
331
+ else
332
+ m = m.to_a
333
+ s = m[0]
334
+ return nil, m unless String === s
335
+ end
336
+ raise InvalidArgument, arg unless arg.rindex(s, 0)
337
+ return nil, m if s.length == arg.length
338
+ yield(InvalidArgument, arg) # didn't match whole arg
339
+ return arg[s.length..-1], m
340
+ end
341
+ private :parse_arg
342
+
343
+ #
344
+ # Parses argument, converts and returns +arg+, +block+ and result of
345
+ # conversion. Yields at semi-error condition instead of raising an
346
+ # exception.
347
+ #
348
+ def conv_arg(arg, val = nil)
349
+ if conv
350
+ val = conv.call(*val)
351
+ else
352
+ val = proc {|val| val}.call(*val)
353
+ end
354
+ return arg, block, val
355
+ end
356
+ private :conv_arg
357
+
358
+ #
359
+ # Produces the summary text. Each line of the summary is yielded to the
360
+ # block (without newline).
361
+ #
362
+ # +sdone+:: Already summarized short style options keyed hash.
363
+ # +ldone+:: Already summarized long style options keyed hash.
364
+ # +width+:: Width of left side (option part). In other words, the right
365
+ # side (description part) starts after +width+ columns.
366
+ # +max+:: Maximum width of left side -> the options are filled within
367
+ # +max+ columns.
368
+ # +indent+:: Prefix string indents all summarized lines.
369
+ #
370
+ def summarize(sdone = [], ldone = [], width = 1, max = width - 1, indent = "")
371
+ sopts, lopts, s = [], [], nil
372
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
373
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
374
+ return if sopts.empty? and lopts.empty? # completely hidden
375
+
376
+ left = [sopts.join(', ')]
377
+ right = desc.dup
378
+
379
+ while s = lopts.shift
380
+ l = left[-1].length + s.length
381
+ l += arg.length if left.size == 1 && arg
382
+ l < max or sopts.empty? or left << ''
383
+ left[-1] << if left[-1].empty? then ' ' * 4 else ', ' end << s
384
+ end
385
+
386
+ left[0] << arg if arg
387
+ mlen = left.collect {|s| s.length}.max.to_i
388
+ while mlen > width and l = left.shift
389
+ mlen = left.collect {|s| s.length}.max.to_i if l.length == mlen
390
+ yield(indent + l)
391
+ end
392
+
393
+ while begin l = left.shift; r = right.shift; l or r end
394
+ l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
395
+ yield(indent + l)
396
+ end
397
+
398
+ self
399
+ end
400
+
401
+ def add_banner(to) # :nodoc:
402
+ unless @short or @long
403
+ s = desc.join
404
+ to << " [" + s + "]..." unless s.empty?
405
+ end
406
+ to
407
+ end
408
+
409
+ def match_nonswitch?(str) # :nodoc:
410
+ @pattern =~ str unless @short or @long
411
+ end
412
+
413
+ #
414
+ # Main name of the switch.
415
+ #
416
+ def switch_name
417
+ (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
418
+ end
419
+
420
+ #
421
+ # Switch that takes no arguments.
422
+ #
423
+ class NoArgument < self
424
+
425
+ #
426
+ # Raises an exception if any arguments given.
427
+ #
428
+ def parse(arg, argv)
429
+ yield(NeedlessArgument, arg) if arg
430
+ conv_arg(arg)
431
+ end
432
+
433
+ def self.incompatible_argument_styles(*)
434
+ end
435
+
436
+ def self.pattern
437
+ Object
438
+ end
439
+ end
440
+
441
+ #
442
+ # Switch that takes an argument.
443
+ #
444
+ class RequiredArgument < self
445
+
446
+ #
447
+ # Raises an exception if argument is not present.
448
+ #
449
+ def parse(arg, argv)
450
+ unless arg
451
+ raise MissingArgument if argv.empty?
452
+ arg = argv.shift
453
+ end
454
+ conv_arg(*parse_arg(arg) {|*exc| raise(*exc)})
455
+ end
456
+ end
457
+
458
+ #
459
+ # Switch that can omit argument.
460
+ #
461
+ class OptionalArgument < self
462
+
463
+ #
464
+ # Parses argument if given, or uses default value.
465
+ #
466
+ def parse(arg, argv, &error)
467
+ if arg
468
+ conv_arg(*parse_arg(arg, &error))
469
+ else
470
+ conv_arg(arg)
471
+ end
472
+ end
473
+ end
474
+
475
+ #
476
+ # Switch that takes an argument, which does not begin with '-'.
477
+ #
478
+ class PlacedArgument < self
479
+
480
+ #
481
+ # Returns nil if argument is not present or begins with '-'.
482
+ #
483
+ def parse(arg, argv, &error)
484
+ if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
485
+ return nil, block, nil
486
+ end
487
+ opt = (val = parse_arg(val, &error))[1]
488
+ val = conv_arg(*val)
489
+ if opt and !arg
490
+ argv.shift
491
+ else
492
+ val[0] = nil
493
+ end
494
+ val
495
+ end
496
+ end
497
+ end
498
+
499
+ #
500
+ # Simple option list providing mapping from short and/or long option
501
+ # string to OptionParser::Switch and mapping from acceptable argument to
502
+ # matching pattern and converter pair. Also provides summary feature.
503
+ #
504
+ class List
505
+ # Map from acceptable argument types to pattern and converter pairs.
506
+ attr_reader :atype
507
+
508
+ # Map from short style option switches to actual switch objects.
509
+ attr_reader :short
510
+
511
+ # Map from long style option switches to actual switch objects.
512
+ attr_reader :long
513
+
514
+ # List of all switches and summary string.
515
+ attr_reader :list
516
+
517
+ #
518
+ # Just initializes all instance variables.
519
+ #
520
+ def initialize
521
+ @atype = {}
522
+ @short = OptionMap.new
523
+ @long = OptionMap.new
524
+ @list = []
525
+ end
526
+
527
+ #
528
+ # See OptionParser.accept.
529
+ #
530
+ def accept(t, pat = /.*/nm, &block)
531
+ if pat
532
+ pat.respond_to?(:match) or raise TypeError, "has no `match'"
533
+ else
534
+ pat = t if t.respond_to?(:match)
535
+ end
536
+ unless block
537
+ block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
538
+ end
539
+ @atype[t] = [pat, block]
540
+ end
541
+
542
+ #
543
+ # See OptionParser.reject.
544
+ #
545
+ def reject(t)
546
+ @atype.delete(t)
547
+ end
548
+
549
+ #
550
+ # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
551
+ #
552
+ # +sw+:: OptionParser::Switch instance to be added.
553
+ # +sopts+:: Short style option list.
554
+ # +lopts+:: Long style option list.
555
+ # +nlopts+:: Negated long style options list.
556
+ #
557
+ def update(sw, sopts, lopts, nsw = nil, nlopts = nil)
558
+ o = nil
559
+ sopts.each {|o| @short[o] = sw} if sopts
560
+ lopts.each {|o| @long[o] = sw} if lopts
561
+ nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
562
+ used = @short.invert.update(@long.invert)
563
+ @list.delete_if {|o| Switch === o and !used[o]}
564
+ end
565
+ private :update
566
+
567
+ #
568
+ # Inserts +switch+ at the head of the list, and associates short, long
569
+ # and negated long options. Arguments are:
570
+ #
571
+ # +switch+:: OptionParser::Switch instance to be inserted.
572
+ # +short_opts+:: List of short style options.
573
+ # +long_opts+:: List of long style options.
574
+ # +nolong_opts+:: List of long style options with "no-" prefix.
575
+ #
576
+ # prepend(switch, short_opts, long_opts, nolong_opts)
577
+ #
578
+ def prepend(*args)
579
+ update(*args)
580
+ @list.unshift(args[0])
581
+ end
582
+
583
+ #
584
+ # Appends +switch+ at the tail of the list, and associates short, long
585
+ # and negated long options. Arguments are:
586
+ #
587
+ # +switch+:: OptionParser::Switch instance to be inserted.
588
+ # +short_opts+:: List of short style options.
589
+ # +long_opts+:: List of long style options.
590
+ # +nolong_opts+:: List of long style options with "no-" prefix.
591
+ #
592
+ # append(switch, short_opts, long_opts, nolong_opts)
593
+ #
594
+ def append(*args)
595
+ update(*args)
596
+ @list.push(args[0])
597
+ end
598
+
599
+ #
600
+ # Searches +key+ in +id+ list. The result is returned or yielded if a
601
+ # block is given. If it isn't found, nil is returned.
602
+ #
603
+ def search(id, key)
604
+ if list = __send__(id)
605
+ val = list.fetch(key) {return nil}
606
+ block_given? ? yield(val) : val
607
+ end
608
+ end
609
+
610
+ #
611
+ # Searches list +id+ for +opt+ and the optional patterns for completion
612
+ # +pat+. If +icase+ is true, the search is case insensitive. The result
613
+ # is returned or yielded if a block is given. If it isn't found, nil is
614
+ # returned.
615
+ #
616
+ def complete(id, opt, icase = false, *pat, &block)
617
+ __send__(id).complete(opt, icase, *pat, &block)
618
+ end
619
+
620
+ #
621
+ # Iterates over each option, passing the option to the +block+.
622
+ #
623
+ def each_option(&block)
624
+ list.each(&block)
625
+ end
626
+
627
+ #
628
+ # Creates the summary table, passing each line to the +block+ (without
629
+ # newline). The arguments +args+ are passed along to the summarize
630
+ # method which is called on every option.
631
+ #
632
+ def summarize(*args, &block)
633
+ sum = []
634
+ list.reverse_each do |opt|
635
+ if opt.respond_to?(:summarize) # perhaps OptionParser::Switch
636
+ s = []
637
+ opt.summarize(*args) {|l| s << l}
638
+ sum.concat(s.reverse)
639
+ elsif !opt or opt.empty?
640
+ sum << ""
641
+ elsif opt.respond_to?(:each_line)
642
+ sum.concat([*opt.each_line].reverse)
643
+ else
644
+ sum.concat([*opt.each].reverse)
645
+ end
646
+ end
647
+ sum.reverse_each(&block)
648
+ end
649
+
650
+ def add_banner(to) # :nodoc:
651
+ list.each do |opt|
652
+ if opt.respond_to?(:add_banner)
653
+ opt.add_banner(to)
654
+ end
655
+ end
656
+ to
657
+ end
658
+ end
659
+
660
+ #
661
+ # Hash with completion search feature. See OptionParser::Completion.
662
+ #
663
+ class CompletingHash < Hash
664
+ include Completion
665
+
666
+ #
667
+ # Completion for hash key.
668
+ #
669
+ def match(key)
670
+ return key, *fetch(key) {
671
+ raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
672
+ }
673
+ end
674
+ end
675
+
676
+ # :stopdoc:
677
+
678
+ #
679
+ # Enumeration of acceptable argument styles. Possible values are:
680
+ #
681
+ # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
682
+ # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
683
+ # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
684
+ #
685
+ # Use like --switch=argument (long style) or -Xargument (short style). For
686
+ # short style, only portion matched to argument pattern is dealed as
687
+ # argument.
688
+ #
689
+ ArgumentStyle = {}
690
+ NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
691
+ RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
692
+ OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument}
693
+ ArgumentStyle.freeze
694
+
695
+ #
696
+ # Switches common used such as '--', and also provides default
697
+ # argument classes
698
+ #
699
+ DefaultList = List.new
700
+ DefaultList.short['-'] = Switch::NoArgument.new {}
701
+ DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
702
+
703
+ #
704
+ # Default options for ARGV, which never appear in option summary.
705
+ #
706
+ Officious = {}
707
+
708
+ #
709
+ # --help
710
+ # Shows option summary.
711
+ #
712
+ Officious['help'] = proc do |parser|
713
+ Switch::NoArgument.new do
714
+ puts parser.help
715
+ exit
716
+ end
717
+ end
718
+
719
+ #
720
+ # --version
721
+ # Shows version string if Version is defined.
722
+ #
723
+ Officious['version'] = proc do |parser|
724
+ Switch::OptionalArgument.new do |pkg|
725
+ if pkg
726
+ begin
727
+ require 'optparse/version'
728
+ rescue LoadError
729
+ else
730
+ show_version(*pkg.split(/,/)) or
731
+ abort("#{parser.program_name}: no version found in package #{pkg}")
732
+ exit
733
+ end
734
+ end
735
+ v = parser.ver or abort("#{parser.program_name}: version unknown")
736
+ puts v
737
+ exit
738
+ end
739
+ end
740
+
741
+ # :startdoc:
742
+
743
+ #
744
+ # Class methods
745
+ #
746
+
747
+ #
748
+ # Initializes a new instance and evaluates the optional block in context
749
+ # of the instance. Arguments +args+ are passed to #new, see there for
750
+ # description of parameters.
751
+ #
752
+ # This method is *deprecated*, its behavior corresponds to the older #new
753
+ # method.
754
+ #
755
+ def self.with(*args, &block)
756
+ opts = new(*args)
757
+ opts.instance_eval(&block)
758
+ opts
759
+ end
760
+
761
+ #
762
+ # Returns an incremented value of +default+ according to +arg+.
763
+ #
764
+ def self.inc(arg, default = nil)
765
+ case arg
766
+ when Integer
767
+ arg.nonzero?
768
+ when nil
769
+ default.to_i + 1
770
+ end
771
+ end
772
+ def inc(*args)
773
+ self.class.inc(*args)
774
+ end
775
+
776
+ #
777
+ # Initializes the instance and yields itself if called with a block.
778
+ #
779
+ # +banner+:: Banner message.
780
+ # +width+:: Summary width.
781
+ # +indent+:: Summary indent.
782
+ #
783
+ def initialize(banner = nil, width = 32, indent = ' ' * 4)
784
+ @stack = [DefaultList, List.new, List.new]
785
+ @program_name = nil
786
+ @banner = banner
787
+ @summary_width = width
788
+ @summary_indent = indent
789
+ @default_argv = ARGV
790
+ add_officious
791
+ yield self if block_given?
792
+ end
793
+
794
+ def add_officious # :nodoc:
795
+ list = base()
796
+ Officious.each do |opt, block|
797
+ list.long[opt] ||= block.call(self)
798
+ end
799
+ end
800
+
801
+ #
802
+ # Terminates option parsing. Optional parameter +arg+ is a string pushed
803
+ # back to be the first non-option argument.
804
+ #
805
+ def terminate(arg = nil)
806
+ self.class.terminate(arg)
807
+ end
808
+ def self.terminate(arg = nil)
809
+ throw :terminate, arg
810
+ end
811
+
812
+ @stack = [DefaultList]
813
+ def self.top() DefaultList end
814
+
815
+ #
816
+ # Directs to accept specified class +t+. The argument string is passed to
817
+ # the block in which it should be converted to the desired class.
818
+ #
819
+ # +t+:: Argument class specifier, any object including Class.
820
+ # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
821
+ #
822
+ # accept(t, pat, &block)
823
+ #
824
+ def accept(*args, &blk) top.accept(*args, &blk) end
825
+ #
826
+ # See #accept.
827
+ #
828
+ def self.accept(*args, &blk) top.accept(*args, &blk) end
829
+
830
+ #
831
+ # Directs to reject specified class argument.
832
+ #
833
+ # +t+:: Argument class specifier, any object including Class.
834
+ #
835
+ # reject(t)
836
+ #
837
+ def reject(*args, &blk) top.reject(*args, &blk) end
838
+ #
839
+ # See #reject.
840
+ #
841
+ def self.reject(*args, &blk) top.reject(*args, &blk) end
842
+
843
+ #
844
+ # Instance methods
845
+ #
846
+
847
+ # Heading banner preceding summary.
848
+ attr_writer :banner
849
+
850
+ # Program name to be emitted in error message and default banner,
851
+ # defaults to $0.
852
+ attr_writer :program_name
853
+
854
+ # Width for option list portion of summary. Must be Numeric.
855
+ attr_accessor :summary_width
856
+
857
+ # Indentation for summary. Must be String (or have + String method).
858
+ attr_accessor :summary_indent
859
+
860
+ # Strings to be parsed in default.
861
+ attr_accessor :default_argv
862
+
863
+ #
864
+ # Heading banner preceding summary.
865
+ #
866
+ def banner
867
+ unless @banner
868
+ @banner = "Usage: #{program_name} [options]"
869
+ visit(:add_banner, @banner)
870
+ end
871
+ @banner
872
+ end
873
+
874
+ #
875
+ # Program name to be emitted in error message and default banner, defaults
876
+ # to $0.
877
+ #
878
+ def program_name
879
+ @program_name || File.basename($0, '.*')
880
+ end
881
+
882
+ # for experimental cascading :-)
883
+ alias set_banner banner=
884
+ alias set_program_name program_name=
885
+ alias set_summary_width summary_width=
886
+ alias set_summary_indent summary_indent=
887
+
888
+ # Version
889
+ attr_writer :version
890
+ # Release code
891
+ attr_writer :release
892
+
893
+ #
894
+ # Version
895
+ #
896
+ def version
897
+ @version || (defined?(::Version) && ::Version)
898
+ end
899
+
900
+ #
901
+ # Release code
902
+ #
903
+ def release
904
+ @release || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
905
+ end
906
+
907
+ #
908
+ # Returns version string from program_name, version and release.
909
+ #
910
+ def ver
911
+ if v = version
912
+ str = "#{program_name} #{[v].join('.')}"
913
+ str << " (#{v})" if v = release
914
+ str
915
+ end
916
+ end
917
+
918
+ def warn(mesg = $!)
919
+ super("#{program_name}: #{mesg}")
920
+ end
921
+
922
+ def abort(mesg = $!)
923
+ super("#{program_name}: #{mesg}")
924
+ end
925
+
926
+ #
927
+ # Subject of #on / #on_head, #accept / #reject
928
+ #
929
+ def top
930
+ @stack[-1]
931
+ end
932
+
933
+ #
934
+ # Subject of #on_tail.
935
+ #
936
+ def base
937
+ @stack[1]
938
+ end
939
+
940
+ #
941
+ # Pushes a new List.
942
+ #
943
+ def new
944
+ @stack.push(List.new)
945
+ if block_given?
946
+ yield self
947
+ else
948
+ self
949
+ end
950
+ end
951
+
952
+ #
953
+ # Removes the last List.
954
+ #
955
+ def remove
956
+ @stack.pop
957
+ end
958
+
959
+ #
960
+ # Puts option summary into +to+ and returns +to+. Yields each line if
961
+ # a block is given.
962
+ #
963
+ # +to+:: Output destination, which must have method <<. Defaults to [].
964
+ # +width+:: Width of left side, defaults to @summary_width.
965
+ # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
966
+ # +indent+:: Indentation, defaults to @summary_indent.
967
+ #
968
+ def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
969
+ blk ||= proc {|l| to << (l.index($/, -1) ? l : l + $/)}
970
+ visit(:summarize, {}, {}, width, max, indent, &blk)
971
+ to
972
+ end
973
+
974
+ #
975
+ # Returns option summary string.
976
+ #
977
+ def help; summarize(banner.to_s.sub(/\n?\z/, "\n")) end
978
+ alias to_s help
979
+
980
+ #
981
+ # Returns option summary list.
982
+ #
983
+ def to_a; summarize(banner.to_a.dup) end
984
+
985
+ #
986
+ # Checks if an argument is given twice, in which case an ArgumentError is
987
+ # raised. Called from OptionParser#switch only.
988
+ #
989
+ # +obj+:: New argument.
990
+ # +prv+:: Previously specified argument.
991
+ # +msg+:: Exception message.
992
+ #
993
+ def notwice(obj, prv, msg)
994
+ unless !prv or prv == obj
995
+ begin
996
+ raise ArgumentError, "argument #{msg} given twice: #{obj}"
997
+ rescue
998
+ $@[0, 2] = nil
999
+ raise
1000
+ end
1001
+ end
1002
+ obj
1003
+ end
1004
+ private :notwice
1005
+
1006
+ #
1007
+ # Creates an OptionParser::Switch from the parameters. The parsed argument
1008
+ # value is passed to the given block, where it can be processed.
1009
+ #
1010
+ # See at the beginning of OptionParser for some full examples.
1011
+ #
1012
+ # +opts+ can include the following elements:
1013
+ #
1014
+ # [Argument style:]
1015
+ # One of the following:
1016
+ # :NONE, :REQUIRED, :OPTIONAL
1017
+ #
1018
+ # [Argument pattern:]
1019
+ # Acceptable option argument format, must be pre-defined with
1020
+ # OptionParser.accept or OptionParser#accept, or Regexp. This can appear
1021
+ # once or assigned as String if not present, otherwise causes an
1022
+ # ArgumentError. Examples:
1023
+ # Float, Time, Array
1024
+ #
1025
+ # [Possible argument values:]
1026
+ # Hash or Array.
1027
+ # [:text, :binary, :auto]
1028
+ # %w[iso-2022-jp shift_jis euc-jp utf8 binary]
1029
+ # { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
1030
+ #
1031
+ # [Long style switch:]
1032
+ # Specifies a long style switch which takes a mandatory, optional or no
1033
+ # argument. It's a string of the following form:
1034
+ # "--switch=MANDATORY" or "--switch MANDATORY"
1035
+ # "--switch[=OPTIONAL]"
1036
+ # "--switch"
1037
+ #
1038
+ # [Short style switch:]
1039
+ # Specifies short style switch which takes a mandatory, optional or no
1040
+ # argument. It's a string of the following form:
1041
+ # "-xMANDATORY"
1042
+ # "-x[OPTIONAL]"
1043
+ # "-x"
1044
+ # There is also a special form which matches character range (not full
1045
+ # set of regular expression):
1046
+ # "-[a-z]MANDATORY"
1047
+ # "-[a-z][OPTIONAL]"
1048
+ # "-[a-z]"
1049
+ #
1050
+ # [Argument style and description:]
1051
+ # Instead of specifying mandatory or optional arguments directly in the
1052
+ # switch parameter, this separate parameter can be used.
1053
+ # "=MANDATORY"
1054
+ # "=[OPTIONAL]"
1055
+ #
1056
+ # [Description:]
1057
+ # Description string for the option.
1058
+ # "Run verbosely"
1059
+ #
1060
+ # [Handler:]
1061
+ # Handler for the parsed argument value. Either give a block or pass a
1062
+ # Proc or Method as an argument.
1063
+ #
1064
+ def make_switch(opts, block = nil)
1065
+ short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
1066
+ ldesc, sdesc, desc, arg = [], [], []
1067
+ default_style = Switch::NoArgument
1068
+ default_pattern = nil
1069
+ klass = nil
1070
+ o = nil
1071
+ n, q, a = nil
1072
+
1073
+ opts.each do |o|
1074
+ # argument class
1075
+ next if search(:atype, o) do |pat, c|
1076
+ klass = notwice(o, klass, 'type')
1077
+ if not_style and not_style != Switch::NoArgument
1078
+ not_pattern, not_conv = pat, c
1079
+ else
1080
+ default_pattern, conv = pat, c
1081
+ end
1082
+ end
1083
+
1084
+ # directly specified pattern(any object possible to match)
1085
+ if !(String === o) and o.respond_to?(:match)
1086
+ pattern = notwice(o, pattern, 'pattern')
1087
+ conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
1088
+ next
1089
+ end
1090
+
1091
+ # anything others
1092
+ case o
1093
+ when Proc, Method
1094
+ block = notwice(o, block, 'block')
1095
+ when Array, Hash
1096
+ case pattern
1097
+ when CompletingHash
1098
+ when nil
1099
+ pattern = CompletingHash.new
1100
+ conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
1101
+ else
1102
+ raise ArgumentError, "argument pattern given twice"
1103
+ end
1104
+ o.each {|(o, *v)| pattern[o] = v.fetch(0) {o}}
1105
+ when Module
1106
+ raise ArgumentError, "unsupported argument type: #{o}"
1107
+ when *ArgumentStyle.keys
1108
+ style = notwice(ArgumentStyle[o], style, 'style')
1109
+ when /^--no-([^\[\]=\s]*)(.+)?/
1110
+ q, a = $1, $2
1111
+ o = notwice(a ? Object : TrueClass, klass, 'type')
1112
+ not_pattern, not_conv = search(:atype, o) unless not_style
1113
+ not_style = (not_style || default_style).guess(arg = a) if a
1114
+ default_style = Switch::NoArgument
1115
+ default_pattern, conv = search(:atype, FalseClass) unless default_pattern
1116
+ ldesc << "--no-#{q}"
1117
+ long << 'no-' + (q = q.downcase)
1118
+ nolong << q
1119
+ when /^--\[no-\]([^\[\]=\s]*)(.+)?/
1120
+ q, a = $1, $2
1121
+ o = notwice(a ? Object : TrueClass, klass, 'type')
1122
+ if a
1123
+ default_style = default_style.guess(arg = a)
1124
+ default_pattern, conv = search(:atype, o) unless default_pattern
1125
+ end
1126
+ ldesc << "--[no-]#{q}"
1127
+ long << (o = q.downcase)
1128
+ not_pattern, not_conv = search(:atype, FalseClass) unless not_style
1129
+ not_style = Switch::NoArgument
1130
+ nolong << 'no-' + o
1131
+ when /^--([^\[\]=\s]*)(.+)?/
1132
+ q, a = $1, $2
1133
+ if a
1134
+ o = notwice(NilClass, klass, 'type')
1135
+ default_style = default_style.guess(arg = a)
1136
+ default_pattern, conv = search(:atype, o) unless default_pattern
1137
+ end
1138
+ ldesc << "--#{q}"
1139
+ long << (o = q.downcase)
1140
+ when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
1141
+ q, a = $1, $2
1142
+ o = notwice(Object, klass, 'type')
1143
+ if a
1144
+ default_style = default_style.guess(arg = a)
1145
+ default_pattern, conv = search(:atype, o) unless default_pattern
1146
+ end
1147
+ sdesc << "-#{q}"
1148
+ short << Regexp.new(q)
1149
+ when /^-(.)(.+)?/
1150
+ q, a = $1, $2
1151
+ if a
1152
+ o = notwice(NilClass, klass, 'type')
1153
+ default_style = default_style.guess(arg = a)
1154
+ default_pattern, conv = search(:atype, o) unless default_pattern
1155
+ end
1156
+ sdesc << "-#{q}"
1157
+ short << q
1158
+ when /^=/
1159
+ style = notwice(default_style.guess(arg = o), style, 'style')
1160
+ default_pattern, conv = search(:atype, Object) unless default_pattern
1161
+ else
1162
+ desc.push(o)
1163
+ end
1164
+ end
1165
+
1166
+ default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
1167
+ if !(short.empty? and long.empty?)
1168
+ s = (style || default_style).new(pattern || default_pattern,
1169
+ conv, sdesc, ldesc, arg, desc, block)
1170
+ elsif !block
1171
+ raise ArgumentError, "no switch given" if style or pattern
1172
+ s = desc
1173
+ else
1174
+ short << pattern
1175
+ s = (style || default_style).new(pattern,
1176
+ conv, nil, nil, arg, desc, block)
1177
+ end
1178
+ return s, short, long,
1179
+ (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
1180
+ nolong
1181
+ end
1182
+
1183
+ def define(*opts, &block)
1184
+ top.append(*(sw = make_switch(opts, block)))
1185
+ sw[0]
1186
+ end
1187
+
1188
+ #
1189
+ # Add option switch and handler. See #make_switch for an explanation of
1190
+ # parameters.
1191
+ #
1192
+ def on(*opts, &block)
1193
+ define(*opts, &block)
1194
+ self
1195
+ end
1196
+ alias def_option define
1197
+
1198
+ def define_head(*opts, &block)
1199
+ top.prepend(*(sw = make_switch(opts, block)))
1200
+ sw[0]
1201
+ end
1202
+
1203
+ #
1204
+ # Add option switch like with #on, but at head of summary.
1205
+ #
1206
+ def on_head(*opts, &block)
1207
+ define_head(*opts, &block)
1208
+ self
1209
+ end
1210
+ alias def_head_option define_head
1211
+
1212
+ def define_tail(*opts, &block)
1213
+ base.append(*(sw = make_switch(opts, block)))
1214
+ sw[0]
1215
+ end
1216
+
1217
+ #
1218
+ # Add option switch like with #on, but at tail of summary.
1219
+ #
1220
+ def on_tail(*opts, &block)
1221
+ define_tail(*opts, &block)
1222
+ self
1223
+ end
1224
+ alias def_tail_option define_tail
1225
+
1226
+ #
1227
+ # Add separator in summary.
1228
+ #
1229
+ def separator(string)
1230
+ top.append(string, nil, nil)
1231
+ end
1232
+
1233
+ #
1234
+ # Parses command line arguments +argv+ in order. When a block is given,
1235
+ # each non-option argument is yielded.
1236
+ #
1237
+ # Returns the rest of +argv+ left unparsed.
1238
+ #
1239
+ def order(*argv, &block)
1240
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1241
+ order!(argv, &block)
1242
+ end
1243
+
1244
+ #
1245
+ # Same as #order, but removes switches destructively.
1246
+ #
1247
+ def order!(argv = default_argv, &nonopt)
1248
+ parse_in_order(argv, &nonopt)
1249
+ end
1250
+
1251
+ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
1252
+ opt, arg, sw, val, rest = nil
1253
+ nonopt ||= proc {|arg| throw :terminate, arg}
1254
+ argv.unshift(arg) if arg = catch(:terminate) {
1255
+ while arg = argv.shift
1256
+ case arg
1257
+ # long option
1258
+ when /\A--([^=]*)(?:=(.*))?/nm
1259
+ opt, rest = $1, $2
1260
+ begin
1261
+ sw, = complete(:long, opt, true)
1262
+ rescue ParseError
1263
+ raise $!.set_option(arg, true)
1264
+ end
1265
+ begin
1266
+ opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
1267
+ val = cb.call(val) if cb
1268
+ setter.call(sw.switch_name, val) if setter
1269
+ rescue ParseError
1270
+ raise $!.set_option(arg, rest)
1271
+ end
1272
+
1273
+ # short option
1274
+ when /\A-(.)((=).*|.+)?/nm
1275
+ opt, has_arg, eq, val, rest = $1, $3, $3, $2, $2
1276
+ begin
1277
+ sw, = search(:short, opt)
1278
+ unless sw
1279
+ begin
1280
+ sw, = complete(:short, opt)
1281
+ # short option matched.
1282
+ val = arg.sub(/\A-/, '')
1283
+ has_arg = true
1284
+ rescue InvalidOption
1285
+ # if no short options match, try completion with long
1286
+ # options.
1287
+ sw, = complete(:long, opt)
1288
+ eq ||= !rest
1289
+ end
1290
+ end
1291
+ rescue ParseError
1292
+ raise $!.set_option(arg, true)
1293
+ end
1294
+ begin
1295
+ opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
1296
+ raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
1297
+ argv.unshift(opt) if opt and (opt = opt.sub(/\A-*/, '-')) != '-'
1298
+ val = cb.call(val) if cb
1299
+ setter.call(sw.switch_name, val) if setter
1300
+ rescue ParseError
1301
+ raise $!.set_option(arg, arg.length > 2)
1302
+ end
1303
+
1304
+ # non-option argument
1305
+ else
1306
+ catch(:prune) do
1307
+ visit(:each_option) do |sw|
1308
+ sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
1309
+ end
1310
+ nonopt.call(arg)
1311
+ end
1312
+ end
1313
+ end
1314
+
1315
+ nil
1316
+ }
1317
+
1318
+ visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
1319
+
1320
+ argv
1321
+ end
1322
+ private :parse_in_order
1323
+
1324
+ #
1325
+ # Parses command line arguments +argv+ in permutation mode and returns
1326
+ # list of non-option arguments.
1327
+ #
1328
+ def permute(*argv)
1329
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1330
+ permute!(argv)
1331
+ end
1332
+
1333
+ #
1334
+ # Same as #permute, but removes switches destructively.
1335
+ #
1336
+ def permute!(argv = default_argv)
1337
+ nonopts = []
1338
+ arg = nil
1339
+ order!(argv) {|arg| nonopts << arg}
1340
+ argv[0, 0] = nonopts
1341
+ argv
1342
+ end
1343
+
1344
+ #
1345
+ # Parses command line arguments +argv+ in order when environment variable
1346
+ # POSIXLY_CORRECT is set, and in permutation mode otherwise.
1347
+ #
1348
+ def parse(*argv)
1349
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1350
+ parse!(argv)
1351
+ end
1352
+
1353
+ #
1354
+ # Same as #parse, but removes switches destructively.
1355
+ #
1356
+ def parse!(argv = default_argv)
1357
+ if ENV.include?('POSIXLY_CORRECT')
1358
+ order!(argv)
1359
+ else
1360
+ permute!(argv)
1361
+ end
1362
+ end
1363
+
1364
+ #
1365
+ # Wrapper method for getopts.rb.
1366
+ #
1367
+ # params = ARGV.getopts("ab:", "foo", "bar:")
1368
+ # # params[:a] = true # -a
1369
+ # # params[:b] = "1" # -b1
1370
+ # # params[:foo] = "1" # --foo
1371
+ # # params[:bar] = "x" # --bar x
1372
+ #
1373
+ def getopts(*args)
1374
+ argv = Array === args.first ? args.shift : default_argv
1375
+ single_options, *long_options = *args
1376
+
1377
+ result = {}
1378
+
1379
+ single_options.scan(/(.)(:)?/) do |opt, val|
1380
+ if val
1381
+ result[opt] = nil
1382
+ define("-#{opt} VAL")
1383
+ else
1384
+ result[opt] = false
1385
+ define("-#{opt}")
1386
+ end
1387
+ end if single_options
1388
+
1389
+ long_options.each do |arg|
1390
+ opt, val = arg.split(':', 2)
1391
+ if val
1392
+ result[opt] = val.empty? ? nil : val
1393
+ define("--#{opt} VAL")
1394
+ else
1395
+ result[opt] = false
1396
+ define("--#{opt}")
1397
+ end
1398
+ end
1399
+
1400
+ parse_in_order(argv, result.method(:[]=))
1401
+ result
1402
+ end
1403
+
1404
+ #
1405
+ # See #getopts.
1406
+ #
1407
+ def self.getopts(*args)
1408
+ new.getopts(*args)
1409
+ end
1410
+
1411
+ #
1412
+ # Traverses @stack, sending each element method +id+ with +args+ and
1413
+ # +block+.
1414
+ #
1415
+ def visit(id, *args, &block)
1416
+ el = nil
1417
+ @stack.reverse_each do |el|
1418
+ el.send(id, *args, &block)
1419
+ end
1420
+ nil
1421
+ end
1422
+ private :visit
1423
+
1424
+ #
1425
+ # Searches +key+ in @stack for +id+ hash and returns or yields the result.
1426
+ #
1427
+ def search(id, key)
1428
+ block_given = block_given?
1429
+ visit(:search, id, key) do |k|
1430
+ return block_given ? yield(k) : k
1431
+ end
1432
+ end
1433
+ private :search
1434
+
1435
+ #
1436
+ # Completes shortened long style option switch and returns pair of
1437
+ # canonical switch and switch descriptor OptionParser::Switch.
1438
+ #
1439
+ # +id+:: Searching table.
1440
+ # +opt+:: Searching key.
1441
+ # +icase+:: Search case insensitive if true.
1442
+ # +pat+:: Optional pattern for completion.
1443
+ #
1444
+ def complete(typ, opt, icase = false, *pat)
1445
+ if pat.empty?
1446
+ search(typ, opt) {|sw| return [sw, opt]} # exact match or...
1447
+ end
1448
+ raise AmbiguousOption, catch(:ambiguous) {
1449
+ visit(:complete, typ, opt, icase, *pat) {|opt, *sw| return sw}
1450
+ raise InvalidOption, opt
1451
+ }
1452
+ end
1453
+ private :complete
1454
+
1455
+ #
1456
+ # Loads options from file names as +filename+. Does nothing when the file
1457
+ # is not present. Returns whether successfully loaded.
1458
+ #
1459
+ # +filename+ defaults to basename of the program without suffix in a
1460
+ # directory ~/.options.
1461
+ #
1462
+ def load(filename = nil)
1463
+ begin
1464
+ filename ||= File.expand_path(File.basename($0, '.*'), '~/.options')
1465
+ rescue
1466
+ return false
1467
+ end
1468
+ begin
1469
+ parse(*IO.readlines(filename).each {|s| s.chomp!})
1470
+ true
1471
+ rescue Errno::ENOENT, Errno::ENOTDIR
1472
+ false
1473
+ end
1474
+ end
1475
+
1476
+ #
1477
+ # Parses environment variable +env+ or its uppercase with splitting like a
1478
+ # shell.
1479
+ #
1480
+ # +env+ defaults to the basename of the program.
1481
+ #
1482
+ def environment(env = File.basename($0, '.*'))
1483
+ env = ENV[env] || ENV[env.upcase] or return
1484
+ require 'shellwords'
1485
+ parse(*Shellwords.shellwords(env))
1486
+ end
1487
+
1488
+ #
1489
+ # Acceptable argument classes
1490
+ #
1491
+
1492
+ #
1493
+ # Any string and no conversion. This is fall-back.
1494
+ #
1495
+ accept(Object) {|s,|s or s.nil?}
1496
+
1497
+ accept(NilClass) {|s,|s}
1498
+
1499
+ #
1500
+ # Any non-empty string, and no conversion.
1501
+ #
1502
+ accept(String, /.+/nm) {|s,*|s}
1503
+
1504
+ #
1505
+ # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
1506
+ # for 0x, and decimal for others; with optional sign prefix. Converts to
1507
+ # Integer.
1508
+ #
1509
+ decimal = '\d+(?:_\d+)*'
1510
+ binary = 'b[01]+(?:_[01]+)*'
1511
+ hex = 'x[\da-f]+(?:_[\da-f]+)*'
1512
+ octal = "0(?:[0-7]*(?:_[0-7]+)*|#{binary}|#{hex})"
1513
+ integer = "#{octal}|#{decimal}"
1514
+ accept(Integer, %r"\A[-+]?(?:#{integer})"io) {|s,| Integer(s) if s}
1515
+
1516
+ #
1517
+ # Float number format, and converts to Float.
1518
+ #
1519
+ float = "(?:#{decimal}(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
1520
+ floatpat = %r"\A[-+]?#{float}"io
1521
+ accept(Float, floatpat) {|s,| s.to_f if s}
1522
+
1523
+ #
1524
+ # Generic numeric format, converts to Integer for integer format, Float
1525
+ # for float format.
1526
+ #
1527
+ accept(Numeric, %r"\A[-+]?(?:#{octal}|#{float})"io) {|s,| eval(s) if s}
1528
+
1529
+ #
1530
+ # Decimal integer format, to be converted to Integer.
1531
+ #
1532
+ DecimalInteger = /\A[-+]?#{decimal}/io
1533
+ accept(DecimalInteger) {|s,| s.to_i if s}
1534
+
1535
+ #
1536
+ # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
1537
+ # Integer.
1538
+ #
1539
+ OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))/io
1540
+ accept(OctalInteger) {|s,| s.oct if s}
1541
+
1542
+ #
1543
+ # Decimal integer/float number format, to be converted to Integer for
1544
+ # integer format, Float for float format.
1545
+ #
1546
+ DecimalNumeric = floatpat # decimal integer is allowed as float also.
1547
+ accept(DecimalNumeric) {|s,| eval(s) if s}
1548
+
1549
+ #
1550
+ # Boolean switch, which means whether it is present or not, whether it is
1551
+ # absent or not with prefix no-, or it takes an argument
1552
+ # yes/no/true/false/+/-.
1553
+ #
1554
+ yesno = CompletingHash.new
1555
+ %w[- no false].each {|el| yesno[el] = false}
1556
+ %w[+ yes true].each {|el| yesno[el] = true}
1557
+ yesno['nil'] = false # shoud be nil?
1558
+ accept(TrueClass, yesno) {|arg, val| val == nil or val}
1559
+ #
1560
+ # Similar to TrueClass, but defaults to false.
1561
+ #
1562
+ accept(FalseClass, yesno) {|arg, val| val != nil and val}
1563
+
1564
+ #
1565
+ # List of strings separated by ",".
1566
+ #
1567
+ accept(Array) do |s,|
1568
+ if s
1569
+ s = s.split(',').collect {|s| s unless s.empty?}
1570
+ end
1571
+ s
1572
+ end
1573
+
1574
+ #
1575
+ # Regular expression with options.
1576
+ #
1577
+ accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
1578
+ f = 0
1579
+ if o
1580
+ f |= Regexp::IGNORECASE if /i/ =~ o
1581
+ f |= Regexp::MULTILINE if /m/ =~ o
1582
+ f |= Regexp::EXTENDED if /x/ =~ o
1583
+ k = o.delete("^imx")
1584
+ end
1585
+ Regexp.new(s || all, f, k)
1586
+ end
1587
+
1588
+ #
1589
+ # Exceptions
1590
+ #
1591
+
1592
+ #
1593
+ # Base class of exceptions from OptionParser.
1594
+ #
1595
+ class ParseError < RuntimeError
1596
+ # Reason which caused the error.
1597
+ Reason = 'parse error'.freeze
1598
+
1599
+ def initialize(*args)
1600
+ @args = args
1601
+ @reason = nil
1602
+ end
1603
+
1604
+ attr_reader :args
1605
+ attr_writer :reason
1606
+
1607
+ #
1608
+ # Pushes back erred argument(s) to +argv+.
1609
+ #
1610
+ def recover(argv)
1611
+ argv[0, 0] = @args
1612
+ argv
1613
+ end
1614
+
1615
+ def set_option(opt, eq)
1616
+ if eq
1617
+ @args[0] = opt
1618
+ else
1619
+ @args.unshift(opt)
1620
+ end
1621
+ self
1622
+ end
1623
+
1624
+ #
1625
+ # Returns error reason. Override this for I18N.
1626
+ #
1627
+ def reason
1628
+ @reason || self.class::Reason
1629
+ end
1630
+
1631
+ def inspect
1632
+ "#<#{self.class.to_s}: #{args.join(' ')}>"
1633
+ end
1634
+
1635
+ #
1636
+ # Default stringizing method to emit standard error message.
1637
+ #
1638
+ def message
1639
+ reason + ': ' + args.join(' ')
1640
+ end
1641
+
1642
+ alias to_s message
1643
+ end
1644
+
1645
+ #
1646
+ # Raises when ambiguously completable string is encountered.
1647
+ #
1648
+ class AmbiguousOption < ParseError
1649
+ const_set(:Reason, 'ambiguous option'.freeze)
1650
+ end
1651
+
1652
+ #
1653
+ # Raises when there is an argument for a switch which takes no argument.
1654
+ #
1655
+ class NeedlessArgument < ParseError
1656
+ const_set(:Reason, 'needless argument'.freeze)
1657
+ end
1658
+
1659
+ #
1660
+ # Raises when a switch with mandatory argument has no argument.
1661
+ #
1662
+ class MissingArgument < ParseError
1663
+ const_set(:Reason, 'missing argument'.freeze)
1664
+ end
1665
+
1666
+ #
1667
+ # Raises when switch is undefined.
1668
+ #
1669
+ class InvalidOption < ParseError
1670
+ const_set(:Reason, 'invalid option'.freeze)
1671
+ end
1672
+
1673
+ #
1674
+ # Raises when the given argument does not match required format.
1675
+ #
1676
+ class InvalidArgument < ParseError
1677
+ const_set(:Reason, 'invalid argument'.freeze)
1678
+ end
1679
+
1680
+ #
1681
+ # Raises when the given argument word can't be completed uniquely.
1682
+ #
1683
+ class AmbiguousArgument < InvalidArgument
1684
+ const_set(:Reason, 'ambiguous argument'.freeze)
1685
+ end
1686
+
1687
+ #
1688
+ # Miscellaneous
1689
+ #
1690
+
1691
+ #
1692
+ # Extends command line arguments array (ARGV) to parse itself.
1693
+ #
1694
+ module Arguable
1695
+
1696
+ #
1697
+ # Sets OptionParser object, when +opt+ is +false+ or +nil+, methods
1698
+ # OptionParser::Arguable#options and OptionParser::Arguable#options= are
1699
+ # undefined. Thus, there is no ways to access the OptionParser object
1700
+ # via the receiver object.
1701
+ #
1702
+ def options=(opt)
1703
+ unless @optparse = opt
1704
+ class << self
1705
+ undef_method(:options)
1706
+ undef_method(:options=)
1707
+ end
1708
+ end
1709
+ end
1710
+
1711
+ #
1712
+ # Actual OptionParser object, automatically created if nonexistent.
1713
+ #
1714
+ # If called with a block, yields the OptionParser object and returns the
1715
+ # result of the block. If an OptionParser::ParseError exception occurs
1716
+ # in the block, it is rescued, a error message printed to STDERR and
1717
+ # +nil+ returned.
1718
+ #
1719
+ def options
1720
+ @optparse ||= OptionParser.new
1721
+ @optparse.default_argv = self
1722
+ block_given? or return @optparse
1723
+ begin
1724
+ yield @optparse
1725
+ rescue ParseError
1726
+ @optparse.warn $!
1727
+ nil
1728
+ end
1729
+ end
1730
+
1731
+ #
1732
+ # Parses +self+ destructively in order and returns +self+ containing the
1733
+ # rest arguments left unparsed.
1734
+ #
1735
+ def order!(&blk) options.order!(self, &blk) end
1736
+
1737
+ #
1738
+ # Parses +self+ destructively in permutation mode and returns +self+
1739
+ # containing the rest arguments left unparsed.
1740
+ #
1741
+ def permute!() options.permute!(self) end
1742
+
1743
+ #
1744
+ # Parses +self+ destructively and returns +self+ containing the
1745
+ # rest arguments left unparsed.
1746
+ #
1747
+ def parse!() options.parse!(self) end
1748
+
1749
+ #
1750
+ # Substitution of getopts is possible as follows. Also see
1751
+ # OptionParser#getopts.
1752
+ #
1753
+ # def getopts(*args)
1754
+ # ($OPT = ARGV.getopts(*args)).each do |opt, val|
1755
+ # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
1756
+ # end
1757
+ # rescue OptionParser::ParseError
1758
+ # end
1759
+ #
1760
+ def getopts(*args)
1761
+ options.getopts(self, *args)
1762
+ end
1763
+
1764
+ #
1765
+ # Initializes instance variable.
1766
+ #
1767
+ def self.extend_object(obj)
1768
+ super
1769
+ obj.instance_eval {@optparse = nil}
1770
+ end
1771
+ def initialize(*args)
1772
+ super
1773
+ @optparse = nil
1774
+ end
1775
+ end
1776
+
1777
+ #
1778
+ # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
1779
+ # and DecimalNumeric. See Acceptable argument classes (in source code).
1780
+ #
1781
+ module Acceptables
1782
+ const_set(:DecimalInteger, OptionParser::DecimalInteger)
1783
+ const_set(:OctalInteger, OptionParser::OctalInteger)
1784
+ const_set(:DecimalNumeric, OptionParser::DecimalNumeric)
1785
+ end
1786
+ end
1787
+
1788
+ # ARGV is arguable by OptionParser
1789
+ ARGV.extend(OptionParser::Arguable)
1790
+
1791
+ if $0 == __FILE__
1792
+ Version = OptionParser::Version
1793
+ ARGV.options {|q|
1794
+ q.parse!.empty? or puts "what's #{ARGV.join(' ')}?"
1795
+ } or abort(ARGV.options.to_s)
1796
+ end