cmd-optparse.rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: