rubysl-optparse 1.0.0

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.
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