trad-getopt 1.1.0

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