benry-cmdopt 2.2.0 → 2.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9308d0182f3f4a17d45f3b7a1f212a4f5f2112f4084d725b2de05271a908bb1d
4
- data.tar.gz: f9b8e9066b9857d2693382f03bcbeacdd040695287d426d8ef8c28cf242f1cd1
3
+ metadata.gz: cb625857a40a61b165810acf4ee25cb3c9db54ac6e2c9e14678206a1036817a5
4
+ data.tar.gz: a47a9b936e4d63ea088945498d9469af67855af74c39680ae909ef36a6292945
5
5
  SHA512:
6
- metadata.gz: e231075a8a9fdd99a0379390ebc1fae07c812f8229d1689e0b7f04b91d5c0c596122835dde000c3ba609681898c3048fa51d08232cd33d4b9df0bacbc22036c6
7
- data.tar.gz: bcabe45f475efd7c95e989c9f7f2c9b61c65396b6373cbb0a68427ce10798a942c4af3cfd8ae66a34928c710b2cac24388d8848a6a1271ca40d3e9458a217898
6
+ metadata.gz: 4a35732c27d59d58ab02e23e22b7b52750975a728988b3f78c0d26bdcf52cfaffb7caa8d1feb2e1928a3455220e44dca0673720072dc31f164a87c08b6ed637c
7
+ data.tar.gz: 8ad1c06cb5b9e5adeb84fc01c4c236162a894c3fbea1f9470dbc87d67bb315c8669f8c84036cc1e594ac22f7047d5bb10fa790e298b24624d26858cc2ff3e127
data/CHANGES.md CHANGED
@@ -2,10 +2,22 @@ CHANGES
2
2
  =======
3
3
 
4
4
 
5
+ Release 2.4.0 (2023-12-04)
6
+ --------------------------
7
+
8
+ * [enhance] `Schema.add()` supports `multiple: true` keyword arg which enables to specify option multiple times.
9
+
10
+
11
+ Release 2.3.0 (2023-11-26)
12
+ --------------------------
13
+
14
+ * [change] `Schema#add()` raises SchemaError if option key, short or long option duplicated.
15
+
16
+
5
17
  Release 2.2.0 (2023-10-28)
6
18
  --------------------------
7
19
 
8
- * [enhance] Define `SchemaItem#add_item()` which adds option item into the schema. This is for Benry-CmdApp framework.
20
+ * [enhance] Define `Schema#add_item()` which adds option item into the schema. This is for Benry-CmdApp framework.
9
21
  * [change] (EXPERIMENTAL) Make `desc`, `detail`, `hidden`, `important`, `tag` attrubtes of `SchemaItem` object to be writable. This is for Benry-CmdApp framework.
10
22
 
11
23
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Benry-CmdOpt
2
2
 
3
- ($Release: 2.2.0 $)
3
+ ($Release: 2.4.0 $)
4
4
 
5
5
 
6
6
 
