optparse 0.1.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.
@@ -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: