trad-getopt 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (7) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +24 -0
  3. data/Rakefile +38 -0
  4. data/test.rb +501 -0
  5. data/trad-getopt.rb +248 -0
  6. data/trad-getopt.txt +190 -0
  7. metadata +48 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 477c3ba1fa3b783d818c18c3a6ded9a1af536059
4
+ data.tar.gz: 68170ced8654712a2fb5dbe196293c7e5fe961f9
5
+ SHA512:
6
+ metadata.gz: ebf8446087fcbe516a85dbf93f0fd564f7bb2ab562061ee18459e24ff9e1bdbf0f17ce13d9ef3e6de86700e7f2bec844c6ec3d78538283cb643f61afab137b6d
7
+ data.tar.gz: 5bb3b2bfe2ad16f387874e4ccb8125995fb10bf4e42d443f7a356459668f1e243ed7867f29be5b1ac13a702dee795daccd12bda996c732dd9fe5f3199776eb72
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2017, NOZAWA Hiromasa. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are
5
+ met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in
11
+ the documentation and/or other materials provided with the
12
+ distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'rake/clean'
2
+ require "rubygems/package_task"
3
+
4
+ require "./trad-getopt.rb" # Getopt::VERSION
5
+
6
+ task :default => :gem
7
+
8
+ task :gem
9
+ spec = Gem::Specification.new { |s|
10
+ s.name = "trad-getopt"
11
+ s.version = Getopt::VERSION
12
+ s.author = "NOZAWA Hiromasa"
13
+ s.summary = "rather traditional getopt()"
14
+ s.license = "BSD-2-Clause"
15
+ s.homepage = "https://github.com/noz/ruby-trad-getopt"
16
+ s.files = FileList[
17
+ "LICENSE",
18
+ "Rakefile",
19
+ "test.rb",
20
+ "trad-getopt.rb",
21
+ "trad-getopt.txt",
22
+ ]
23
+ s.require_path = "."
24
+ }
25
+ Gem::PackageTask.new(spec) { |pkg|
26
+ pkg.need_tar_gz = true
27
+ pkg.need_tar_bz2 = true
28
+ pkg.need_zip = true
29
+ }
30
+
31
+ # require "rake/testtask"
32
+ # Rake::TestTask.new { |t|
33
+ # t.test_files = FileList["test.rb"]
34
+ # }
35
+ desc "do unit test"
36
+ task :test {
37
+ ruby "-w", "test.rb"
38
+ }
data/test.rb ADDED
@@ -0,0 +1,501 @@
1
+ require "test/unit"
2
+ require "./trad-getopt.rb"
3
+
4
+ class Test_getopt < Test::Unit::TestCase
5
+
6
+ test "empty argv" do
7
+ av = []
8
+ assert_equal nil, getopt(av, "a")
9
+ assert_equal [], av
10
+ end
11
+ test "empty opts" do
12
+ av = [ "a" ]
13
+ assert_equal nil, getopt(av, "")
14
+ assert_equal [ "a" ], av
15
+ end
16
+ test "nil opts" do
17
+ av = [ "a" ]
18
+ assert_equal nil, getopt(av, nil)
19
+ assert_equal [ "a" ], av
20
+ end
21
+
22
+ test "stop at non option" do
23
+ av = ["foo"]
24
+ assert_equal nil, getopt(av, "-a")
25
+ assert_equal ["foo"], av
26
+ end
27
+ test "unknown error" do
28
+ av = [ "-x" ]
29
+ $stderr = StringIO.new
30
+ got = getopt(av, "a")
31
+ msg = $stderr.string
32
+ $stderr = STDERR
33
+ assert_equal [:unknown_option, "x"], got
34
+ assert_equal "test.rb: unknown option - x\n", msg
35
+ assert_equal [], av
36
+ end
37
+
38
+ test "short noarg" do
39
+ av = [ "-a", "foo" ]
40
+ assert_equal ["a"], getopt(av, "a")
41
+ assert_equal ["foo"], av
42
+ end
43
+
44
+ test "short reqarg" do
45
+ av = [ "-a", "foo" ]
46
+ assert_equal ["a", "foo"], getopt(av, "a:")
47
+ assert_equal [], av
48
+ end
49
+ test "short reqarg. error" do
50
+ av = [ "-a" ]
51
+ $stderr = StringIO.new
52
+ got = getopt(av, "a:")
53
+ msg = $stderr.string
54
+ $stderr = STDERR
55
+ assert_equal [:argument_required, "a"], got
56
+ assert_equal "test.rb: option requires an argument - a\n", msg
57
+ assert_equal [], av
58
+ end
59
+
60
+ test "short optarg, with arg" do
61
+ av = [ "-afoo" ]
62
+ assert_equal ["a", "foo"], getopt(av, "a::")
63
+ assert_equal [], av
64
+ end
65
+ test "short optarg, no arg" do
66
+ av = [ "-a", "foo" ]
67
+ assert_equal [ "a", nil ], getopt(av, "a::")
68
+ assert_equal [ "foo" ], av
69
+ end
70
+ test "short optarg, no arg, at tail" do
71
+ av = [ "-a" ]
72
+ assert_equal [ "a", nil ], getopt(av, "a::")
73
+ assert_equal [], av
74
+ end
75
+ test "short optarg, disabled" do
76
+ av = [ "-a" ]
77
+ $stderr = StringIO.new
78
+ got = getopt(av, "a::", optional_short:false)
79
+ $stderr = STDERR
80
+ assert_equal [ :argument_required, "a"], got
81
+ end
82
+
83
+ ### concatenation
84
+
85
+ test "concat, noarg + noarg" do
86
+ av = [ "-ab" ]
87
+ opts = "ab"
88
+ assert_equal ["a"], getopt(av, opts)
89
+ assert_equal ["b"], getopt(av, opts)
90
+ end
91
+ test "concat, noarg + reqarg + arg" do
92
+ av = [ "-abfoo" ]
93
+ opts = "ab:"
94
+ assert_equal ["a"], getopt(av, opts)
95
+ assert_equal ["b", "foo"], getopt(av, opts)
96
+ end
97
+
98
+ ### special chars
99
+
100
+ test "single `-'" do
101
+ av = [ "-" ]
102
+ assert_equal nil, getopt(av, "a")
103
+ assert_equal ["-"], av
104
+ end
105
+ test "stop by `--'" do
106
+ av = [ "--" ]
107
+ assert_equal nil, getopt(av, "a")
108
+ assert_equal [], av
109
+ end
110
+
111
+ test "stop_by_double_hyphen, disable" do
112
+ av = [ "--" ]
113
+ assert_equal [ "-" ], getopt(av, "-", stop_by_double_hyphen:false)
114
+ end
115
+
116
+ test "hyphen in concat, as option" do
117
+ av = [ "-a-" ]
118
+ opts = "a-"
119
+ assert_equal ["a"], getopt(av, opts)
120
+ assert_equal ["-"], getopt(av, opts)
121
+ assert_equal [], av
122
+ end
123
+ test "hyphen in concat, not as option" do
124
+ av = [ "-a-" ]
125
+ opts = "a"
126
+ assert_equal ["a"], getopt(av, opts)
127
+ $stderr = StringIO.new
128
+ got = getopt(av, opts)
129
+ msg = $stderr.string
130
+ $stderr = STDERR
131
+ assert_equal [:unknown_option, "-"], got
132
+ assert_equal "test.rb: unknown option - -\n", msg
133
+ assert_equal [], av
134
+ end
135
+
136
+ test "colon as option" do
137
+ av = [ "-:" ]
138
+ assert_equal [":"], getopt(av, ":a")
139
+ end
140
+ test "colon not as option" do
141
+ av = [ "-:" ]
142
+ $stderr = StringIO.new
143
+ got = getopt(av, "a:")
144
+ msg = $stderr.string
145
+ $stderr = STDERR
146
+ assert_equal [:unknown_option, ":"], got
147
+ assert_equal "test.rb: unknown option - :\n", msg
148
+ assert_equal [], av
149
+ end
150
+
151
+ ### keywords
152
+
153
+ test "program_name" do
154
+ av = [ "-x" ]
155
+ $stderr = StringIO.new
156
+ getopt(av, "a", error_message:true, program_name:"foo")
157
+ msg = $stderr.string
158
+ $stderr = STDERR
159
+ assert_equal "foo: unknown option - x\n", msg
160
+ end
161
+
162
+ test "error_message" do
163
+ av = [ "-x" ]
164
+ $stderr = StringIO.new
165
+ getopt(av, "a", error_message:false)
166
+ msg = $stderr.string
167
+ $stderr = STDERR
168
+ assert_equal "", msg
169
+ end
170
+
171
+ test "use_exception, Getopt::UnknownOptionError" do
172
+ av = [ "-x" ]
173
+ begin
174
+ getopt(av, "a", use_exception:true)
175
+ rescue => ex
176
+ assert_equal Getopt::UnknownOptionError, ex.class
177
+ assert_equal "x", ex.option
178
+ assert_equal "unknown option", ex.message
179
+ end
180
+ end
181
+ test "use_exception, Getopt::ArgumentRequiredError" do
182
+ av = [ "-a" ]
183
+ begin
184
+ getopt(av, "a:", use_exception:true)
185
+ rescue => ex
186
+ assert_equal Getopt::ArgumentRequiredError, ex.class
187
+ assert_equal "a", ex.option
188
+ assert_equal "option requires an argument", ex.message
189
+ end
190
+ end
191
+
192
+ test "permute" do
193
+ av = [ "foo", "-a", "bar" ]
194
+ opts = "a"
195
+ assert_equal ["a"], getopt(av, opts, permute:true)
196
+ assert_equal nil, getopt(av, opts, permute:true)
197
+ assert_equal ["foo", "bar"], av
198
+ end
199
+ test "permute, reqarg" do
200
+ av = [ "foo", "-a", "bar", "baz" ]
201
+ opts = "a:"
202
+ assert_equal ["a", "bar"], getopt(av, opts, permute:true)
203
+ assert_equal nil, getopt(av, opts, permute:true)
204
+ assert_equal ["foo", "baz"], av
205
+ end
206
+
207
+ test "allow_empty_optarg" do
208
+ av = [ "-a", "" ]
209
+ opts = "a:"
210
+ $stderr = StringIO.new
211
+ assert_equal [:argument_required, "a"], getopt(av, opts, allow_empty_optarg:false)
212
+ $stderr = STDERR
213
+ end
214
+ test "allow_empty_optarg. long" do
215
+ av = [ "--foo=" ]
216
+ longopts = { "foo" => :required_argument }
217
+ $stderr = StringIO.new
218
+ assert_equal [:argument_required, "foo"], getopt(av, "", longopts, allow_empty_optarg:false)
219
+ $stderr = STDERR
220
+ end
221
+ test "allow_empty_optarg. long 2" do
222
+ av = [ "--foo", "" ]
223
+ longopts = { "foo" => :required_argument }
224
+ $stderr = StringIO.new
225
+ assert_equal [:argument_required, "foo"], getopt(av, "", longopts, allow_empty_optarg:false)
226
+ $stderr = STDERR
227
+ end
228
+ test "allow_empty_optarg. optional long" do
229
+ av = [ "--foo=" ]
230
+ longopts = { "foo" => :optional_argument }
231
+ $stderr = StringIO.new
232
+ assert_equal [:argument_required, "foo"], getopt(av, "", longopts, allow_empty_optarg:false)
233
+ $stderr = STDERR
234
+ end
235
+
236
+ ### short context
237
+
238
+ test "short context" do
239
+ av = [ "-a-" ]
240
+ opts = "a"
241
+ assert_equal [ "a" ], getopt(av, opts)
242
+ $stderr = StringIO.new
243
+ assert_equal [ :unknown_option, "-" ], getopt(av, opts)
244
+ $stderr = STDERR
245
+ end
246
+ test "short context, not long option" do
247
+ av = [ "-a-foo" ]
248
+ opts = "afo-"
249
+ lopts = {
250
+ "foo" => :no_argument
251
+ }
252
+ assert_equal [ "a" ], getopt(av, opts, lopts)
253
+ assert_equal [ "-" ], getopt(av, opts, lopts)
254
+ assert_equal [ "f" ], getopt(av, opts, lopts)
255
+ end
256
+ test "short context, not long option, error" do
257
+ av = [ "-a-foo" ]
258
+ opts = "a-"
259
+ lopts = {
260
+ "foo" => :no_argument
261
+ }
262
+ assert_equal [ "a" ], getopt(av, opts, lopts)
263
+ assert_equal [ "-" ], getopt(av, opts, lopts)
264
+ $stderr = StringIO.new
265
+ assert_equal [ :unknown_option, "f" ], getopt(av, opts, lopts)
266
+ $stderr = STDERR
267
+ end
268
+
269
+ ### long option
270
+
271
+ test "long option" do
272
+ av = [ "--foo" ]
273
+ opts = "fo-"
274
+ lopts = {
275
+ "foo" => :no_argument
276
+ }
277
+ assert_equal [ "foo" ], getopt(av, opts, lopts)
278
+ end
279
+
280
+ test "not long option" do
281
+ av = [ "-foo" ]
282
+ opts = "fo"
283
+ lopts = {
284
+ "foo" => :no_argument
285
+ }
286
+ assert_equal [ "f" ], getopt(av, opts, lopts)
287
+ assert_equal [ "o" ], getopt(av, opts, lopts)
288
+ assert_equal [ "o" ], getopt(av, opts, lopts)
289
+ end
290
+
291
+ test "wrong long option type" do
292
+ av = [ "--foo" ]
293
+ lopts = {
294
+ "foo" => :bar
295
+ }
296
+ begin
297
+ getopt(["--foo"], "", lopts)
298
+ rescue => ex
299
+ assert_equal ArgumentError, ex.class
300
+ assert_equal [ "--foo" ], av
301
+ end
302
+ end
303
+ test "wrong long option type, permute" do
304
+ av = [ "a", "--foo", "b" ]
305
+ lopts = {
306
+ "foo" => :bar
307
+ }
308
+ begin
309
+ getopt(["--foo"], "", lopts, permute:true)
310
+ rescue => ex
311
+ assert_equal ArgumentError, ex.class
312
+ assert_equal [ "a", "--foo", "b" ], av
313
+ end
314
+ end
315
+
316
+ test "unknown long option" do
317
+ av = [ "--bar" ]
318
+ lopts = {
319
+ "foo" => :no_argument
320
+ }
321
+ $stderr = StringIO.new
322
+ got = getopt(av, "", lopts)
323
+ msg = $stderr.string
324
+ $stderr = STDERR
325
+ assert_equal [ :unknown_option, "bar" ], got
326
+ assert_equal "test.rb: unknown option - bar\n", msg
327
+ end
328
+
329
+ test "no_argument" do
330
+ av = [ "--foo" ]
331
+ lopts = {
332
+ "foo" => :no_argument
333
+ }
334
+ assert_equal [ "foo" ], getopt(av, "", lopts)
335
+ end
336
+ test "no_argument, error" do
337
+ av = [ "--foo=bar" ]
338
+ lopts = {
339
+ "foo" => :no_argument
340
+ }
341
+ $stderr = StringIO.new
342
+ got = getopt(av, "", lopts)
343
+ msg = $stderr.string
344
+ $stderr = STDERR
345
+ assert_equal [ :argument_given, "foo" ], got
346
+ assert_equal "test.rb: option doesn't take an argument - foo\n", msg
347
+ end
348
+ test "no_argument, exception" do
349
+ av = [ "--foo=bar" ]
350
+ lopts = {
351
+ "foo" => :no_argument
352
+ }
353
+ begin
354
+ getopt(av, "", lopts, use_exception:true)
355
+ rescue => ex
356
+ assert_equal Getopt::ArgumentGivenError, ex.class
357
+ assert_equal "foo", ex.option
358
+ assert_equal "option doesn't take an argument", ex.message
359
+ end
360
+ end
361
+
362
+ test "required_argument" do
363
+ av = [ "--foo=bar" ]
364
+ lopts = {
365
+ "foo" => :required_argument
366
+ }
367
+ assert_equal [ "foo", "bar" ], getopt(av, "", lopts)
368
+ end
369
+ test "required_argument, split" do
370
+ av = [ "--foo", "bar" ]
371
+ lopts = {
372
+ "foo" => :required_argument
373
+ }
374
+ assert_equal [ "foo", "bar" ], getopt(av, "", lopts)
375
+ end
376
+ test "required_argument, empty arg" do
377
+ av = [ "--foo=" ]
378
+ lopts = {
379
+ "foo" => :required_argument
380
+ }
381
+ assert_equal [ "foo", "" ], getopt(av, "", lopts)
382
+ end
383
+ test "required_argument, error" do
384
+ av = [ "--foo" ]
385
+ lopts = {
386
+ "foo" => :required_argument
387
+ }
388
+ $stderr = StringIO.new
389
+ got = getopt(av, "", lopts)
390
+ msg = $stderr.string
391
+ $stderr = STDERR
392
+ assert_equal [ :argument_required, "foo" ], got
393
+ assert_equal "test.rb: option requires an argument - foo\n", msg
394
+ end
395
+ test "required_argument, exception" do
396
+ av = [ "--foo" ]
397
+ lopts = {
398
+ "foo" => :required_argument
399
+ }
400
+ begin
401
+ getopt(av, "", lopts, use_exception:true)
402
+ rescue => ex
403
+ assert_equal Getopt::ArgumentRequiredError, ex.class
404
+ assert_equal "foo", ex.option
405
+ assert_equal "option requires an argument", ex.message
406
+ end
407
+ end
408
+
409
+ test "optional_argument, with arg" do
410
+ av = [ "--foo=bar" ]
411
+ lopts = {
412
+ "foo" => :optional_argument
413
+ }
414
+ assert_equal [ "foo", "bar" ], getopt(av, "", lopts)
415
+ end
416
+ test "optional_argument, empty arg" do
417
+ av = [ "--foo=" ]
418
+ lopts = {
419
+ "foo" => :optional_argument
420
+ }
421
+ assert_equal [ "foo", "" ], getopt(av, "", lopts)
422
+ end
423
+ test "optional_argument, no arg" do
424
+ av = [ "--foo", "bar" ]
425
+ lopts = {
426
+ "foo" => :optional_argument
427
+ }
428
+ assert_equal [ "foo", nil ], getopt(av, "", lopts)
429
+ end
430
+ test "optional_argument, no arg, at tail" do
431
+ av = [ "--foo" ]
432
+ lopts = {
433
+ "foo" => :optional_argument
434
+ }
435
+ assert_equal [ "foo", nil ], getopt(av, "", lopts)
436
+ end
437
+
438
+ test "unique abbrev, no candidates" do
439
+ av = [ "--fo" ]
440
+ lopts = {
441
+ "foo" => :no_argument
442
+ }
443
+ assert_equal [ "foo" ], getopt(av, "", lopts)
444
+ end
445
+ test "unique abbrev" do
446
+ av = [ "--foo-" ]
447
+ lopts = {
448
+ "foo" => :no_argument,
449
+ "foo-bar" => :no_argument
450
+ }
451
+ assert_equal [ "foo-bar" ], getopt(av, "", lopts)
452
+ end
453
+ test "abbrev, exact match" do
454
+ av = [ "--foo" ]
455
+ lopts = {
456
+ "foo" => :no_argument,
457
+ "foo-bar" => :no_argument
458
+ }
459
+ assert_equal [ "foo" ], getopt(av, "", lopts)
460
+ end
461
+ test "abbrev, ambiguous" do
462
+ av = [ "--foo" ]
463
+ lopts = {
464
+ "foo1" => :no_argument,
465
+ "foo2" => :no_argument
466
+ }
467
+ $stderr = StringIO.new
468
+ got = getopt(av, "", lopts)
469
+ msg = $stderr.string
470
+ $stderr = STDERR
471
+ assert_equal [ :ambiguous_option, "foo", ["foo1", "foo2"] ], got
472
+ assert_equal "test.rb: ambiguos option (--foo1 --foo2) - foo\n", msg
473
+ end
474
+ test "abbrev, ambiguous, exception" do
475
+ av = [ "--foo" ]
476
+ lopts = {
477
+ "foo1" => :no_argument,
478
+ "foo2" => :no_argument
479
+ }
480
+ begin
481
+ getopt(av, "", lopts, use_exception:true)
482
+ rescue => ex
483
+ assert_equal Getopt::AmbiguousOptionError, ex.class
484
+ assert_equal "foo", ex.option
485
+ assert_equal "ambiguos option (--foo1 --foo2)", ex.message
486
+ end
487
+ end
488
+
489
+ test "abbrev disabled" do
490
+ av = [ "--fo" ]
491
+ lopts = {
492
+ "foo" => :no_argument,
493
+ }
494
+ $stderr = StringIO.new
495
+ got = getopt(av, "", lopts, abbreviation:false)
496
+ msg = $stderr.string
497
+ $stderr = STDERR
498
+ assert_equal [ :unknown_option, "fo" ], got
499
+ assert_equal "test.rb: unknown option - fo\n", msg
500
+ end
501
+ end
data/trad-getopt.rb ADDED
@@ -0,0 +1,248 @@
1
+ # rather traditional getopt for Ruby
2
+
3
+ module Getopt
4
+ VERSION = "1.1.0"
5
+
6
+ class GetoptError < StandardError
7
+ def initialize option, message
8
+ super message
9
+ @option = option
10
+ end
11
+ attr_reader :option
12
+ end
13
+ class UnknownOptionError < GetoptError
14
+ def initialize option, message = "unknown option"
15
+ super option, message
16
+ end
17
+ end
18
+ class ArgumentRequiredError < GetoptError
19
+ def initialize option, message = "option requires an argument"
20
+ super option, message
21
+ end
22
+ end
23
+ class ArgumentGivenError < GetoptError
24
+ def initialize option, message = "option doesn't take an argument"
25
+ super option, message
26
+ end
27
+ end
28
+ class AmbiguousOptionError < GetoptError
29
+ def initialize option, message, candidates
30
+ message ||= "ambiguos option"
31
+ @candidates = candidates
32
+ cands = candidates.collect { |c| "--#{c}" }.join " "
33
+ super option, "#{message} (#{cands})"
34
+ end
35
+ attr_reader :candidates
36
+ end
37
+ end
38
+
39
+ def getopt(argv, opts, longopts = nil,
40
+ abbreviation: true, allow_empty_optarg: true,
41
+ error_message: true, optional_short: true, permute: false,
42
+ program_name: nil, stop_by_double_hyphen: true,
43
+ use_exception: false)
44
+ if permute
45
+ args = []
46
+ until op = getopt(argv, opts, longopts,
47
+ permute: false,
48
+ abbreviation: abbreviation,
49
+ allow_empty_optarg: allow_empty_optarg,
50
+ error_message: error_message,
51
+ optional_short: optional_short,
52
+ program_name: program_name,
53
+ stop_by_double_hyphen: stop_by_double_hyphen,
54
+ use_exception: use_exception)
55
+ if argv.empty?
56
+ argv.unshift(*args)
57
+ return nil
58
+ end
59
+ args.push argv.shift
60
+ end
61
+ argv.unshift(*args)
62
+ return op
63
+ end
64
+
65
+ opts ||= ""
66
+ program_name ||= $0
67
+
68
+ arg = argv.shift
69
+ return nil if arg.nil?
70
+ if arg == :getopt_short
71
+ arg = argv.shift
72
+ return nil if arg.nil?
73
+ else
74
+ if arg == "-"
75
+ argv.unshift "-"
76
+ return nil
77
+ end
78
+ if stop_by_double_hyphen && arg == "--"
79
+ return nil
80
+ end
81
+ # long option
82
+ if longopts && arg.index("--") == 0
83
+ optopt, optarg = arg[2..-1].split "=", 2
84
+
85
+ if abbreviation
86
+ abbr = longopts.collect { |o| o if o[0] =~ /^#{optopt}/ }.compact
87
+ if abbr.empty?
88
+ raise Getopt::UnknownOptionError.new optopt
89
+ end
90
+ if abbr.size == 1
91
+ optopt = abbr.first.first
92
+ elsif exact = abbr.find { |a| a[0] == optopt }
93
+ optopt = exact.first
94
+ else
95
+ cands = abbr.collect { |o| o.first }
96
+ raise Getopt::AmbiguousOptionError.new optopt, nil, cands
97
+ end
98
+ else
99
+ unless longopts[optopt]
100
+ raise Getopt::UnknownOptionError.new optopt
101
+ end
102
+ end
103
+
104
+ case longopts[optopt]
105
+ when :no_argument
106
+ if optarg
107
+ raise Getopt::ArgumentGivenError.new optopt
108
+ end
109
+ return [ optopt ]
110
+ when :required_argument
111
+ unless optarg
112
+ optarg = argv.shift
113
+ unless optarg
114
+ raise Getopt::ArgumentRequiredError.new optopt
115
+ end
116
+ end
117
+ if ! allow_empty_optarg && optarg.empty?
118
+ raise Getopt::ArgumentRequiredError.new optopt
119
+ end
120
+ return [ optopt, optarg ]
121
+ when :optional_argument
122
+ if ! allow_empty_optarg && optarg && optarg.empty?
123
+ raise Getopt::ArgumentRequiredError.new optopt
124
+ end
125
+ return [ optopt, optarg ]
126
+ else
127
+ raise ArgumentError,
128
+ "wrong long option type - #{longopts[optopt].inspect}"
129
+ end
130
+ # NOTREACHED
131
+ end
132
+ end
133
+
134
+ # non option argument
135
+ unless arg[0] == "-"
136
+ argv.unshift arg
137
+ return nil
138
+ end
139
+
140
+ # short option. here arg[0] == "-"
141
+
142
+ optopt = arg[1]
143
+ arg = arg[2 .. -1]
144
+ pos = opts.split("").find_index(optopt)
145
+ if pos.nil? || (optopt == ":" && pos != 0)
146
+ argv.unshift "-#{arg}" unless arg.empty?
147
+ # keep short option context on error
148
+ argv.unshift :getopt_short if arg[0] == "-"
149
+ raise Getopt::UnknownOptionError.new optopt
150
+ end
151
+
152
+ if opts[pos.succ] == ":"
153
+ if optional_short && opts[pos.succ.succ] == ":"
154
+ # short option with optional argument
155
+ optarg = arg.empty? ? nil : arg
156
+ return [ optopt, optarg ]
157
+ else
158
+ # short option with required argument
159
+ optarg = arg.empty? ? argv.shift : arg
160
+ if optarg.nil? || (optarg.empty? && ! allow_empty_optarg)
161
+ raise Getopt::ArgumentRequiredError.new optopt
162
+ end
163
+ return [ optopt, optarg ]
164
+ end
165
+ else
166
+ # short option without argument
167
+ unless arg.empty?
168
+ argv.unshift "-#{arg}"
169
+ argv.unshift :getopt_short if arg[0] == "-"
170
+ end
171
+ return [ optopt ]
172
+ end
173
+
174
+ rescue Getopt::GetoptError => ex
175
+ raise if use_exception
176
+ warn "#{program_name}: #{ex.message} - #{ex.option}" if error_message
177
+ case ex
178
+ when Getopt::UnknownOptionError
179
+ return [ :unknown_option, ex.option ]
180
+ when Getopt::ArgumentRequiredError
181
+ return [ :argument_required, ex.option ]
182
+ when Getopt::ArgumentGivenError
183
+ return [ :argument_given, ex.option ]
184
+ when Getopt::AmbiguousOptionError
185
+ return [ :ambiguous_option, ex.option, ex.candidates ]
186
+ end
187
+ end
188
+
189
+ Kernel.define_singleton_method "getopt", method(:getopt)
190
+
191
+ if __FILE__ == $0
192
+
193
+ def usage
194
+ puts <<EOD
195
+ usage: #{$0} [-hVp] [-Llongopt] opts ...
196
+ -h print this
197
+ -V print revision
198
+ -L define long option like -Lfoo, -Lfoo: or -Lfoo::
199
+ -p permute
200
+ opts define short options
201
+ EOD
202
+ end
203
+
204
+ longopts = {}
205
+ permute = false
206
+
207
+ while op = getopt(ARGV, "hL:pV")
208
+ op, oparg = op
209
+ exit 1 if op.is_a? Symbol
210
+ case op
211
+ when "h"
212
+ usage
213
+ exit
214
+ when "V"
215
+ puts "trad-getopt rev.#{Getopt::VERSION}"
216
+ exit
217
+ when "p"
218
+ permute = true
219
+ when "L"
220
+ if oparg[-1] == ":"
221
+ if oparg[-2] == ":"
222
+ v = :optional_argument
223
+ oparg[-2] = ""
224
+ else
225
+ v = :required_argument
226
+ end
227
+ oparg[-1] = ""
228
+ else
229
+ v = :no_argument
230
+ end
231
+ longopts[oparg] = v
232
+ else
233
+ break
234
+ end
235
+ end
236
+
237
+ opts = ARGV.shift
238
+ unless opts
239
+ puts "argument required"
240
+ exit 1
241
+ end
242
+
243
+ while op = getopt(ARGV, opts, longopts, permute:permute)
244
+ puts "option #{op} ARGV #{ARGV}"
245
+ end
246
+ puts "ARGV #{ARGV}"
247
+
248
+ end
data/trad-getopt.txt ADDED
@@ -0,0 +1,190 @@
1
+ ruby-trad-getopt
2
+
3
+ 伝統的な getopt に近い getopt。コマンドラインオプションを解析する。
4
+
5
+ ---------------------------------------------
6
+ getopt(argv, opts, longopts = nil, KWARGS...)
7
+ ---------------------------------------------
8
+
9
+ argv にはコマンドライン引数文字列のリストをとる。opts にはショートオプ
10
+ ションとする文字を並べた文字列、longopts にはロングオプションを定義す
11
+ るハッシュをとる。
12
+
13
+ argv の先頭の要素が opts または longopts に定義されたコマンドラインオ
14
+ プションであるなら、オプションの種類に応じて次のような、オプション文字
15
+ (列)を第 1 要素とするリストを返す。
16
+
17
+ ・引数なしオプションなら [ "オプション文字" ]
18
+ ・引数つきオプションなら [ "オプション文字", "引数" ]
19
+ ・オプショナル引数つきオプションの場合、引数が、
20
+ ・あるなら [ "オプション文字", "引数" ]
21
+ ・無いなら [ "オプション文字", nil ]
22
+
23
+ argv の先頭の要素がコマンドラインオプションでない場合、または argv が
24
+ 空の場合には nil を返す。
25
+
26
+ コマンドラインオプションとして処理した要素は argv から削除する。argv
27
+ は破壊的に変更されるので、解析をリセットする必要がある場合、あらかじめ
28
+ 呼び出し側で複製した argv を用いる必要がある。
29
+
30
+ 単独の `--' はオプション解析の停止を意味する特別なオプションとして扱い、
31
+ argv からは削除して nil を返す。単独の `-' は非オプションとして扱い、
32
+ argv から削除せず nil を返す。
33
+
34
+ エラーした場合、第 1 要素にエラーの種類を表すシンボル、第 2 要素にエラー
35
+ したオプション文字(列)を置いたリストを返す。
36
+
37
+ = ショートオプション
38
+
39
+ opts には "ab:c" のような、ショートオプションとする文字を並べた文字列
40
+ をとる。
41
+
42
+ ・通常の文字は引数なしショートオプションとなる
43
+ ・後ろに `:' を置いた文字は引数つきショートオプションとなる
44
+ ・後ろに `::' を置いた文字はオプショナル引数つきショートオプションと
45
+ なる
46
+
47
+ 引数つきショートオプションのオプションと引数は、argv 上の続く 2 要素で
48
+ あっても ([ "-a", "foo" ])、1 つの要素であっても ([ "-afoo" ]) よい。
49
+ オプショナル引数つきショートオプションはオプションと引数が 1 つの要素
50
+ で指定されたときのみ引数ありと解釈する。
51
+
52
+ argv 上で [ "-a", "-b", "-c", "foo" ] のように連続しているショートオプ
53
+ ションが [ "-abcfoo" ] のように連結されていてもよい。このとき
54
+ getotpt() はこの要素を、呼び出し毎に "-bcfoo"、"-cfoo"、削除、と変更す
55
+ る。
56
+
57
+ = ロングオプション
58
+
59
+ longopts にはキーをオプション名、値をシンボルとするハッシュをとる。有
60
+ 効なシンボルは次の通り。
61
+
62
+ ・:no_argument - 引数なしロングオプション
63
+ ・:required_argument - 引数つきロングオプション
64
+ ・:optional_argument - オプショナル引数つきロングオプション
65
+
66
+ ロングオプションに引数を与えるには "--bar=引数" のようにオプションと引
67
+ 数を空白なしに `=' でつなげた形をとる。引数つきロングオプションは argv
68
+ 上で連続する 2 要素に分かれていてもよい ([ "--bar", "引数" ])。オプショ
69
+ ナル引数つきロングオプションは `=' 区切りの 1 要素による指定の場合のみ
70
+ 引数をとる。
71
+
72
+ ロングオプションは一意に特定できる限りにおいて省略できる。ただし省略形
73
+ に完全一致するロングオプションを優先する。
74
+
75
+ = エラー
76
+
77
+ エラーすると標準エラー出力にメッセージを出力し、エラーを示すシンボルと
78
+ エラーを生じたオプション文字(列)からなるリストを返す。エラーしたオプショ
79
+ ンは argv から削除する。
80
+
81
+ キーワード引数 use_exception を真にするとエラー時に例外を発生するよう
82
+ になる。例外は Getopt::GetoptError をベースクラスとしており、インスタ
83
+ ンスメソッド option() からエラーしたオプションを得られる。
84
+
85
+ エラーを示すシンボルと対応する例外クラスは以下の通り:
86
+
87
+ - :unknown_option (Getopt::UnknownOptionError)
88
+ 未定義のオプション
89
+
90
+ - :argument_required (Getopt::ArgumentRequiredError)
91
+ 引数つきオプションに引数が無い
92
+
93
+ - :argument_given (Getopt::ArgumentGivenError)
94
+ 引数なしロングオプションに引数が指定された
95
+
96
+ - :ambiguousu_option (Getopt::AmbiguousOptionError)
97
+ ロングオプションの省略形が一意でない。このときエラーメッセージに候補
98
+ を示す。また返り値の第 3 要素にも候補のリストを置く。例外を有効とし
99
+ ている場合は Getopt::AmbiguousOptionError#candidates() で取得できる。
100
+
101
+ = キーワード引数
102
+
103
+ - abbreviation => true
104
+ 偽にするとロングオプションの省略形が無効になる。
105
+
106
+ - allow_empty_optarg => true
107
+ 偽にすると、引数つきオプションまたはオプショナル引数つきオプションで、
108
+ オプションの引数が空文字列だったときにエラー (:argument_required) と
109
+ する。
110
+
111
+ - error_message => true
112
+ 偽にするとエラーメッセージを出力しなくなる。
113
+
114
+ - optional_short => true
115
+ 偽にするとオプショナル引数つきショートオプションを無効にする。opts
116
+ 中の "::" を ":" と解釈してただの引数つきオプションとする。
117
+
118
+ - permute => false
119
+ 真にすると、オプションに出会うまで非オプションを飛ばす GNU の getopt
120
+ を模した動作になる。argv 中にオプションが無ければ nil を返す。読んだ
121
+ オプションを削除することは変わらないので、nil が返るまで getopt() を
122
+ 繰り返すと argv には非オプションの引数のみが残ることになる。
123
+
124
+ - program_name => nil
125
+ エラーメッセージに出すプログラム名文字列を指定する。デフォルトは nil
126
+ で $0 を使う。
127
+
128
+ - stop_by_double_hyphen => true
129
+ 偽にすると `--' を特別扱いしなくなり、`-' を普通のショートオプション
130
+ 文字として使えるようになる。
131
+
132
+ - use_exception => false
133
+ 真ならエラー時に例外を発生するようになる。
134
+
135
+ = 要注意なオプション文字
136
+
137
+ - `-'
138
+ ショートオプション文字としても解析停止の `--' を優先する都合上、単独
139
+ の表記では通常のショートオプションとして得られないが、`-a-' のように
140
+ ショートオプションの連結中に表れたときには通常のショートオプションと
141
+ して得られる。
142
+ キーワード引数 stop_by_double_hyphen を偽とすることで、`-' を単なる
143
+ ショートオプション文字としてのみ使えるようになる。
144
+ また本実装では、このコンテキストを捉えるために、連結されたオプション
145
+ の次回の読み出しが `-' になるとき、argv の先頭に :getopt_short とい
146
+ うシンボルを置く。
147
+
148
+ - `:'
149
+ ショートオプション文字として使うには、引数つきオプションを示す `:'
150
+ と区別するため、opts の先頭に置かなければならない。C 言語等の
151
+ getopt() にオプション文字列先頭の `:' が特別な機能を持つものがあるが、
152
+ それとは意味が違う点に注意。
153
+
154
+ - `>' や `|' などのシェルのメタ文字
155
+ コマンドライン上では `-\>' や `--foo\|bar' のようにエスケープして表
156
+ 記する必要が生じる。具体的には使用しているシェルに依存する。
157
+
158
+ = 例
159
+
160
+ ----------------------------------------------------------------------------
161
+ require "trad-getopt"
162
+
163
+ opts = "ab:"
164
+
165
+ longopts = {
166
+ "foo" => :no_argument,
167
+ "foo-bar" => :optional_argument,
168
+ "baz" => :required_argument,
169
+ }
170
+
171
+ while op = getopt(ARGV, opts, longopts, permute:false)
172
+ case op[0]
173
+ when "a", "foo"
174
+ puts "option #{op[0]}"
175
+ when "b", "baz"
176
+ puts "option #{op[0]} with #{op[1]}"
177
+ when "foo-bar"
178
+ if op[1]
179
+ puts "option #{op[0]} with #{op[1]}"
180
+ else
181
+ puts "option #{op[0]} with no-arg"
182
+ end
183
+ when :unknown_option, :argument_required, :argument_given, :ambiguous_option
184
+ exit 1
185
+ end
186
+ end
187
+ puts "argv #{ARGV}"
188
+ ----------------------------------------------------------------------------
189
+
190
+ #eof
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trad-getopt
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - NOZAWA Hiromasa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - LICENSE
20
+ - Rakefile
21
+ - test.rb
22
+ - trad-getopt.rb
23
+ - trad-getopt.txt
24
+ homepage: https://github.com/noz/ruby-trad-getopt
25
+ licenses:
26
+ - BSD-2-Clause
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - "."
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 2.6.8
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: rather traditional getopt()
48
+ test_files: []