@@ -41,6 +41,9 @@ Benry-CmdOpt requires Ruby >= 2.3.
41
41
  * [Important Options](#important-options)
42
42
  * [Not Supported](#not-supported)
43
43
  * [Internal Classes](#internal-classes)
44
+ * [FAQ](#faq)
45
+ * [Q: How to change or customize error messages?](#q-how-to-change-or-customize-error-messages)
46
+ * [Q: Is it possible to support `-vvv` style option?](#q-is-it-possible-to-support--vvv-style-option)
44
47
  * [License and Copyright](#license-and-copyright)
45
48
 
46
49
  <!-- /TOC -->
@@ -139,6 +142,23 @@ cmdopt = Benry::CmdOpt.new
139
142
  cmdopt.add(:number, "-n <N>", "number", type: Integer, enum: [1, 2, 3]) # very intuitive
140
143
  ```
141
144
 
145
+ * `optparse.rb` doesn't report error even when options are duplicated.
146
+ This specification makes debugging hard.
147
+
148
+ `benry/cmdopt.rb` reports error when options are duplicated.
149
+
150
+ ```ruby
151
+ require 'optparse'
152
+
153
+ options = {}
154
+ parser = OptionParser.new
155
+ parser.on('-v', '--version') { options[:version] = true }
156
+ parser.on('-v', '--verbose') { options[:verbose] = true } # !!!!
157
+ argv = ["-v"]
158
+ parser.parse!(argv)
159
+ p options #=> {:verbose=>true}, not {:version=>true}
160
+ ```
161
+
142
162
  * `optparse.rb` adds `-h` and `--help` options automatically, and
143
163
  terminates current process when `-h` or `--help` specified in command-line.
144
164
  It is hard to remove these options.
@@ -260,13 +280,13 @@ end
260
280
 
261
281
  In fact, file `optparse.rb` and `optparse/*.rb` (in Ruby 3.2)
262
282
  contains total 1298 lines (except comments and blanks), while
263
- `benry/cmdopt.rb` (v2.0.0) contains only 429 lines (except both, too).
283
+ `benry/cmdopt.rb` (v2.4.0) contains only 479 lines (except both, too).
264
284
 
265
285
 
266
286
 
267
287
  ## Install
268
288
 
269
- ```
289
+ ```console
270
290
  $ gem install benry-cmdopt
271
291
  ```
272
292
 
@@ -450,11 +470,24 @@ p options[:flag2] #=> false (!!!!!)
450
470
 
451
471
  ### Multiple Value Option
452
472
 
473
+ Release 2.4 or later supports `multiple: true` keyword arg.
474
+
475
+ ```ruby
476
+ require 'benry/cmdopt'
477
+ cmdopt = Benry::CmdOpt.new
478
+
479
+ cmdopt.add(:inc , '-I <path>', "include path", multiple: true) # !!!!
480
+ options = cmdopt.parse(["-I", "/foo", "-I", "/bar", "-I/baz"])
481
+ p options #=> {:inc=>["/foo", "/bar", "/baz"]}
482
+ ```
483
+
484
+ On older version:
485
+
453
486
  ```ruby
454
487
  require 'benry/cmdopt'
455
488
  cmdopt = Benry::CmdOpt.new
456
489
 
457
- cmdopt.add(:lib , '-I <NAME>', "library name") {|options, key, val|
490
+ cmdopt.add(:inc , '-I <path>', "include path") {|options, key, val|
458
491
  arr = options[key] || []
459
492
  arr << val
460
493
  arr
@@ -462,8 +495,8 @@ cmdopt.add(:lib , '-I <NAME>', "library name") {|options, key, val|
462
495
  #(options[key] || []) << val
463
496
  }
464
497
 
465
- options = cmdopt.parse(["-I", "foo", "-I", "bar", "-Ibaz"])
466
- p options #=> {:lib=>["foo", "bar", "baz"]}
498
+ options = cmdopt.parse(["-I", "/foo", "-I", "/bar", "-I/baz"])
499
+ p options #=> {:inc=>["/foo", "/bar", "/baz"]}
467
500
  ```
468
501
 
469
502
 
@@ -687,6 +720,34 @@ Use `cmdopt.is_a?(Benry::CmdOpt::Facade)` instead if necessary.
687
720
 
688
721
 
689
722
 
723
+ ## FAQ
724
+
725
+
726
+ ### Q: How to change or customize error messages?
727
+
728
+ A: Currently not supported. Maybe supported in the future.
729
+
730
+
731
+ ### Q: Is it possible to support `-vvv` style option?
732
+
733
+ A: Yes.
734
+
735
+ ```ruby
736
+ require 'benry/cmdopt'
737
+ cmdopt = Benry::CmdOpt.new
738
+
739
+ cmdopt.add(:verbose , '-v', "verbose level") {|opts, key, val|
740
+ opts[key] ||= 0
741
+ opts[key] += 1
742
+ }
743
+
744
+ p cmdopt.parse(["-v"]) #=> {:verbose=>1}
745
+ p cmdopt.parse(["-vv"]) #=> {:verbose=>2}
746
+ p cmdopt.parse(["-vvv"]) #=> {:verbose=>3}
747
+ ```
748
+
749
+
750
+
690
751
  ## License and Copyright
691
752
 
692
753
  $License: MIT License $
data/benry-cmdopt.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "benry-cmdopt"
5
- spec.version = "$Release: 2.2.0 $".split()[1]
5
+ spec.version = "$Release: 2.4.0 $".split()[1]
6
6
  spec.author = "kwatch"
7
7
  spec.email = "kwatch@gmail.com"
8
8
  spec.platform = Gem::Platform::RUBY
@@ -21,7 +21,7 @@
21
21
  <ul class="nav">
22
22
  </ul>
23
23
  </nav>
24
- <p>($Release: 2.2.0 $)</p>
24
+ <p>($Release: 2.4.0 $)</p>
25
25
  <section class="section" id="whats-this">
26
26
  <h2>What's This?</h2>
27
27
  <p>Benry-CmdOpt is a command option parser library, like <code>optparse.rb</code>
@@ -57,6 +57,11 @@ and easy to understahnd.</p>
57
57
  <li><a href="#not-supported">Not Supported</a></li>
58
58
  </ul></li>
59
59
  <li><a href="#internal-classes">Internal Classes</a></li>
60
+ <li><a href="#faq">FAQ</a>
61
+ <ul>
62
+ <li><a href="#q-how-to-change-or-customize-error-messages">Q: How to change or customize error messages?</a></li>
63
+ <li><a href="#q-is-it-possible-to-support--vvv-style-option">Q: Is it possible to support <code>-vvv</code> style option?</a></li>
64
+ </ul></li>
60
65
  <li><a href="#license-and-copyright">License and Copyright</a></li>
61
66
  </ul>
62
67
  </div>
@@ -155,6 +160,23 @@ cmdopt = Benry::CmdOpt.new
155
160
  cmdopt.add(:number, "-n &ltN&gt;", "number", type: Integer, <strong>enum: [1, 2, 3]</strong>) # very intuitive
156
161
  </pre>
157
162
  <ul>
163
+ <li><code>optparse.rb</code> doesn't report error even when options are duplicated.
164
+ This specification makes debugging hard.
165
+ <p></p>
166
+ <code>benry/cmdopt.rb</code> reports error when options are duplicated.</li>
167
+ </ul>
168
+ <pre class="language-ruby">
169
+ require 'optparse'
170
+
171
+ options = {}
172
+ parser = OptionParser.new
173
+ parser.on(<strong>'-v'</strong>, '--version') { options[:version] = true }
174
+ parser.on(<strong>'-v'</strong>, '--verbose') { options[:verbose] = true } # !!!!
175
+ argv = ["-v"]
176
+ parser.parse!(argv)
177
+ p options #=&gt; {:verbose=&gt;true}, not {:version=&gt;true}
178
+ </pre>
179
+ <ul>
158
180
  <li><code>optparse.rb</code> adds <code>-h</code> and <code>--help</code> options automatically, and
159
181
  terminates current process when <code>-h</code> or <code>--help</code> specified in command-line.
160
182
  It is hard to remove these options.
@@ -276,12 +298,12 @@ end
276
298
  <p></p>
277
299
  In fact, file <code>optparse.rb</code> and <code>optparse/*.rb</code> (in Ruby 3.2)
278
300
  contains total 1298 lines (except comments and blanks), while
279
- <code>benry/cmdopt.rb</code> (v2.0.0) contains only 429 lines (except both, too).</li>
301
+ <code>benry/cmdopt.rb</code> (v2.4.0) contains only 479 lines (except both, too).</li>
280
302
  </ul>
281
303
  </section>
282
304
  <section class="section" id="install">
283
305
  <h2>Install</h2>
284
- <pre>
306
+ <pre class="language-console">
285
307
  $ gem install benry-cmdopt
286
308
  </pre>
287
309
  </section>
@@ -443,11 +465,21 @@ p options[:flag2] #=&gt; <strong>false</strong> (!!!!!)
443
465
  </section>
444
466
  <section class="subsection" id="multiple-value-option">
445
467
  <h3>Multiple Value Option</h3>
468
+ <p>Release 2.4 or later supports <code>multiple: true</code> keyword arg.</p>
469
+ <pre class="language-ruby">
470
+ require 'benry/cmdopt'
471
+ cmdopt = Benry::CmdOpt.new
472
+
473
+ cmdopt.add(:inc , '-I &ltpath&gt;', "include path", <strong>multiple: true</strong>) # !!!!
474
+ options = cmdopt.parse(["-I", "/foo", "-I", "/bar", "-I/baz"])
475
+ p options #=&gt; <strong>{:inc=&gt;["/foo", "/bar", "/baz"]}</strong>
476
+ </pre>
477
+ <p>On older version:</p>
446
478
  <pre class="language-ruby">
447
479
  require 'benry/cmdopt'
448
480
  cmdopt = Benry::CmdOpt.new
449
481
 
450
- cmdopt.add(:lib , '-I &ltNAME&gt;', "library name") <strong>{|options, key, val|</strong>
482
+ cmdopt.add(:inc , '-I &ltpath&gt;', "include path") <strong>{|options, key, val|</strong>
451
483
  <strong>arr = options[key] || []</strong>
452
484
  <strong>arr &lt&lt val</strong>
453
485
  <strong>arr</strong>
@@ -455,8 +487,8 @@ cmdopt.add(:lib , '-I &ltNAME&gt;', "library name") <strong>{|options, key, val|
455
487
  #(options[key] || []) &lt&lt val
456
488
  <strong>}</strong>
457
489
 
458
- options = cmdopt.parse(["-I", "foo", "-I", "bar", "-Ibaz"])
459
- p options #=&gt; <strong>{:lib=&gt;["foo", "bar", "baz"]}</strong>
490
+ options = cmdopt.parse(["-I", "/foo", "-I", "/bar", "-I/baz"])
491
+ p options #=&gt; <strong>{:inc=&gt;["/foo", "/bar", "/baz"]}</strong>
460
492
  </pre>
461
493
  </section>
462
494
  <section class="subsection" id="hidden-option">
@@ -661,6 +693,30 @@ opts = <strong>cmdopt.parse</strong>(ARGV) # same as <strong>pars
661
693
  <p>Notice that <code>cmdopt.is_a?(Benry::CmdOpt)</code> results in false.
662
694
  Use <code>cmdopt.is_a?(Benry::CmdOpt::Facade)</code> instead if necessary.</p>
663
695
  </section>
696
+ <section class="section" id="faq">
697
+ <h2>FAQ</h2>
698
+ <section class="subsection" id="q-how-to-change-or-customize-error-messages">
699
+ <h3>Q: How to change or customize error messages?</h3>
700
+ <p>A: Currently not supported. Maybe supported in the future.</p>
701
+ </section>
702
+ <section class="subsection" id="q-is-it-possible-to-support--vvv-style-option">
703
+ <h3>Q: Is it possible to support <code>-vvv</code> style option?</h3>
704
+ <p>A: Yes.</p>
705
+ <pre class="language-ruby">
706
+ require 'benry/cmdopt'
707
+ cmdopt = Benry::CmdOpt.new
708
+
709
+ cmdopt.add(:verbose , '-v', "verbose level") {|opts, key, val|
710
+ opts[key] ||= 0
711
+ opts[key] += 1
712
+ }
713
+
714
+ p cmdopt.parse(["-v"]) #=&gt; {:verbose=&gt;1}
715
+ p cmdopt.parse(["-vv"]) #=&gt; {:verbose=&gt;2}
716
+ p cmdopt.parse(["-vvv"]) #=&gt; {:verbose=&gt;3}
717
+ </pre>
718
+ </section>
719
+ </section>
664
720
  <section class="section" id="license-and-copyright">
665
721
  <h2>License and Copyright</h2>
666
722
  <p>$License: MIT License $</p>
data/doc/css/style.css CHANGED
@@ -74,12 +74,12 @@ pre > strong {
74
74
  font-weight: bold;
75
75
  color: #900;
76
76
  }
77
- pre.language-terminal {
77
+ pre.language-terminal, pre.language-console {
78
78
  background: #333;
79
79
  color: #fff;
80
80
  border-color: #000;
81
81
  }
82
- pre.language-terminal > strong {
82
+ pre.language-terminal > strong, pre.language-console > strong {
83
83
  color: #f66;
84
84
  }
85
85
  code {
data/lib/benry/cmdopt.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  ###
5
- ### $Release: 2.2.0 $
5
+ ### $Release: 2.4.0 $
6
6
  ### $Copyright: copyright(c) 2021 kwatch@gmail.com $
7
7
  ### $License: MIT License $
8
8
  ###
@@ -23,7 +23,7 @@ end
23
23
  module Benry::CmdOpt
24
24
 
25
25
 
26
- VERSION = '$Release: 2.2.0 $'.split()[1]
26
+ VERSION = '$Release: 2.4.0 $'.split()[1]
27
27
 
28
28
 
29
29
  def self.new()
@@ -40,11 +40,12 @@ module Benry::CmdOpt
40
40
 
41
41
  attr_reader :schema
42
42
 
43
- def add(key, optdef, desc, *rest, type: nil, rexp: nil, pattern: nil, enum: nil, range: nil, value: nil, detail: nil, hidden: nil, important: nil, tag: nil, &callback)
43
+ def add(key, optdef, desc, *rest, type: nil, rexp: nil, pattern: nil, enum: nil, range: nil, value: nil, multiple: nil, detail: nil, hidden: nil, important: nil, tag: nil, &callback)
44
44
  rexp ||= pattern # for backward compatibility
45
45
  #; [!vmb3r] defines command option.
46
46
  #; [!71cvg] type, rexp, enum, and range are can be passed as positional args as well as keyword args.
47
- @schema.add(key, optdef, desc, *rest, type: type, rexp: rexp, enum: enum, range: range, value: value, detail: detail, hidden: hidden, important: important, tag: tag, &callback)
47
+ @schema.add(key, optdef, desc, *rest,
48
+ type: type, rexp: rexp, enum: enum, range: range, value: value, multiple: multiple, detail: detail, hidden: hidden, important: important, tag: tag, &callback)
48
49
  #; [!tu4k3] returns self.
49
50
  self
50
51
  end
@@ -103,7 +104,7 @@ module Benry::CmdOpt
103
104
  self
104
105
  end
105
106
 
106
- def add(key, optdef, desc, *rest, type: nil, rexp: nil, pattern: nil, enum: nil, range: nil, value: nil, detail: nil, hidden: nil, important: nil, tag: nil, &callback)
107
+ def add(key, optdef, desc, *rest, type: nil, rexp: nil, pattern: nil, enum: nil, range: nil, value: nil, multiple: nil, detail: nil, hidden: nil, important: nil, tag: nil, &callback)
107
108
  rexp ||= pattern # for backward compatibility
108
109
  #; [!kuhf9] type, rexp, enum, and range are can be passed as positional args as well as keyword args.
109
110
  rest.each do |x|
@@ -137,17 +138,38 @@ module Benry::CmdOpt
137
138
  end
138
139
  #; [!yht0v] keeps command option definitions.
139
140
  item = SchemaItem.new(key, optdef, desc, short, long, param, required,
140
- type: type, rexp: rexp, enum: enum, range: range, value: value, detail: detail, hidden: hidden, important: important, tag: tag, &callback)
141
- @items << item
141
+ type: type, rexp: rexp, enum: enum, range: range, value: value, multiple: multiple, detail: detail, hidden: hidden, important: important, tag: tag, &callback)
142
+ add_item(item)
142
143
  item
143
144
  end
144
145
 
145
146
  def add_item(item)
147
+ #; [!qyjp9] raises SchemaError if invalid item added.
148
+ errmsg = _validate_item(item)
149
+ errmsg == nil or
150
+ raise SchemaError.new(errmsg)
146
151
  #; [!a693h] adds option item into current schema.
147
152
  @items << item
148
153
  self
149
154
  end
150
155
 
156
+ def _validate_item(item)
157
+ key = item.key; short = item.short; long = item.long
158
+ for x in @items
159
+ #; [!ewl20] returns error message if option key duplicated.
160
+ key != x.key or
161
+ return "#{key}: Option key duplicated."
162
+ #; [!xg56v] returns error message if short option duplicated.
163
+ short == nil || short != x.short or
164
+ return "-#{short}: Short option duplicated (key: #{key} and #{x.key})."
165
+ #; [!izezi] returns error message if long option duplicated.
166
+ long == nil || long != x.long or
167
+ return "--#{long}: Long option duplicated (key: #{key} and #{x.key})."
168
+ end
169
+ return nil
170
+ end
171
+ private :_validate_item
172
+
151
173
  def option_help(width_or_format=nil, all: false)
152
174
  #; [!0aq0i] can take integer as width.
153
175
  #; [!pcsah] can take format string.
@@ -301,7 +323,7 @@ module Benry::CmdOpt
301
323
 
302
324
  class SchemaItem # avoid Struct
303
325
 
304
- def initialize(key, optdef, desc, short, long, param, required, type: nil, rexp: nil, pattern: nil, enum: nil, range: nil, detail: nil, value: nil, hidden: nil, important: nil, tag: nil, &callback)
326
+ def initialize(key, optdef, desc, short, long, param, required, type: nil, rexp: nil, pattern: nil, enum: nil, range: nil, value: nil, multiple: nil, detail: nil, hidden: nil, important: nil, tag: nil, &callback)
305
327
  rexp ||= pattern # for backward compatibility
306
328
  _init_validation(param, required, type, rexp, enum, range, value)
307
329
  @key = key unless nil == key
@@ -315,8 +337,9 @@ module Benry::CmdOpt
315
337
  @rexp = rexp unless nil == rexp
316
338
  @enum = enum unless nil == enum
317
339
  @range = range unless nil == range
318
- @detail = detail unless nil == detail
319
340
  @value = value unless nil == value
341
+ @multiple = multiple unless nil == multiple
342
+ @detail = detail unless nil == detail
320
343
  @hidden = hidden unless nil == hidden
321
344
  @important = important unless nil == important
322
345
  @tag = tag unless nil == tag
@@ -325,7 +348,7 @@ module Benry::CmdOpt
325
348
  @enum.freeze() if @enum
326
349
  end
327
350
 
328
- attr_reader :key, :optdef, :desc, :short, :long, :param, :type, :rexp, :enum, :range, :detail, :value, :tag, :callback
351
+ attr_reader :key, :optdef, :desc, :short, :long, :param, :type, :rexp, :enum, :range, :value, :detail, :tag, :callback
329
352
  attr_writer :desc, :detail, :hidden, :important, :tag # !!experimental!!
330
353
  alias pattern rexp # for backward compatibility
331
354
  alias help desc # for backward compatibility
@@ -346,6 +369,12 @@ module Benry::CmdOpt
346
369
  return :optional
347
370
  end
348
371
 
372
+ def multiple?()
373
+ #; [!1lj8v] returns true if @multiple is truthy.
374
+ #; [!cun23] returns false if @multiple is falthy.
375
+ return !! @multiple
376
+ end
377
+
349
378
  def hidden?()
350
379
  #; [!no6ov] returns true if @hidden is true.
351
380
  #; [!ej8ot] returns false if @hidden is false.
@@ -608,7 +637,8 @@ module Benry::CmdOpt
608
637
  rescue RuntimeError => ex
609
638
  raise _error("#{optstr}: #{ex.message}")
610
639
  end
611
- optdict[item.key] = val
640
+ #; [!1m87b] supports multiple option.
641
+ store_option_value(optdict, item, val)
612
642
  end
613
643
 
614
644
  def parse_short_options(optstr, optdict, &block)
@@ -648,7 +678,8 @@ module Benry::CmdOpt
648
678
  raise _error("-#{char}#{sp}#{val}: #{ex.message}")
649
679
  end
650
680
  end
651
- optdict[item.key] = val
681
+ #; [!187r2] supports multiple option.
682
+ store_option_value(optdict, item, val)
652
683
  end
653
684
  end
654
685
 
@@ -657,6 +688,16 @@ module Benry::CmdOpt
657
688
  return OPTIONS_CLASS.new
658
689
  end
659
690
 
691
+ def store_option_value(optdict, item, val)
692
+ #; [!my86j] stores multiple values if multiple option item.
693
+ if item.multiple?
694
+ (optdict[item.key] ||= []) << val
695
+ #; [!tm7xw] stores singile value if not multiple option item.
696
+ else
697
+ optdict[item.key] = val
698
+ end
699
+ end
700
+
660
701
  def handle_unknown_long_option(optstr, name, val)
661
702
  #; [!0q78a] raises OptionError.
662
703
  raise _error("#{optstr}: Unknown long option.")