cli-option_parser.rb 0.5.2

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