optparse 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8de11374b27b7f909eda2151c07df0a81eb3385fadedcfcf017e2407f5bbab30
4
+ data.tar.gz: 9b94b1a58d6ecccec7c516bfa6fdb8ed7eb7d58fb079c5fb77af86d9214a0b2b
5
+ SHA512:
6
+ metadata.gz: 4361581a6e38d86d531b988fabe314682ae4c600e459780facdca18b2addd2b639fa77b1fbeb0d5120c44f6c4c4b67fbcceb3fbeb26dfc2df6c4185007efd780
7
+ data.tar.gz: a9bc19932e9eec5854f70b7c1e4a4f0ade1b0d95779d6a29339499ed238500d60d1add5b24cb59be8582a839fa32834521fc655c76231ab6c727986559b81842
@@ -0,0 +1,24 @@
1
+ name: test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, 2.5, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@master
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: |
21
+ gem install bundler --no-document
22
+ bundle install
23
+ - name: Run test
24
+ run: rake test
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/COPYING ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a. place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b. use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c. give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d. make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a. distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b. accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c. give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d. make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rake"
4
+ gem "test-unit"
@@ -0,0 +1,17 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ power_assert (1.2.0)
5
+ rake (13.0.1)
6
+ test-unit (3.3.5)
7
+ power_assert
8
+
9
+ PLATFORMS
10
+ ruby
11
+
12
+ DEPENDENCIES
13
+ rake
14
+ test-unit
15
+
16
+ BUNDLED WITH
17
+ 2.2.0.dev
@@ -0,0 +1,60 @@
1
+ # OptionParser
2
+
3
+ OptionParser is a class for command-line option analysis. It is much more
4
+ advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
5
+ solution.
6
+
7
+ ## Features
8
+
9
+ 1. The argument specification and the code to handle it are written in the
10
+ same place.
11
+ 2. It can output an option summary; you don't need to maintain this string
12
+ separately.
13
+ 3. Optional and mandatory arguments are specified very gracefully.
14
+ 4. Arguments can be automatically converted to a specified class.
15
+ 5. Arguments can be restricted to a certain set.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'optparse'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle install
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install optparse
32
+
33
+ ## Usage
34
+
35
+ ```ruby
36
+ require 'optparse'
37
+
38
+ options = {}
39
+ OptionParser.new do |opts|
40
+ opts.banner = "Usage: example.rb [options]"
41
+
42
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
43
+ options[:verbose] = v
44
+ end
45
+ end.parse!
46
+
47
+ p options
48
+ p ARGV
49
+ ```
50
+
51
+ ## Development
52
+
53
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
+
55
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/optparse.
60
+
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList['test/**/test_*.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "optparse"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: false
2
+ require_relative 'optparse'
@@ -0,0 +1,2237 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # optparse.rb - command-line option analysis with the OptionParser class.
4
+ #
5
+ # Author:: Nobu Nakada
6
+ # Documentation:: Nobu Nakada and Gavin Sinclair.
7
+ #
8
+ # See OptionParser for documentation.
9
+ #
10
+
11
+
12
+ #--
13
+ # == Developer Documentation (not for RDoc output)
14
+ #
15
+ # === Class tree
16
+ #
17
+ # - OptionParser:: front end
18
+ # - OptionParser::Switch:: each switches
19
+ # - OptionParser::List:: options list
20
+ # - OptionParser::ParseError:: errors on parsing
21
+ # - OptionParser::AmbiguousOption
22
+ # - OptionParser::NeedlessArgument
23
+ # - OptionParser::MissingArgument
24
+ # - OptionParser::InvalidOption
25
+ # - OptionParser::InvalidArgument
26
+ # - OptionParser::AmbiguousArgument
27
+ #
28
+ # === Object relationship diagram
29
+ #
30
+ # +--------------+
31
+ # | OptionParser |<>-----+
32
+ # +--------------+ | +--------+
33
+ # | ,-| Switch |
34
+ # on_head -------->+---------------+ / +--------+
35
+ # accept/reject -->| List |<|>-
36
+ # | |<|>- +----------+
37
+ # on ------------->+---------------+ `-| argument |
38
+ # : : | class |
39
+ # +---------------+ |==========|
40
+ # on_tail -------->| | |pattern |
41
+ # +---------------+ |----------|
42
+ # OptionParser.accept ->| DefaultList | |converter |
43
+ # reject |(shared between| +----------+
44
+ # | all instances)|
45
+ # +---------------+
46
+ #
47
+ #++
48
+ #
49
+ # == OptionParser
50
+ #
51
+ # === Introduction
52
+ #
53
+ # OptionParser is a class for command-line option analysis. It is much more
54
+ # advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
55
+ # solution.
56
+ #
57
+ # === Features
58
+ #
59
+ # 1. The argument specification and the code to handle it are written in the
60
+ # same place.
61
+ # 2. It can output an option summary; you don't need to maintain this string
62
+ # separately.
63
+ # 3. Optional and mandatory arguments are specified very gracefully.
64
+ # 4. Arguments can be automatically converted to a specified class.
65
+ # 5. Arguments can be restricted to a certain set.
66
+ #
67
+ # All of these features are demonstrated in the examples below. See
68
+ # #make_switch for full documentation.
69
+ #
70
+ # === Minimal example
71
+ #
72
+ # require 'optparse'
73
+ #
74
+ # options = {}
75
+ # OptionParser.new do |opts|
76
+ # opts.banner = "Usage: example.rb [options]"
77
+ #
78
+ # opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
79
+ # options[:verbose] = v
80
+ # end
81
+ # end.parse!
82
+ #
83
+ # p options
84
+ # p ARGV
85
+ #
86
+ # === Generating Help
87
+ #
88
+ # OptionParser can be used to automatically generate help for the commands you
89
+ # write:
90
+ #
91
+ # require 'optparse'
92
+ #
93
+ # Options = Struct.new(:name)
94
+ #
95
+ # class Parser
96
+ # def self.parse(options)
97
+ # args = Options.new("world")
98
+ #
99
+ # opt_parser = OptionParser.new do |opts|
100
+ # opts.banner = "Usage: example.rb [options]"
101
+ #
102
+ # opts.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
103
+ # args.name = n
104
+ # end
105
+ #
106
+ # opts.on("-h", "--help", "Prints this help") do
107
+ # puts opts
108
+ # exit
109
+ # end
110
+ # end
111
+ #
112
+ # opt_parser.parse!(options)
113
+ # return args
114
+ # end
115
+ # end
116
+ # options = Parser.parse %w[--help]
117
+ #
118
+ # #=>
119
+ # # Usage: example.rb [options]
120
+ # # -n, --name=NAME Name to say hello to
121
+ # # -h, --help Prints this help
122
+ #
123
+ # === Required Arguments
124
+ #
125
+ # For options that require an argument, option specification strings may include an
126
+ # option name in all caps. If an option is used without the required argument,
127
+ # an exception will be raised.
128
+ #
129
+ # require 'optparse'
130
+ #
131
+ # options = {}
132
+ # OptionParser.new do |parser|
133
+ # parser.on("-r", "--require LIBRARY",
134
+ # "Require the LIBRARY before executing your script") do |lib|
135
+ # puts "You required #{lib}!"
136
+ # end
137
+ # end.parse!
138
+ #
139
+ # Used:
140
+ #
141
+ # $ ruby optparse-test.rb -r
142
+ # optparse-test.rb:9:in `<main>': missing argument: -r (OptionParser::MissingArgument)
143
+ # $ ruby optparse-test.rb -r my-library
144
+ # You required my-library!
145
+ #
146
+ # === Type Coercion
147
+ #
148
+ # OptionParser supports the ability to coerce command line arguments
149
+ # into objects for us.
150
+ #
151
+ # OptionParser comes with a few ready-to-use kinds of type
152
+ # coercion. They are:
153
+ #
154
+ # - Date -- Anything accepted by +Date.parse+
155
+ # - DateTime -- Anything accepted by +DateTime.parse+
156
+ # - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+
157
+ # - URI -- Anything accepted by +URI.parse+
158
+ # - Shellwords -- Anything accepted by +Shellwords.shellwords+
159
+ # - String -- Any non-empty string
160
+ # - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040)
161
+ # - Float -- Any float. (e.g. 10, 3.14, -100E+13)
162
+ # - Numeric -- Any integer, float, or rational (1, 3.4, 1/3)
163
+ # - DecimalInteger -- Like +Integer+, but no octal format.
164
+ # - OctalInteger -- Like +Integer+, but no decimal format.
165
+ # - DecimalNumeric -- Decimal integer or float.
166
+ # - TrueClass -- Accepts '+, yes, true, -, no, false' and
167
+ # defaults as +true+
168
+ # - FalseClass -- Same as +TrueClass+, but defaults to +false+
169
+ # - Array -- Strings separated by ',' (e.g. 1,2,3)
170
+ # - Regexp -- Regular expressions. Also includes options.
171
+ #
172
+ # We can also add our own coercions, which we will cover below.
173
+ #
174
+ # ==== Using Built-in Conversions
175
+ #
176
+ # As an example, the built-in +Time+ conversion is used. The other built-in
177
+ # conversions behave in the same way.
178
+ # OptionParser will attempt to parse the argument
179
+ # as a +Time+. If it succeeds, that time will be passed to the
180
+ # handler block. Otherwise, an exception will be raised.
181
+ #
182
+ # require 'optparse'
183
+ # require 'optparse/time'
184
+ # OptionParser.new do |parser|
185
+ # parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
186
+ # p time
187
+ # end
188
+ # end.parse!
189
+ #
190
+ # Used:
191
+ #
192
+ # $ ruby optparse-test.rb -t nonsense
193
+ # ... invalid argument: -t nonsense (OptionParser::InvalidArgument)
194
+ # $ ruby optparse-test.rb -t 10-11-12
195
+ # 2010-11-12 00:00:00 -0500
196
+ # $ ruby optparse-test.rb -t 9:30
197
+ # 2014-08-13 09:30:00 -0400
198
+ #
199
+ # ==== Creating Custom Conversions
200
+ #
201
+ # The +accept+ method on OptionParser may be used to create converters.
202
+ # It specifies which conversion block to call whenever a class is specified.
203
+ # The example below uses it to fetch a +User+ object before the +on+ handler receives it.
204
+ #
205
+ # require 'optparse'
206
+ #
207
+ # User = Struct.new(:id, :name)
208
+ #
209
+ # def find_user id
210
+ # not_found = ->{ raise "No User Found for id #{id}" }
211
+ # [ User.new(1, "Sam"),
212
+ # User.new(2, "Gandalf") ].find(not_found) do |u|
213
+ # u.id == id
214
+ # end
215
+ # end
216
+ #
217
+ # op = OptionParser.new
218
+ # op.accept(User) do |user_id|
219
+ # find_user user_id.to_i
220
+ # end
221
+ #
222
+ # op.on("--user ID", User) do |user|
223
+ # puts user
224
+ # end
225
+ #
226
+ # op.parse!
227
+ #
228
+ # Used:
229
+ #
230
+ # $ ruby optparse-test.rb --user 1
231
+ # #<struct User id=1, name="Sam">
232
+ # $ ruby optparse-test.rb --user 2
233
+ # #<struct User id=2, name="Gandalf">
234
+ # $ ruby optparse-test.rb --user 3
235
+ # optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError)
236
+ #
237
+ # === Store options to a Hash
238
+ #
239
+ # The +into+ option of +order+, +parse+ and so on methods stores command line options into a Hash.
240
+ #
241
+ # require 'optparse'
242
+ #
243
+ # params = {}
244
+ # OptionParser.new do |opts|
245
+ # opts.on('-a')
246
+ # opts.on('-b NUM', Integer)
247
+ # opts.on('-v', '--verbose')
248
+ # end.parse!(into: params)
249
+ #
250
+ # p params
251
+ #
252
+ # Used:
253
+ #
254
+ # $ ruby optparse-test.rb -a
255
+ # {:a=>true}
256
+ # $ ruby optparse-test.rb -a -v
257
+ # {:a=>true, :verbose=>true}
258
+ # $ ruby optparse-test.rb -a -b 100
259
+ # {:a=>true, :b=>100}
260
+ #
261
+ # === Complete example
262
+ #
263
+ # The following example is a complete Ruby program. You can run it and see the
264
+ # effect of specifying various options. This is probably the best way to learn
265
+ # the features of +optparse+.
266
+ #
267
+ # require 'optparse'
268
+ # require 'optparse/time'
269
+ # require 'ostruct'
270
+ # require 'pp'
271
+ #
272
+ # class OptparseExample
273
+ # Version = '1.0.0'
274
+ #
275
+ # CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
276
+ # CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
277
+ #
278
+ # class ScriptOptions
279
+ # attr_accessor :library, :inplace, :encoding, :transfer_type,
280
+ # :verbose, :extension, :delay, :time, :record_separator,
281
+ # :list
282
+ #
283
+ # def initialize
284
+ # self.library = []
285
+ # self.inplace = false
286
+ # self.encoding = "utf8"
287
+ # self.transfer_type = :auto
288
+ # self.verbose = false
289
+ # end
290
+ #
291
+ # def define_options(parser)
292
+ # parser.banner = "Usage: example.rb [options]"
293
+ # parser.separator ""
294
+ # parser.separator "Specific options:"
295
+ #
296
+ # # add additional options
297
+ # perform_inplace_option(parser)
298
+ # delay_execution_option(parser)
299
+ # execute_at_time_option(parser)
300
+ # specify_record_separator_option(parser)
301
+ # list_example_option(parser)
302
+ # specify_encoding_option(parser)
303
+ # optional_option_argument_with_keyword_completion_option(parser)
304
+ # boolean_verbose_option(parser)
305
+ #
306
+ # parser.separator ""
307
+ # parser.separator "Common options:"
308
+ # # No argument, shows at tail. This will print an options summary.
309
+ # # Try it and see!
310
+ # parser.on_tail("-h", "--help", "Show this message") do
311
+ # puts parser
312
+ # exit
313
+ # end
314
+ # # Another typical switch to print the version.
315
+ # parser.on_tail("--version", "Show version") do
316
+ # puts Version
317
+ # exit
318
+ # end
319
+ # end
320
+ #
321
+ # def perform_inplace_option(parser)
322
+ # # Specifies an optional option argument
323
+ # parser.on("-i", "--inplace [EXTENSION]",
324
+ # "Edit ARGV files in place",
325
+ # "(make backup if EXTENSION supplied)") do |ext|
326
+ # self.inplace = true
327
+ # self.extension = ext || ''
328
+ # self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
329
+ # end
330
+ # end
331
+ #
332
+ # def delay_execution_option(parser)
333
+ # # Cast 'delay' argument to a Float.
334
+ # parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
335
+ # self.delay = n
336
+ # end
337
+ # end
338
+ #
339
+ # def execute_at_time_option(parser)
340
+ # # Cast 'time' argument to a Time object.
341
+ # parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
342
+ # self.time = time
343
+ # end
344
+ # end
345
+ #
346
+ # def specify_record_separator_option(parser)
347
+ # # Cast to octal integer.
348
+ # parser.on("-F", "--irs [OCTAL]", OptionParser::OctalInteger,
349
+ # "Specify record separator (default \\0)") do |rs|
350
+ # self.record_separator = rs
351
+ # end
352
+ # end
353
+ #
354
+ # def list_example_option(parser)
355
+ # # List of arguments.
356
+ # parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
357
+ # self.list = list
358
+ # end
359
+ # end
360
+ #
361
+ # def specify_encoding_option(parser)
362
+ # # Keyword completion. We are specifying a specific set of arguments (CODES
363
+ # # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
364
+ # # the shortest unambiguous text.
365
+ # code_list = (CODE_ALIASES.keys + CODES).join(', ')
366
+ # parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
367
+ # "(#{code_list})") do |encoding|
368
+ # self.encoding = encoding
369
+ # end
370
+ # end
371
+ #
372
+ # def optional_option_argument_with_keyword_completion_option(parser)
373
+ # # Optional '--type' option argument with keyword completion.
374
+ # parser.on("--type [TYPE]", [:text, :binary, :auto],
375
+ # "Select transfer type (text, binary, auto)") do |t|
376
+ # self.transfer_type = t
377
+ # end
378
+ # end
379
+ #
380
+ # def boolean_verbose_option(parser)
381
+ # # Boolean switch.
382
+ # parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
383
+ # self.verbose = v
384
+ # end
385
+ # end
386
+ # end
387
+ #
388
+ # #
389
+ # # Return a structure describing the options.
390
+ # #
391
+ # def parse(args)
392
+ # # The options specified on the command line will be collected in
393
+ # # *options*.
394
+ #
395
+ # @options = ScriptOptions.new
396
+ # @args = OptionParser.new do |parser|
397
+ # @options.define_options(parser)
398
+ # parser.parse!(args)
399
+ # end
400
+ # @options
401
+ # end
402
+ #
403
+ # attr_reader :parser, :options
404
+ # end # class OptparseExample
405
+ #
406
+ # example = OptparseExample.new
407
+ # options = example.parse(ARGV)
408
+ # pp options # example.options
409
+ # pp ARGV
410
+ #
411
+ # === Shell Completion
412
+ #
413
+ # For modern shells (e.g. bash, zsh, etc.), you can use shell
414
+ # completion for command line options.
415
+ #
416
+ # === Further documentation
417
+ #
418
+ # The above examples should be enough to learn how to use this class. If you
419
+ # have any questions, file a ticket at http://bugs.ruby-lang.org.
420
+ #
421
+ class OptionParser
422
+ OptionParser::Version = "0.1.0"
423
+
424
+ # :stopdoc:
425
+ NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
426
+ RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
427
+ OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
428
+ # :startdoc:
429
+
430
+ #
431
+ # Keyword completion module. This allows partial arguments to be specified
432
+ # and resolved against a list of acceptable values.
433
+ #
434
+ module Completion
435
+ def self.regexp(key, icase)
436
+ Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
437
+ end
438
+
439
+ def self.candidate(key, icase = false, pat = nil, &block)
440
+ pat ||= Completion.regexp(key, icase)
441
+ candidates = []
442
+ block.call do |k, *v|
443
+ (if Regexp === k
444
+ kn = ""
445
+ k === key
446
+ else
447
+ kn = defined?(k.id2name) ? k.id2name : k
448
+ pat === kn
449
+ end) or next
450
+ v << k if v.empty?
451
+ candidates << [k, v, kn]
452
+ end
453
+ candidates
454
+ end
455
+
456
+ def candidate(key, icase = false, pat = nil)
457
+ Completion.candidate(key, icase, pat, &method(:each))
458
+ end
459
+
460
+ public
461
+ def complete(key, icase = false, pat = nil)
462
+ candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
463
+ if candidates.size == 1
464
+ canon, sw, * = candidates[0]
465
+ elsif candidates.size > 1
466
+ canon, sw, cn = candidates.shift
467
+ candidates.each do |k, v, kn|
468
+ next if sw == v
469
+ if String === cn and String === kn
470
+ if cn.rindex(kn, 0)
471
+ canon, sw, cn = k, v, kn
472
+ next
473
+ elsif kn.rindex(cn, 0)
474
+ next
475
+ end
476
+ end
477
+ throw :ambiguous, key
478
+ end
479
+ end
480
+ if canon
481
+ block_given? or return key, *sw
482
+ yield(key, *sw)
483
+ end
484
+ end
485
+
486
+ def convert(opt = nil, val = nil, *)
487
+ val
488
+ end
489
+ end
490
+
491
+
492
+ #
493
+ # Map from option/keyword string to object with completion.
494
+ #
495
+ class OptionMap < Hash
496
+ include Completion
497
+ end
498
+
499
+
500
+ #
501
+ # Individual switch class. Not important to the user.
502
+ #
503
+ # Defined within Switch are several Switch-derived classes: NoArgument,
504
+ # RequiredArgument, etc.
505
+ #
506
+ class Switch
507
+ attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
508
+
509
+ #
510
+ # Guesses argument style from +arg+. Returns corresponding
511
+ # OptionParser::Switch class (OptionalArgument, etc.).
512
+ #
513
+ def self.guess(arg)
514
+ case arg
515
+ when ""
516
+ t = self
517
+ when /\A=?\[/
518
+ t = Switch::OptionalArgument
519
+ when /\A\s+\[/
520
+ t = Switch::PlacedArgument
521
+ else
522
+ t = Switch::RequiredArgument
523
+ end
524
+ self >= t or incompatible_argument_styles(arg, t)
525
+ t
526
+ end
527
+
528
+ def self.incompatible_argument_styles(arg, t)
529
+ raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
530
+ ParseError.filter_backtrace(caller(2)))
531
+ end
532
+
533
+ def self.pattern
534
+ NilClass
535
+ end
536
+
537
+ def initialize(pattern = nil, conv = nil,
538
+ short = nil, long = nil, arg = nil,
539
+ desc = ([] if short or long), block = nil, &_block)
540
+ raise if Array === pattern
541
+ block ||= _block
542
+ @pattern, @conv, @short, @long, @arg, @desc, @block =
543
+ pattern, conv, short, long, arg, desc, block
544
+ end
545
+
546
+ #
547
+ # Parses +arg+ and returns rest of +arg+ and matched portion to the
548
+ # argument pattern. Yields when the pattern doesn't match substring.
549
+ #
550
+ def parse_arg(arg)
551
+ pattern or return nil, [arg]
552
+ unless m = pattern.match(arg)
553
+ yield(InvalidArgument, arg)
554
+ return arg, []
555
+ end
556
+ if String === m
557
+ m = [s = m]
558
+ else
559
+ m = m.to_a
560
+ s = m[0]
561
+ return nil, m unless String === s
562
+ end
563
+ raise InvalidArgument, arg unless arg.rindex(s, 0)
564
+ return nil, m if s.length == arg.length
565
+ yield(InvalidArgument, arg) # didn't match whole arg
566
+ return arg[s.length..-1], m
567
+ end
568
+ private :parse_arg
569
+
570
+ #
571
+ # Parses argument, converts and returns +arg+, +block+ and result of
572
+ # conversion. Yields at semi-error condition instead of raising an
573
+ # exception.
574
+ #
575
+ def conv_arg(arg, val = [])
576
+ if conv
577
+ val = conv.call(*val)
578
+ else
579
+ val = proc {|v| v}.call(*val)
580
+ end
581
+ return arg, block, val
582
+ end
583
+ private :conv_arg
584
+
585
+ #
586
+ # Produces the summary text. Each line of the summary is yielded to the
587
+ # block (without newline).
588
+ #
589
+ # +sdone+:: Already summarized short style options keyed hash.
590
+ # +ldone+:: Already summarized long style options keyed hash.
591
+ # +width+:: Width of left side (option part). In other words, the right
592
+ # side (description part) starts after +width+ columns.
593
+ # +max+:: Maximum width of left side -> the options are filled within
594
+ # +max+ columns.
595
+ # +indent+:: Prefix string indents all summarized lines.
596
+ #
597
+ def summarize(sdone = {}, ldone = {}, width = 1, max = width - 1, indent = "")
598
+ sopts, lopts = [], [], nil
599
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
600
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
601
+ return if sopts.empty? and lopts.empty? # completely hidden
602
+
603
+ left = [sopts.join(', ')]
604
+ right = desc.dup
605
+
606
+ while s = lopts.shift
607
+ l = left[-1].length + s.length
608
+ l += arg.length if left.size == 1 && arg
609
+ l < max or sopts.empty? or left << +''
610
+ left[-1] << (left[-1].empty? ? ' ' * 4 : ', ') << s
611
+ end
612
+
613
+ if arg
614
+ left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
615
+ end
616
+ mlen = left.collect {|ss| ss.length}.max.to_i
617
+ while mlen > width and l = left.shift
618
+ mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
619
+ if l.length < width and (r = right[0]) and !r.empty?
620
+ l = l.to_s.ljust(width) + ' ' + r
621
+ right.shift
622
+ end
623
+ yield(indent + l)
624
+ end
625
+
626
+ while begin l = left.shift; r = right.shift; l or r end
627
+ l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
628
+ yield(indent + l)
629
+ end
630
+
631
+ self
632
+ end
633
+
634
+ def add_banner(to) # :nodoc:
635
+ unless @short or @long
636
+ s = desc.join
637
+ to << " [" + s + "]..." unless s.empty?
638
+ end
639
+ to
640
+ end
641
+
642
+ def match_nonswitch?(str) # :nodoc:
643
+ @pattern =~ str unless @short or @long
644
+ end
645
+
646
+ #
647
+ # Main name of the switch.
648
+ #
649
+ def switch_name
650
+ (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
651
+ end
652
+
653
+ def compsys(sdone, ldone) # :nodoc:
654
+ sopts, lopts = [], []
655
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
656
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
657
+ return if sopts.empty? and lopts.empty? # completely hidden
658
+
659
+ (sopts+lopts).each do |opt|
660
+ # "(-x -c -r)-l[left justify]"
661
+ if /^--\[no-\](.+)$/ =~ opt
662
+ o = $1
663
+ yield("--#{o}", desc.join(""))
664
+ yield("--no-#{o}", desc.join(""))
665
+ else
666
+ yield("#{opt}", desc.join(""))
667
+ end
668
+ end
669
+ end
670
+
671
+ #
672
+ # Switch that takes no arguments.
673
+ #
674
+ class NoArgument < self
675
+
676
+ #
677
+ # Raises an exception if any arguments given.
678
+ #
679
+ def parse(arg, argv)
680
+ yield(NeedlessArgument, arg) if arg
681
+ conv_arg(arg)
682
+ end
683
+
684
+ def self.incompatible_argument_styles(*)
685
+ end
686
+
687
+ def self.pattern
688
+ Object
689
+ end
690
+ end
691
+
692
+ #
693
+ # Switch that takes an argument.
694
+ #
695
+ class RequiredArgument < self
696
+
697
+ #
698
+ # Raises an exception if argument is not present.
699
+ #
700
+ def parse(arg, argv)
701
+ unless arg
702
+ raise MissingArgument if argv.empty?
703
+ arg = argv.shift
704
+ end
705
+ conv_arg(*parse_arg(arg, &method(:raise)))
706
+ end
707
+ end
708
+
709
+ #
710
+ # Switch that can omit argument.
711
+ #
712
+ class OptionalArgument < self
713
+
714
+ #
715
+ # Parses argument if given, or uses default value.
716
+ #
717
+ def parse(arg, argv, &error)
718
+ if arg
719
+ conv_arg(*parse_arg(arg, &error))
720
+ else
721
+ conv_arg(arg)
722
+ end
723
+ end
724
+ end
725
+
726
+ #
727
+ # Switch that takes an argument, which does not begin with '-'.
728
+ #
729
+ class PlacedArgument < self
730
+
731
+ #
732
+ # Returns nil if argument is not present or begins with '-'.
733
+ #
734
+ def parse(arg, argv, &error)
735
+ if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
736
+ return nil, block, nil
737
+ end
738
+ opt = (val = parse_arg(val, &error))[1]
739
+ val = conv_arg(*val)
740
+ if opt and !arg
741
+ argv.shift
742
+ else
743
+ val[0] = nil
744
+ end
745
+ val
746
+ end
747
+ end
748
+ end
749
+
750
+ #
751
+ # Simple option list providing mapping from short and/or long option
752
+ # string to OptionParser::Switch and mapping from acceptable argument to
753
+ # matching pattern and converter pair. Also provides summary feature.
754
+ #
755
+ class List
756
+ # Map from acceptable argument types to pattern and converter pairs.
757
+ attr_reader :atype
758
+
759
+ # Map from short style option switches to actual switch objects.
760
+ attr_reader :short
761
+
762
+ # Map from long style option switches to actual switch objects.
763
+ attr_reader :long
764
+
765
+ # List of all switches and summary string.
766
+ attr_reader :list
767
+
768
+ #
769
+ # Just initializes all instance variables.
770
+ #
771
+ def initialize
772
+ @atype = {}
773
+ @short = OptionMap.new
774
+ @long = OptionMap.new
775
+ @list = []
776
+ end
777
+
778
+ #
779
+ # See OptionParser.accept.
780
+ #
781
+ def accept(t, pat = /.*/m, &block)
782
+ if pat
783
+ pat.respond_to?(:match) or
784
+ raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
785
+ else
786
+ pat = t if t.respond_to?(:match)
787
+ end
788
+ unless block
789
+ block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
790
+ end
791
+ @atype[t] = [pat, block]
792
+ end
793
+
794
+ #
795
+ # See OptionParser.reject.
796
+ #
797
+ def reject(t)
798
+ @atype.delete(t)
799
+ end
800
+
801
+ #
802
+ # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
803
+ #
804
+ # +sw+:: OptionParser::Switch instance to be added.
805
+ # +sopts+:: Short style option list.
806
+ # +lopts+:: Long style option list.
807
+ # +nlopts+:: Negated long style options list.
808
+ #
809
+ def update(sw, sopts, lopts, nsw = nil, nlopts = nil)
810
+ sopts.each {|o| @short[o] = sw} if sopts
811
+ lopts.each {|o| @long[o] = sw} if lopts
812
+ nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
813
+ used = @short.invert.update(@long.invert)
814
+ @list.delete_if {|o| Switch === o and !used[o]}
815
+ end
816
+ private :update
817
+
818
+ #
819
+ # Inserts +switch+ at the head of the list, and associates short, long
820
+ # and negated long options. Arguments are:
821
+ #
822
+ # +switch+:: OptionParser::Switch instance to be inserted.
823
+ # +short_opts+:: List of short style options.
824
+ # +long_opts+:: List of long style options.
825
+ # +nolong_opts+:: List of long style options with "no-" prefix.
826
+ #
827
+ # prepend(switch, short_opts, long_opts, nolong_opts)
828
+ #
829
+ def prepend(*args)
830
+ update(*args)
831
+ @list.unshift(args[0])
832
+ end
833
+
834
+ #
835
+ # Appends +switch+ at the tail of the list, and associates short, long
836
+ # and negated long options. Arguments are:
837
+ #
838
+ # +switch+:: OptionParser::Switch instance to be inserted.
839
+ # +short_opts+:: List of short style options.
840
+ # +long_opts+:: List of long style options.
841
+ # +nolong_opts+:: List of long style options with "no-" prefix.
842
+ #
843
+ # append(switch, short_opts, long_opts, nolong_opts)
844
+ #
845
+ def append(*args)
846
+ update(*args)
847
+ @list.push(args[0])
848
+ end
849
+
850
+ #
851
+ # Searches +key+ in +id+ list. The result is returned or yielded if a
852
+ # block is given. If it isn't found, nil is returned.
853
+ #
854
+ def search(id, key)
855
+ if list = __send__(id)
856
+ val = list.fetch(key) {return nil}
857
+ block_given? ? yield(val) : val
858
+ end
859
+ end
860
+
861
+ #
862
+ # Searches list +id+ for +opt+ and the optional patterns for completion
863
+ # +pat+. If +icase+ is true, the search is case insensitive. The result
864
+ # is returned or yielded if a block is given. If it isn't found, nil is
865
+ # returned.
866
+ #
867
+ def complete(id, opt, icase = false, *pat, &block)
868
+ __send__(id).complete(opt, icase, *pat, &block)
869
+ end
870
+
871
+ def get_candidates(id)
872
+ yield __send__(id).keys
873
+ end
874
+
875
+ #
876
+ # Iterates over each option, passing the option to the +block+.
877
+ #
878
+ def each_option(&block)
879
+ list.each(&block)
880
+ end
881
+
882
+ #
883
+ # Creates the summary table, passing each line to the +block+ (without
884
+ # newline). The arguments +args+ are passed along to the summarize
885
+ # method which is called on every option.
886
+ #
887
+ def summarize(*args, &block)
888
+ sum = []
889
+ list.reverse_each do |opt|
890
+ if opt.respond_to?(:summarize) # perhaps OptionParser::Switch
891
+ s = []
892
+ opt.summarize(*args) {|l| s << l}
893
+ sum.concat(s.reverse)
894
+ elsif !opt or opt.empty?
895
+ sum << ""
896
+ elsif opt.respond_to?(:each_line)
897
+ sum.concat([*opt.each_line].reverse)
898
+ else
899
+ sum.concat([*opt.each].reverse)
900
+ end
901
+ end
902
+ sum.reverse_each(&block)
903
+ end
904
+
905
+ def add_banner(to) # :nodoc:
906
+ list.each do |opt|
907
+ if opt.respond_to?(:add_banner)
908
+ opt.add_banner(to)
909
+ end
910
+ end
911
+ to
912
+ end
913
+
914
+ def compsys(*args, &block) # :nodoc:
915
+ list.each do |opt|
916
+ if opt.respond_to?(:compsys)
917
+ opt.compsys(*args, &block)
918
+ end
919
+ end
920
+ end
921
+ end
922
+
923
+ #
924
+ # Hash with completion search feature. See OptionParser::Completion.
925
+ #
926
+ class CompletingHash < Hash
927
+ include Completion
928
+
929
+ #
930
+ # Completion for hash key.
931
+ #
932
+ def match(key)
933
+ *values = fetch(key) {
934
+ raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
935
+ }
936
+ return key, *values
937
+ end
938
+ end
939
+
940
+ # :stopdoc:
941
+
942
+ #
943
+ # Enumeration of acceptable argument styles. Possible values are:
944
+ #
945
+ # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
946
+ # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
947
+ # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
948
+ #
949
+ # Use like --switch=argument (long style) or -Xargument (short style). For
950
+ # short style, only portion matched to argument pattern is treated as
951
+ # argument.
952
+ #
953
+ ArgumentStyle = {}
954
+ NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
955
+ RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
956
+ OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument}
957
+ ArgumentStyle.freeze
958
+
959
+ #
960
+ # Switches common used such as '--', and also provides default
961
+ # argument classes
962
+ #
963
+ DefaultList = List.new
964
+ DefaultList.short['-'] = Switch::NoArgument.new {}
965
+ DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
966
+
967
+
968
+ COMPSYS_HEADER = <<'XXX' # :nodoc:
969
+
970
+ typeset -A opt_args
971
+ local context state line
972
+
973
+ _arguments -s -S \
974
+ XXX
975
+
976
+ def compsys(to, name = File.basename($0)) # :nodoc:
977
+ to << "#compdef #{name}\n"
978
+ to << COMPSYS_HEADER
979
+ visit(:compsys, {}, {}) {|o, d|
980
+ to << %Q[ "#{o}[#{d.gsub(/[\"\[\]]/, '\\\\\&')}]" \\\n]
981
+ }
982
+ to << " '*:file:_files' && return 0\n"
983
+ end
984
+
985
+ #
986
+ # Default options for ARGV, which never appear in option summary.
987
+ #
988
+ Officious = {}
989
+
990
+ #
991
+ # --help
992
+ # Shows option summary.
993
+ #
994
+ Officious['help'] = proc do |parser|
995
+ Switch::NoArgument.new do |arg|
996
+ puts parser.help
997
+ exit
998
+ end
999
+ end
1000
+
1001
+ #
1002
+ # --*-completion-bash=WORD
1003
+ # Shows candidates for command line completion.
1004
+ #
1005
+ Officious['*-completion-bash'] = proc do |parser|
1006
+ Switch::RequiredArgument.new do |arg|
1007
+ puts parser.candidate(arg)
1008
+ exit
1009
+ end
1010
+ end
1011
+
1012
+ #
1013
+ # --*-completion-zsh[=NAME:FILE]
1014
+ # Creates zsh completion file.
1015
+ #
1016
+ Officious['*-completion-zsh'] = proc do |parser|
1017
+ Switch::OptionalArgument.new do |arg|
1018
+ parser.compsys(STDOUT, arg)
1019
+ exit
1020
+ end
1021
+ end
1022
+
1023
+ #
1024
+ # --version
1025
+ # Shows version string if Version is defined.
1026
+ #
1027
+ Officious['version'] = proc do |parser|
1028
+ Switch::OptionalArgument.new do |pkg|
1029
+ if pkg
1030
+ begin
1031
+ require 'optparse/version'
1032
+ rescue LoadError
1033
+ else
1034
+ show_version(*pkg.split(/,/)) or
1035
+ abort("#{parser.program_name}: no version found in package #{pkg}")
1036
+ exit
1037
+ end
1038
+ end
1039
+ v = parser.ver or abort("#{parser.program_name}: version unknown")
1040
+ puts v
1041
+ exit
1042
+ end
1043
+ end
1044
+
1045
+ # :startdoc:
1046
+
1047
+ #
1048
+ # Class methods
1049
+ #
1050
+
1051
+ #
1052
+ # Initializes a new instance and evaluates the optional block in context
1053
+ # of the instance. Arguments +args+ are passed to #new, see there for
1054
+ # description of parameters.
1055
+ #
1056
+ # This method is *deprecated*, its behavior corresponds to the older #new
1057
+ # method.
1058
+ #
1059
+ def self.with(*args, &block)
1060
+ opts = new(*args)
1061
+ opts.instance_eval(&block)
1062
+ opts
1063
+ end
1064
+
1065
+ #
1066
+ # Returns an incremented value of +default+ according to +arg+.
1067
+ #
1068
+ def self.inc(arg, default = nil)
1069
+ case arg
1070
+ when Integer
1071
+ arg.nonzero?
1072
+ when nil
1073
+ default.to_i + 1
1074
+ end
1075
+ end
1076
+ def inc(*args)
1077
+ self.class.inc(*args)
1078
+ end
1079
+
1080
+ #
1081
+ # Initializes the instance and yields itself if called with a block.
1082
+ #
1083
+ # +banner+:: Banner message.
1084
+ # +width+:: Summary width.
1085
+ # +indent+:: Summary indent.
1086
+ #
1087
+ def initialize(banner = nil, width = 32, indent = ' ' * 4)
1088
+ @stack = [DefaultList, List.new, List.new]
1089
+ @program_name = nil
1090
+ @banner = banner
1091
+ @summary_width = width
1092
+ @summary_indent = indent
1093
+ @default_argv = ARGV
1094
+ add_officious
1095
+ yield self if block_given?
1096
+ end
1097
+
1098
+ def add_officious # :nodoc:
1099
+ list = base()
1100
+ Officious.each do |opt, block|
1101
+ list.long[opt] ||= block.call(self)
1102
+ end
1103
+ end
1104
+
1105
+ #
1106
+ # Terminates option parsing. Optional parameter +arg+ is a string pushed
1107
+ # back to be the first non-option argument.
1108
+ #
1109
+ def terminate(arg = nil)
1110
+ self.class.terminate(arg)
1111
+ end
1112
+ def self.terminate(arg = nil)
1113
+ throw :terminate, arg
1114
+ end
1115
+
1116
+ @stack = [DefaultList]
1117
+ def self.top() DefaultList end
1118
+
1119
+ #
1120
+ # Directs to accept specified class +t+. The argument string is passed to
1121
+ # the block in which it should be converted to the desired class.
1122
+ #
1123
+ # +t+:: Argument class specifier, any object including Class.
1124
+ # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
1125
+ #
1126
+ # accept(t, pat, &block)
1127
+ #
1128
+ def accept(*args, &blk) top.accept(*args, &blk) end
1129
+ #
1130
+ # See #accept.
1131
+ #
1132
+ def self.accept(*args, &blk) top.accept(*args, &blk) end
1133
+
1134
+ #
1135
+ # Directs to reject specified class argument.
1136
+ #
1137
+ # +t+:: Argument class specifier, any object including Class.
1138
+ #
1139
+ # reject(t)
1140
+ #
1141
+ def reject(*args, &blk) top.reject(*args, &blk) end
1142
+ #
1143
+ # See #reject.
1144
+ #
1145
+ def self.reject(*args, &blk) top.reject(*args, &blk) end
1146
+
1147
+ #
1148
+ # Instance methods
1149
+ #
1150
+
1151
+ # Heading banner preceding summary.
1152
+ attr_writer :banner
1153
+
1154
+ # Program name to be emitted in error message and default banner,
1155
+ # defaults to $0.
1156
+ attr_writer :program_name
1157
+
1158
+ # Width for option list portion of summary. Must be Numeric.
1159
+ attr_accessor :summary_width
1160
+
1161
+ # Indentation for summary. Must be String (or have + String method).
1162
+ attr_accessor :summary_indent
1163
+
1164
+ # Strings to be parsed in default.
1165
+ attr_accessor :default_argv
1166
+
1167
+ #
1168
+ # Heading banner preceding summary.
1169
+ #
1170
+ def banner
1171
+ unless @banner
1172
+ @banner = +"Usage: #{program_name} [options]"
1173
+ visit(:add_banner, @banner)
1174
+ end
1175
+ @banner
1176
+ end
1177
+
1178
+ #
1179
+ # Program name to be emitted in error message and default banner, defaults
1180
+ # to $0.
1181
+ #
1182
+ def program_name
1183
+ @program_name || File.basename($0, '.*')
1184
+ end
1185
+
1186
+ # for experimental cascading :-)
1187
+ alias set_banner banner=
1188
+ alias set_program_name program_name=
1189
+ alias set_summary_width summary_width=
1190
+ alias set_summary_indent summary_indent=
1191
+
1192
+ # Version
1193
+ attr_writer :version
1194
+ # Release code
1195
+ attr_writer :release
1196
+
1197
+ #
1198
+ # Version
1199
+ #
1200
+ def version
1201
+ (defined?(@version) && @version) || (defined?(::Version) && ::Version)
1202
+ end
1203
+
1204
+ #
1205
+ # Release code
1206
+ #
1207
+ def release
1208
+ (defined?(@release) && @release) || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
1209
+ end
1210
+
1211
+ #
1212
+ # Returns version string from program_name, version and release.
1213
+ #
1214
+ def ver
1215
+ if v = version
1216
+ str = +"#{program_name} #{[v].join('.')}"
1217
+ str << " (#{v})" if v = release
1218
+ str
1219
+ end
1220
+ end
1221
+
1222
+ def warn(mesg = $!)
1223
+ super("#{program_name}: #{mesg}")
1224
+ end
1225
+
1226
+ def abort(mesg = $!)
1227
+ super("#{program_name}: #{mesg}")
1228
+ end
1229
+
1230
+ #
1231
+ # Subject of #on / #on_head, #accept / #reject
1232
+ #
1233
+ def top
1234
+ @stack[-1]
1235
+ end
1236
+
1237
+ #
1238
+ # Subject of #on_tail.
1239
+ #
1240
+ def base
1241
+ @stack[1]
1242
+ end
1243
+
1244
+ #
1245
+ # Pushes a new List.
1246
+ #
1247
+ def new
1248
+ @stack.push(List.new)
1249
+ if block_given?
1250
+ yield self
1251
+ else
1252
+ self
1253
+ end
1254
+ end
1255
+
1256
+ #
1257
+ # Removes the last List.
1258
+ #
1259
+ def remove
1260
+ @stack.pop
1261
+ end
1262
+
1263
+ #
1264
+ # Puts option summary into +to+ and returns +to+. Yields each line if
1265
+ # a block is given.
1266
+ #
1267
+ # +to+:: Output destination, which must have method <<. Defaults to [].
1268
+ # +width+:: Width of left side, defaults to @summary_width.
1269
+ # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
1270
+ # +indent+:: Indentation, defaults to @summary_indent.
1271
+ #
1272
+ def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
1273
+ nl = "\n"
1274
+ blk ||= proc {|l| to << (l.index(nl, -1) ? l : l + nl)}
1275
+ visit(:summarize, {}, {}, width, max, indent, &blk)
1276
+ to
1277
+ end
1278
+
1279
+ #
1280
+ # Returns option summary string.
1281
+ #
1282
+ def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
1283
+ alias to_s help
1284
+
1285
+ #
1286
+ # Returns option summary list.
1287
+ #
1288
+ def to_a; summarize("#{banner}".split(/^/)) end
1289
+
1290
+ #
1291
+ # Checks if an argument is given twice, in which case an ArgumentError is
1292
+ # raised. Called from OptionParser#switch only.
1293
+ #
1294
+ # +obj+:: New argument.
1295
+ # +prv+:: Previously specified argument.
1296
+ # +msg+:: Exception message.
1297
+ #
1298
+ def notwice(obj, prv, msg)
1299
+ unless !prv or prv == obj
1300
+ raise(ArgumentError, "argument #{msg} given twice: #{obj}",
1301
+ ParseError.filter_backtrace(caller(2)))
1302
+ end
1303
+ obj
1304
+ end
1305
+ private :notwice
1306
+
1307
+ SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a} # :nodoc:
1308
+ #
1309
+ # Creates an OptionParser::Switch from the parameters. The parsed argument
1310
+ # value is passed to the given block, where it can be processed.
1311
+ #
1312
+ # See at the beginning of OptionParser for some full examples.
1313
+ #
1314
+ # +opts+ can include the following elements:
1315
+ #
1316
+ # [Argument style:]
1317
+ # One of the following:
1318
+ # :NONE, :REQUIRED, :OPTIONAL
1319
+ #
1320
+ # [Argument pattern:]
1321
+ # Acceptable option argument format, must be pre-defined with
1322
+ # OptionParser.accept or OptionParser#accept, or Regexp. This can appear
1323
+ # once or assigned as String if not present, otherwise causes an
1324
+ # ArgumentError. Examples:
1325
+ # Float, Time, Array
1326
+ #
1327
+ # [Possible argument values:]
1328
+ # Hash or Array.
1329
+ # [:text, :binary, :auto]
1330
+ # %w[iso-2022-jp shift_jis euc-jp utf8 binary]
1331
+ # { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
1332
+ #
1333
+ # [Long style switch:]
1334
+ # Specifies a long style switch which takes a mandatory, optional or no
1335
+ # argument. It's a string of the following form:
1336
+ # "--switch=MANDATORY" or "--switch MANDATORY"
1337
+ # "--switch[=OPTIONAL]"
1338
+ # "--switch"
1339
+ #
1340
+ # [Short style switch:]
1341
+ # Specifies short style switch which takes a mandatory, optional or no
1342
+ # argument. It's a string of the following form:
1343
+ # "-xMANDATORY"
1344
+ # "-x[OPTIONAL]"
1345
+ # "-x"
1346
+ # There is also a special form which matches character range (not full
1347
+ # set of regular expression):
1348
+ # "-[a-z]MANDATORY"
1349
+ # "-[a-z][OPTIONAL]"
1350
+ # "-[a-z]"
1351
+ #
1352
+ # [Argument style and description:]
1353
+ # Instead of specifying mandatory or optional arguments directly in the
1354
+ # switch parameter, this separate parameter can be used.
1355
+ # "=MANDATORY"
1356
+ # "=[OPTIONAL]"
1357
+ #
1358
+ # [Description:]
1359
+ # Description string for the option.
1360
+ # "Run verbosely"
1361
+ # If you give multiple description strings, each string will be printed
1362
+ # line by line.
1363
+ #
1364
+ # [Handler:]
1365
+ # Handler for the parsed argument value. Either give a block or pass a
1366
+ # Proc or Method as an argument.
1367
+ #
1368
+ def make_switch(opts, block = nil)
1369
+ short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
1370
+ ldesc, sdesc, desc, arg = [], [], []
1371
+ default_style = Switch::NoArgument
1372
+ default_pattern = nil
1373
+ klass = nil
1374
+ q, a = nil
1375
+ has_arg = false
1376
+
1377
+ opts.each do |o|
1378
+ # argument class
1379
+ next if search(:atype, o) do |pat, c|
1380
+ klass = notwice(o, klass, 'type')
1381
+ if not_style and not_style != Switch::NoArgument
1382
+ not_pattern, not_conv = pat, c
1383
+ else
1384
+ default_pattern, conv = pat, c
1385
+ end
1386
+ end
1387
+
1388
+ # directly specified pattern(any object possible to match)
1389
+ if (!(String === o || Symbol === o)) and o.respond_to?(:match)
1390
+ pattern = notwice(o, pattern, 'pattern')
1391
+ if pattern.respond_to?(:convert)
1392
+ conv = pattern.method(:convert).to_proc
1393
+ else
1394
+ conv = SPLAT_PROC
1395
+ end
1396
+ next
1397
+ end
1398
+
1399
+ # anything others
1400
+ case o
1401
+ when Proc, Method
1402
+ block = notwice(o, block, 'block')
1403
+ when Array, Hash
1404
+ case pattern
1405
+ when CompletingHash
1406
+ when nil
1407
+ pattern = CompletingHash.new
1408
+ conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
1409
+ else
1410
+ raise ArgumentError, "argument pattern given twice"
1411
+ end
1412
+ o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
1413
+ when Module
1414
+ raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
1415
+ when *ArgumentStyle.keys
1416
+ style = notwice(ArgumentStyle[o], style, 'style')
1417
+ when /^--no-([^\[\]=\s]*)(.+)?/
1418
+ q, a = $1, $2
1419
+ o = notwice(a ? Object : TrueClass, klass, 'type')
1420
+ not_pattern, not_conv = search(:atype, o) unless not_style
1421
+ not_style = (not_style || default_style).guess(arg = a) if a
1422
+ default_style = Switch::NoArgument
1423
+ default_pattern, conv = search(:atype, FalseClass) unless default_pattern
1424
+ ldesc << "--no-#{q}"
1425
+ (q = q.downcase).tr!('_', '-')
1426
+ long << "no-#{q}"
1427
+ nolong << q
1428
+ when /^--\[no-\]([^\[\]=\s]*)(.+)?/
1429
+ q, a = $1, $2
1430
+ o = notwice(a ? Object : TrueClass, klass, 'type')
1431
+ if a
1432
+ default_style = default_style.guess(arg = a)
1433
+ default_pattern, conv = search(:atype, o) unless default_pattern
1434
+ end
1435
+ ldesc << "--[no-]#{q}"
1436
+ (o = q.downcase).tr!('_', '-')
1437
+ long << o
1438
+ not_pattern, not_conv = search(:atype, FalseClass) unless not_style
1439
+ not_style = Switch::NoArgument
1440
+ nolong << "no-#{o}"
1441
+ when /^--([^\[\]=\s]*)(.+)?/
1442
+ q, a = $1, $2
1443
+ if a
1444
+ o = notwice(NilClass, klass, 'type')
1445
+ default_style = default_style.guess(arg = a)
1446
+ default_pattern, conv = search(:atype, o) unless default_pattern
1447
+ end
1448
+ ldesc << "--#{q}"
1449
+ (o = q.downcase).tr!('_', '-')
1450
+ long << o
1451
+ when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
1452
+ q, a = $1, $2
1453
+ o = notwice(Object, klass, 'type')
1454
+ if a
1455
+ default_style = default_style.guess(arg = a)
1456
+ default_pattern, conv = search(:atype, o) unless default_pattern
1457
+ else
1458
+ has_arg = true
1459
+ end
1460
+ sdesc << "-#{q}"
1461
+ short << Regexp.new(q)
1462
+ when /^-(.)(.+)?/
1463
+ q, a = $1, $2
1464
+ if a
1465
+ o = notwice(NilClass, klass, 'type')
1466
+ default_style = default_style.guess(arg = a)
1467
+ default_pattern, conv = search(:atype, o) unless default_pattern
1468
+ end
1469
+ sdesc << "-#{q}"
1470
+ short << q
1471
+ when /^=/
1472
+ style = notwice(default_style.guess(arg = o), style, 'style')
1473
+ default_pattern, conv = search(:atype, Object) unless default_pattern
1474
+ else
1475
+ desc.push(o)
1476
+ end
1477
+ end
1478
+
1479
+ default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
1480
+ if !(short.empty? and long.empty?)
1481
+ if has_arg and default_style == Switch::NoArgument
1482
+ default_style = Switch::RequiredArgument
1483
+ end
1484
+ s = (style || default_style).new(pattern || default_pattern,
1485
+ conv, sdesc, ldesc, arg, desc, block)
1486
+ elsif !block
1487
+ if style or pattern
1488
+ raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
1489
+ end
1490
+ s = desc
1491
+ else
1492
+ short << pattern
1493
+ s = (style || default_style).new(pattern,
1494
+ conv, nil, nil, arg, desc, block)
1495
+ end
1496
+ return s, short, long,
1497
+ (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
1498
+ nolong
1499
+ end
1500
+
1501
+ def define(*opts, &block)
1502
+ top.append(*(sw = make_switch(opts, block)))
1503
+ sw[0]
1504
+ end
1505
+
1506
+ #
1507
+ # Add option switch and handler. See #make_switch for an explanation of
1508
+ # parameters.
1509
+ #
1510
+ def on(*opts, &block)
1511
+ define(*opts, &block)
1512
+ self
1513
+ end
1514
+ alias def_option define
1515
+
1516
+ def define_head(*opts, &block)
1517
+ top.prepend(*(sw = make_switch(opts, block)))
1518
+ sw[0]
1519
+ end
1520
+
1521
+ #
1522
+ # Add option switch like with #on, but at head of summary.
1523
+ #
1524
+ def on_head(*opts, &block)
1525
+ define_head(*opts, &block)
1526
+ self
1527
+ end
1528
+ alias def_head_option define_head
1529
+
1530
+ def define_tail(*opts, &block)
1531
+ base.append(*(sw = make_switch(opts, block)))
1532
+ sw[0]
1533
+ end
1534
+
1535
+ #
1536
+ # Add option switch like with #on, but at tail of summary.
1537
+ #
1538
+ def on_tail(*opts, &block)
1539
+ define_tail(*opts, &block)
1540
+ self
1541
+ end
1542
+ alias def_tail_option define_tail
1543
+
1544
+ #
1545
+ # Add separator in summary.
1546
+ #
1547
+ def separator(string)
1548
+ top.append(string, nil, nil)
1549
+ end
1550
+
1551
+ #
1552
+ # Parses command line arguments +argv+ in order. When a block is given,
1553
+ # each non-option argument is yielded. When optional +into+ keyword
1554
+ # argument is provided, the parsed option values are stored there via
1555
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
1556
+ # similar object).
1557
+ #
1558
+ # Returns the rest of +argv+ left unparsed.
1559
+ #
1560
+ def order(*argv, into: nil, &nonopt)
1561
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1562
+ order!(argv, into: into, &nonopt)
1563
+ end
1564
+
1565
+ #
1566
+ # Same as #order, but removes switches destructively.
1567
+ # Non-option arguments remain in +argv+.
1568
+ #
1569
+ def order!(argv = default_argv, into: nil, &nonopt)
1570
+ setter = ->(name, val) {into[name.to_sym] = val} if into
1571
+ parse_in_order(argv, setter, &nonopt)
1572
+ end
1573
+
1574
+ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
1575
+ opt, arg, val, rest = nil
1576
+ nonopt ||= proc {|a| throw :terminate, a}
1577
+ argv.unshift(arg) if arg = catch(:terminate) {
1578
+ while arg = argv.shift
1579
+ case arg
1580
+ # long option
1581
+ when /\A--([^=]*)(?:=(.*))?/m
1582
+ opt, rest = $1, $2
1583
+ opt.tr!('_', '-')
1584
+ begin
1585
+ sw, = complete(:long, opt, true)
1586
+ rescue ParseError
1587
+ raise $!.set_option(arg, true)
1588
+ end
1589
+ begin
1590
+ opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
1591
+ val = cb.call(val) if cb
1592
+ setter.call(sw.switch_name, val) if setter
1593
+ rescue ParseError
1594
+ raise $!.set_option(arg, rest)
1595
+ end
1596
+
1597
+ # short option
1598
+ when /\A-(.)((=).*|.+)?/m
1599
+ eq, rest, opt = $3, $2, $1
1600
+ has_arg, val = eq, rest
1601
+ begin
1602
+ sw, = search(:short, opt)
1603
+ unless sw
1604
+ begin
1605
+ sw, = complete(:short, opt)
1606
+ # short option matched.
1607
+ val = arg.delete_prefix('-')
1608
+ has_arg = true
1609
+ rescue InvalidOption
1610
+ # if no short options match, try completion with long
1611
+ # options.
1612
+ sw, = complete(:long, opt)
1613
+ eq ||= !rest
1614
+ end
1615
+ end
1616
+ rescue ParseError
1617
+ raise $!.set_option(arg, true)
1618
+ end
1619
+ begin
1620
+ opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
1621
+ raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
1622
+ argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
1623
+ val = cb.call(val) if cb
1624
+ setter.call(sw.switch_name, val) if setter
1625
+ rescue ParseError
1626
+ raise $!.set_option(arg, arg.length > 2)
1627
+ end
1628
+
1629
+ # non-option argument
1630
+ else
1631
+ catch(:prune) do
1632
+ visit(:each_option) do |sw0|
1633
+ sw = sw0
1634
+ sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
1635
+ end
1636
+ nonopt.call(arg)
1637
+ end
1638
+ end
1639
+ end
1640
+
1641
+ nil
1642
+ }
1643
+
1644
+ visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
1645
+
1646
+ argv
1647
+ end
1648
+ private :parse_in_order
1649
+
1650
+ #
1651
+ # Parses command line arguments +argv+ in permutation mode and returns
1652
+ # list of non-option arguments. When optional +into+ keyword
1653
+ # argument is provided, the parsed option values are stored there via
1654
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
1655
+ # similar object).
1656
+ #
1657
+ def permute(*argv, into: nil)
1658
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1659
+ permute!(argv, into: into)
1660
+ end
1661
+
1662
+ #
1663
+ # Same as #permute, but removes switches destructively.
1664
+ # Non-option arguments remain in +argv+.
1665
+ #
1666
+ def permute!(argv = default_argv, into: nil)
1667
+ nonopts = []
1668
+ order!(argv, into: into, &nonopts.method(:<<))
1669
+ argv[0, 0] = nonopts
1670
+ argv
1671
+ end
1672
+
1673
+ #
1674
+ # Parses command line arguments +argv+ in order when environment variable
1675
+ # POSIXLY_CORRECT is set, and in permutation mode otherwise.
1676
+ # When optional +into+ keyword argument is provided, the parsed option
1677
+ # values are stored there via <code>[]=</code> method (so it can be Hash,
1678
+ # or OpenStruct, or other similar object).
1679
+ #
1680
+ def parse(*argv, into: nil)
1681
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1682
+ parse!(argv, into: into)
1683
+ end
1684
+
1685
+ #
1686
+ # Same as #parse, but removes switches destructively.
1687
+ # Non-option arguments remain in +argv+.
1688
+ #
1689
+ def parse!(argv = default_argv, into: nil)
1690
+ if ENV.include?('POSIXLY_CORRECT')
1691
+ order!(argv, into: into)
1692
+ else
1693
+ permute!(argv, into: into)
1694
+ end
1695
+ end
1696
+
1697
+ #
1698
+ # Wrapper method for getopts.rb.
1699
+ #
1700
+ # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
1701
+ # # params["a"] = true # -a
1702
+ # # params["b"] = "1" # -b1
1703
+ # # params["foo"] = "1" # --foo
1704
+ # # params["bar"] = "x" # --bar x
1705
+ # # params["zot"] = "z" # --zot Z
1706
+ #
1707
+ def getopts(*args)
1708
+ argv = Array === args.first ? args.shift : default_argv
1709
+ single_options, *long_options = *args
1710
+
1711
+ result = {}
1712
+
1713
+ single_options.scan(/(.)(:)?/) do |opt, val|
1714
+ if val
1715
+ result[opt] = nil
1716
+ define("-#{opt} VAL")
1717
+ else
1718
+ result[opt] = false
1719
+ define("-#{opt}")
1720
+ end
1721
+ end if single_options
1722
+
1723
+ long_options.each do |arg|
1724
+ arg, desc = arg.split(';', 2)
1725
+ opt, val = arg.split(':', 2)
1726
+ if val
1727
+ result[opt] = val.empty? ? nil : val
1728
+ define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
1729
+ else
1730
+ result[opt] = false
1731
+ define("--#{opt}", *[desc].compact)
1732
+ end
1733
+ end
1734
+
1735
+ parse_in_order(argv, result.method(:[]=))
1736
+ result
1737
+ end
1738
+
1739
+ #
1740
+ # See #getopts.
1741
+ #
1742
+ def self.getopts(*args)
1743
+ new.getopts(*args)
1744
+ end
1745
+
1746
+ #
1747
+ # Traverses @stack, sending each element method +id+ with +args+ and
1748
+ # +block+.
1749
+ #
1750
+ def visit(id, *args, &block)
1751
+ @stack.reverse_each do |el|
1752
+ el.send(id, *args, &block)
1753
+ end
1754
+ nil
1755
+ end
1756
+ private :visit
1757
+
1758
+ #
1759
+ # Searches +key+ in @stack for +id+ hash and returns or yields the result.
1760
+ #
1761
+ def search(id, key)
1762
+ block_given = block_given?
1763
+ visit(:search, id, key) do |k|
1764
+ return block_given ? yield(k) : k
1765
+ end
1766
+ end
1767
+ private :search
1768
+
1769
+ #
1770
+ # Completes shortened long style option switch and returns pair of
1771
+ # canonical switch and switch descriptor OptionParser::Switch.
1772
+ #
1773
+ # +typ+:: Searching table.
1774
+ # +opt+:: Searching key.
1775
+ # +icase+:: Search case insensitive if true.
1776
+ # +pat+:: Optional pattern for completion.
1777
+ #
1778
+ def complete(typ, opt, icase = false, *pat)
1779
+ if pat.empty?
1780
+ search(typ, opt) {|sw| return [sw, opt]} # exact match or...
1781
+ end
1782
+ ambiguous = catch(:ambiguous) {
1783
+ visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
1784
+ }
1785
+ exc = ambiguous ? AmbiguousOption : InvalidOption
1786
+ raise exc.new(opt, additional: self.method(:additional_message).curry[typ])
1787
+ end
1788
+ private :complete
1789
+
1790
+ #
1791
+ # Returns additional info.
1792
+ #
1793
+ def additional_message(typ, opt)
1794
+ return unless typ and opt and defined?(DidYouMean::SpellChecker)
1795
+ all_candidates = []
1796
+ visit(:get_candidates, typ) do |candidates|
1797
+ all_candidates.concat(candidates)
1798
+ end
1799
+ all_candidates.select! {|cand| cand.is_a?(String) }
1800
+ checker = DidYouMean::SpellChecker.new(dictionary: all_candidates)
1801
+ DidYouMean.formatter.message_for(all_candidates & checker.correct(opt))
1802
+ end
1803
+
1804
+ def candidate(word)
1805
+ list = []
1806
+ case word
1807
+ when '-'
1808
+ long = short = true
1809
+ when /\A--/
1810
+ word, arg = word.split(/=/, 2)
1811
+ argpat = Completion.regexp(arg, false) if arg and !arg.empty?
1812
+ long = true
1813
+ when /\A-/
1814
+ short = true
1815
+ end
1816
+ pat = Completion.regexp(word, long)
1817
+ visit(:each_option) do |opt|
1818
+ next unless Switch === opt
1819
+ opts = (long ? opt.long : []) + (short ? opt.short : [])
1820
+ opts = Completion.candidate(word, true, pat, &opts.method(:each)).map(&:first) if pat
1821
+ if /\A=/ =~ opt.arg
1822
+ opts.map! {|sw| sw + "="}
1823
+ if arg and CompletingHash === opt.pattern
1824
+ if opts = opt.pattern.candidate(arg, false, argpat)
1825
+ opts.map!(&:last)
1826
+ end
1827
+ end
1828
+ end
1829
+ list.concat(opts)
1830
+ end
1831
+ list
1832
+ end
1833
+
1834
+ #
1835
+ # Loads options from file names as +filename+. Does nothing when the file
1836
+ # is not present. Returns whether successfully loaded.
1837
+ #
1838
+ # +filename+ defaults to basename of the program without suffix in a
1839
+ # directory ~/.options, then the basename with '.options' suffix
1840
+ # under XDG and Haiku standard places.
1841
+ #
1842
+ def load(filename = nil)
1843
+ unless filename
1844
+ basename = File.basename($0, '.*')
1845
+ return true if load(File.expand_path(basename, '~/.options')) rescue nil
1846
+ basename << ".options"
1847
+ return [
1848
+ # XDG
1849
+ ENV['XDG_CONFIG_HOME'],
1850
+ '~/.config',
1851
+ *ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
1852
+
1853
+ # Haiku
1854
+ '~/config/settings',
1855
+ ].any? {|dir|
1856
+ next if !dir or dir.empty?
1857
+ load(File.expand_path(basename, dir)) rescue nil
1858
+ }
1859
+ end
1860
+ begin
1861
+ parse(*IO.readlines(filename).each {|s| s.chomp!})
1862
+ true
1863
+ rescue Errno::ENOENT, Errno::ENOTDIR
1864
+ false
1865
+ end
1866
+ end
1867
+
1868
+ #
1869
+ # Parses environment variable +env+ or its uppercase with splitting like a
1870
+ # shell.
1871
+ #
1872
+ # +env+ defaults to the basename of the program.
1873
+ #
1874
+ def environment(env = File.basename($0, '.*'))
1875
+ env = ENV[env] || ENV[env.upcase] or return
1876
+ require 'shellwords'
1877
+ parse(*Shellwords.shellwords(env))
1878
+ end
1879
+
1880
+ #
1881
+ # Acceptable argument classes
1882
+ #
1883
+
1884
+ #
1885
+ # Any string and no conversion. This is fall-back.
1886
+ #
1887
+ accept(Object) {|s,|s or s.nil?}
1888
+
1889
+ accept(NilClass) {|s,|s}
1890
+
1891
+ #
1892
+ # Any non-empty string, and no conversion.
1893
+ #
1894
+ accept(String, /.+/m) {|s,*|s}
1895
+
1896
+ #
1897
+ # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
1898
+ # for 0x, and decimal for others; with optional sign prefix. Converts to
1899
+ # Integer.
1900
+ #
1901
+ decimal = '\d+(?:_\d+)*'
1902
+ binary = 'b[01]+(?:_[01]+)*'
1903
+ hex = 'x[\da-f]+(?:_[\da-f]+)*'
1904
+ octal = "0(?:[0-7]+(?:_[0-7]+)*|#{binary}|#{hex})?"
1905
+ integer = "#{octal}|#{decimal}"
1906
+
1907
+ accept(Integer, %r"\A[-+]?(?:#{integer})\z"io) {|s,|
1908
+ begin
1909
+ Integer(s)
1910
+ rescue ArgumentError
1911
+ raise OptionParser::InvalidArgument, s
1912
+ end if s
1913
+ }
1914
+
1915
+ #
1916
+ # Float number format, and converts to Float.
1917
+ #
1918
+ float = "(?:#{decimal}(?=(.)?)(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
1919
+ floatpat = %r"\A[-+]?#{float}\z"io
1920
+ accept(Float, floatpat) {|s,| s.to_f if s}
1921
+
1922
+ #
1923
+ # Generic numeric format, converts to Integer for integer format, Float
1924
+ # for float format, and Rational for rational format.
1925
+ #
1926
+ real = "[-+]?(?:#{octal}|#{float})"
1927
+ accept(Numeric, /\A(#{real})(?:\/(#{real}))?\z/io) {|s, d, f, n,|
1928
+ if n
1929
+ Rational(d, n)
1930
+ elsif f
1931
+ Float(s)
1932
+ else
1933
+ Integer(s)
1934
+ end
1935
+ }
1936
+
1937
+ #
1938
+ # Decimal integer format, to be converted to Integer.
1939
+ #
1940
+ DecimalInteger = /\A[-+]?#{decimal}\z/io
1941
+ accept(DecimalInteger, DecimalInteger) {|s,|
1942
+ begin
1943
+ Integer(s, 10)
1944
+ rescue ArgumentError
1945
+ raise OptionParser::InvalidArgument, s
1946
+ end if s
1947
+ }
1948
+
1949
+ #
1950
+ # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
1951
+ # Integer.
1952
+ #
1953
+ OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))\z/io
1954
+ accept(OctalInteger, OctalInteger) {|s,|
1955
+ begin
1956
+ Integer(s, 8)
1957
+ rescue ArgumentError
1958
+ raise OptionParser::InvalidArgument, s
1959
+ end if s
1960
+ }
1961
+
1962
+ #
1963
+ # Decimal integer/float number format, to be converted to Integer for
1964
+ # integer format, Float for float format.
1965
+ #
1966
+ DecimalNumeric = floatpat # decimal integer is allowed as float also.
1967
+ accept(DecimalNumeric, floatpat) {|s, f|
1968
+ begin
1969
+ if f
1970
+ Float(s)
1971
+ else
1972
+ Integer(s)
1973
+ end
1974
+ rescue ArgumentError
1975
+ raise OptionParser::InvalidArgument, s
1976
+ end if s
1977
+ }
1978
+
1979
+ #
1980
+ # Boolean switch, which means whether it is present or not, whether it is
1981
+ # absent or not with prefix no-, or it takes an argument
1982
+ # yes/no/true/false/+/-.
1983
+ #
1984
+ yesno = CompletingHash.new
1985
+ %w[- no false].each {|el| yesno[el] = false}
1986
+ %w[+ yes true].each {|el| yesno[el] = true}
1987
+ yesno['nil'] = false # should be nil?
1988
+ accept(TrueClass, yesno) {|arg, val| val == nil or val}
1989
+ #
1990
+ # Similar to TrueClass, but defaults to false.
1991
+ #
1992
+ accept(FalseClass, yesno) {|arg, val| val != nil and val}
1993
+
1994
+ #
1995
+ # List of strings separated by ",".
1996
+ #
1997
+ accept(Array) do |s, |
1998
+ if s
1999
+ s = s.split(',').collect {|ss| ss unless ss.empty?}
2000
+ end
2001
+ s
2002
+ end
2003
+
2004
+ #
2005
+ # Regular expression with options.
2006
+ #
2007
+ accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
2008
+ f = 0
2009
+ if o
2010
+ f |= Regexp::IGNORECASE if /i/ =~ o
2011
+ f |= Regexp::MULTILINE if /m/ =~ o
2012
+ f |= Regexp::EXTENDED if /x/ =~ o
2013
+ k = o.delete("imx")
2014
+ k = nil if k.empty?
2015
+ end
2016
+ Regexp.new(s || all, f, k)
2017
+ end
2018
+
2019
+ #
2020
+ # Exceptions
2021
+ #
2022
+
2023
+ #
2024
+ # Base class of exceptions from OptionParser.
2025
+ #
2026
+ class ParseError < RuntimeError
2027
+ # Reason which caused the error.
2028
+ Reason = 'parse error'
2029
+
2030
+ def initialize(*args, additional: nil)
2031
+ @additional = additional
2032
+ @arg0, = args
2033
+ @args = args
2034
+ @reason = nil
2035
+ end
2036
+
2037
+ attr_reader :args
2038
+ attr_writer :reason
2039
+ attr_accessor :additional
2040
+
2041
+ #
2042
+ # Pushes back erred argument(s) to +argv+.
2043
+ #
2044
+ def recover(argv)
2045
+ argv[0, 0] = @args
2046
+ argv
2047
+ end
2048
+
2049
+ def self.filter_backtrace(array)
2050
+ unless $DEBUG
2051
+ array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
2052
+ end
2053
+ array
2054
+ end
2055
+
2056
+ def set_backtrace(array)
2057
+ super(self.class.filter_backtrace(array))
2058
+ end
2059
+
2060
+ def set_option(opt, eq)
2061
+ if eq
2062
+ @args[0] = opt
2063
+ else
2064
+ @args.unshift(opt)
2065
+ end
2066
+ self
2067
+ end
2068
+
2069
+ #
2070
+ # Returns error reason. Override this for I18N.
2071
+ #
2072
+ def reason
2073
+ @reason || self.class::Reason
2074
+ end
2075
+
2076
+ def inspect
2077
+ "#<#{self.class}: #{args.join(' ')}>"
2078
+ end
2079
+
2080
+ #
2081
+ # Default stringizing method to emit standard error message.
2082
+ #
2083
+ def message
2084
+ "#{reason}: #{args.join(' ')}#{additional[@arg0] if additional}"
2085
+ end
2086
+
2087
+ alias to_s message
2088
+ end
2089
+
2090
+ #
2091
+ # Raises when ambiguously completable string is encountered.
2092
+ #
2093
+ class AmbiguousOption < ParseError
2094
+ const_set(:Reason, 'ambiguous option')
2095
+ end
2096
+
2097
+ #
2098
+ # Raises when there is an argument for a switch which takes no argument.
2099
+ #
2100
+ class NeedlessArgument < ParseError
2101
+ const_set(:Reason, 'needless argument')
2102
+ end
2103
+
2104
+ #
2105
+ # Raises when a switch with mandatory argument has no argument.
2106
+ #
2107
+ class MissingArgument < ParseError
2108
+ const_set(:Reason, 'missing argument')
2109
+ end
2110
+
2111
+ #
2112
+ # Raises when switch is undefined.
2113
+ #
2114
+ class InvalidOption < ParseError
2115
+ const_set(:Reason, 'invalid option')
2116
+ end
2117
+
2118
+ #
2119
+ # Raises when the given argument does not match required format.
2120
+ #
2121
+ class InvalidArgument < ParseError
2122
+ const_set(:Reason, 'invalid argument')
2123
+ end
2124
+
2125
+ #
2126
+ # Raises when the given argument word can't be completed uniquely.
2127
+ #
2128
+ class AmbiguousArgument < InvalidArgument
2129
+ const_set(:Reason, 'ambiguous argument')
2130
+ end
2131
+
2132
+ #
2133
+ # Miscellaneous
2134
+ #
2135
+
2136
+ #
2137
+ # Extends command line arguments array (ARGV) to parse itself.
2138
+ #
2139
+ module Arguable
2140
+
2141
+ #
2142
+ # Sets OptionParser object, when +opt+ is +false+ or +nil+, methods
2143
+ # OptionParser::Arguable#options and OptionParser::Arguable#options= are
2144
+ # undefined. Thus, there is no ways to access the OptionParser object
2145
+ # via the receiver object.
2146
+ #
2147
+ def options=(opt)
2148
+ unless @optparse = opt
2149
+ class << self
2150
+ undef_method(:options)
2151
+ undef_method(:options=)
2152
+ end
2153
+ end
2154
+ end
2155
+
2156
+ #
2157
+ # Actual OptionParser object, automatically created if nonexistent.
2158
+ #
2159
+ # If called with a block, yields the OptionParser object and returns the
2160
+ # result of the block. If an OptionParser::ParseError exception occurs
2161
+ # in the block, it is rescued, a error message printed to STDERR and
2162
+ # +nil+ returned.
2163
+ #
2164
+ def options
2165
+ @optparse ||= OptionParser.new
2166
+ @optparse.default_argv = self
2167
+ block_given? or return @optparse
2168
+ begin
2169
+ yield @optparse
2170
+ rescue ParseError
2171
+ @optparse.warn $!
2172
+ nil
2173
+ end
2174
+ end
2175
+
2176
+ #
2177
+ # Parses +self+ destructively in order and returns +self+ containing the
2178
+ # rest arguments left unparsed.
2179
+ #
2180
+ def order!(&blk) options.order!(self, &blk) end
2181
+
2182
+ #
2183
+ # Parses +self+ destructively in permutation mode and returns +self+
2184
+ # containing the rest arguments left unparsed.
2185
+ #
2186
+ def permute!() options.permute!(self) end
2187
+
2188
+ #
2189
+ # Parses +self+ destructively and returns +self+ containing the
2190
+ # rest arguments left unparsed.
2191
+ #
2192
+ def parse!() options.parse!(self) end
2193
+
2194
+ #
2195
+ # Substitution of getopts is possible as follows. Also see
2196
+ # OptionParser#getopts.
2197
+ #
2198
+ # def getopts(*args)
2199
+ # ($OPT = ARGV.getopts(*args)).each do |opt, val|
2200
+ # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
2201
+ # end
2202
+ # rescue OptionParser::ParseError
2203
+ # end
2204
+ #
2205
+ def getopts(*args)
2206
+ options.getopts(self, *args)
2207
+ end
2208
+
2209
+ #
2210
+ # Initializes instance variable.
2211
+ #
2212
+ def self.extend_object(obj)
2213
+ super
2214
+ obj.instance_eval {@optparse = nil}
2215
+ end
2216
+ def initialize(*args)
2217
+ super
2218
+ @optparse = nil
2219
+ end
2220
+ end
2221
+
2222
+ #
2223
+ # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
2224
+ # and DecimalNumeric. See Acceptable argument classes (in source code).
2225
+ #
2226
+ module Acceptables
2227
+ const_set(:DecimalInteger, OptionParser::DecimalInteger)
2228
+ const_set(:OctalInteger, OptionParser::OctalInteger)
2229
+ const_set(:DecimalNumeric, OptionParser::DecimalNumeric)
2230
+ end
2231
+ end
2232
+
2233
+ # ARGV is arguable by OptionParser
2234
+ ARGV.extend(OptionParser::Arguable)
2235
+
2236
+ # An alias for OptionParser.
2237
+ OptParse = OptionParser # :nodoc: