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