getopt-declare 1.25 → 1.26

Sign up to get free protection for your applications and to get access to all the features.
data/Declare.rdoc CHANGED
@@ -1184,6 +1184,25 @@
1184
1184
  # second Getopt::Declare object).
1185
1185
  #
1186
1186
  #
1187
+ # == Other global directives
1188
+ #
1189
+ # Getopt::Declare offers some other less used global directives to control
1190
+ # how some options are handled.
1191
+ #
1192
+ # The directives are:
1193
+ #
1194
+ # * <tt>[tight]</tt>
1195
+ #
1196
+ # Specifies that the usage (help) description should be printed in a tight
1197
+ # form, eliminating as many empty or whitespace only lines as possible.
1198
+ #
1199
+ # * <tt>[debug]</tt>
1200
+ #
1201
+ # For debugging purposes, it specifies that the internal parser that
1202
+ # Getopt::Declare generates gets saved to a file called .CODE.rb.
1203
+ # This file is placed in the directory where the command was run from.
1204
+ #
1205
+ #
1187
1206
  # == Parameter dependencies
1188
1207
  #
1189
1208
  # Getopt::Declare provides five other directives which modify the
@@ -1200,13 +1219,8 @@
1200
1219
  # condition was violated, the program terminates
1201
1220
  # (whilst still inside Getopt::Declare::new()).
1202
1221
  #
1203
- # The directives are:
1204
- #
1205
- # * <tt>[tight]</tt>
1206
- #
1207
- # Specifies that the usage description should be printed in a tight
1208
- # form, eliminating as many empty or whitespace only lines as possible.
1209
1222
  #
1223
+ # The directives are:
1210
1224
  #
1211
1225
  # * <tt>[required]</tt>
1212
1226
  #
data/HISTORY.txt CHANGED
@@ -1,3 +1,13 @@
1
+ == 1.26
2
+ * Stripping of usage was making help lines that were not
3
+ parameters look bad. Fixed.
4
+ * [ requires: param && flag ] was being expanded incorrectly,
5
+ leading to an obtuse error. Fixed.
6
+ like what user expects.
7
+ * Removed _enbool() routine as it is no longer needed.
8
+ * Documented [debug] directive.
9
+ * Updated usage() tests.
10
+
1
11
  == 1.25
2
12
  * Really just v1.24, but there were problems with hoe releasing.
3
13
  * Made -version not fail when doing rake tests and file is not
data/Rakefile CHANGED
@@ -8,6 +8,10 @@ require './lib/Getopt/Declare'
8
8
  rdoc_files = ["Declare.rdoc", 'HISTORY.txt'] + Dir.glob('lib/*/*.rb')
9
9
 
10
10
 
11
+ #
12
+ # Make sure that ~/.rubyforge/auto-config.yml contains getopt-declare
13
+ # as project (not getoptdeclare).
14
+ #
11
15
  Hoe.new('getopt-declare', Getopt::Declare::VERSION) do |p|
12
16
  p.rubyforge_name = name = 'getoptdeclare'
13
17
  p.author = "Gonzalo Garramuno"
@@ -1,1738 +1,1739 @@
1
- #
2
- # Getopt::Declare - Declaratively Expressed Command-Line Arguments via Regular Expressions
3
- #
4
- # Ruby port of Perl's Getopt::Declare, version 1.21,
5
- # released May 21, 1999.
6
- #
7
- # $Release Version: 1.25 $
8
- # $Date: 2007/01/15 10:53:09 $
9
- # by Gonzalo Garramu�o
10
- #
11
- # For detailed instructions, see Declare.rdoc file
12
- #
13
- # Ruby Port:
14
- # Copyright (c) 2004, Gonzalo Garramuno. All Rights Reserved.
15
- # This package is free software. It may be used, redistributed
16
- # and/or modified under the terms of the Perl Artistic License
17
- # (see http://www.perl.com/perl/misc/Artistic.html)
18
- #
19
- # Original Perl Implementation:
20
- # Damian Conway (damian@conway.org)
21
- # Copyright (c) 1997-2000, Damian Conway. All Rights Reserved.
22
- # This package is free software. It may be used, redistributed
23
- # and/or modified under the terms of the Perl Artistic License
24
- # (see http://www.perl.com/perl/misc/Artistic.html)
25
- #
26
-
27
- require "Getopt/DelimScanner"
28
-
29
-
30
- # Verifies that code is valid Ruby code. returns false if not
31
- def valid_syntax?(code, fname = 'parser_code')
32
- eval("BEGIN {return true}\n#{code}", nil, fname, 0)
33
- rescue Exception
34
- false
35
- end
36
-
37
-
38
- # An add-on to the String class
39
- class String
40
- # Expand all tabs to spaces
41
- def expand_tabs!( tabstop = 8 )
42
- while self.sub!(/(^|\n)([^\t\n]*)(\t+)/sex) { |f|
43
- val = ( tabstop * "#$3".length() - ("#$2".length() % tabstop) )
44
- "#$1#$2" + (" " * val)
45
- }
46
- end
47
- self
48
- end
49
-
50
- # Return new string with all tabs set to spaces
51
- def expand_tabs( tabstop = 8 )
52
- h = self.dup
53
- while h.sub!(/(^|\n)([^\t\n]*)(\t+)/sex) { |f|
54
- val = ( tabstop * "#$3".length() - ("#$2".length() % tabstop) )
55
- "#$1#$2" + (" " * val)
56
- }
57
- end
58
- h
59
- end
60
- end
61
-
62
-
63
- # Regex for removing bracket directives
64
- BracketDirectives =
65
- /\[\s*(?:ditto|tight|strict|no\s*case|repeatable|debug|required|mutex:.*|implies:.*|excludes:.*|requires:.*|cluster:.*)\s*\]/
66
-
67
-
68
- module Getopt
69
-
70
- # Main Class
71
- class Declare
72
-
73
- VERSION = '1.25'
74
-
75
- # For debugging, use [debug] and it will output the ruby code as .CODE.rb
76
- @@debug = false
77
-
78
- # Main separator used to distinguish arguments in Getopt/Declare spec.
79
- # By default, one or more tabs or 3 spaces or more.
80
- @@separator = '(?:\t+| {3})'
81
-
82
- # Class used to handle the beginning of options
83
- class StartOpt
84
-
85
- # Returns regex used matching start of options
86
- def matcher(g)
87
- '(?:()'
88
- end
89
-
90
- # Returns code used
91
- def code(*t)
92
- ''
93
- end
94
-
95
- # Returns how to cache code in class
96
- def cachecode(a,b)
97
- ''
98
- end
99
-
100
- # Helps build regex that matches parameters of flags
101
- def trailer
102
- nil
103
- end
104
-
105
- # Helps build regex that matches parameters of flags
106
- def ows(g)
107
- g
108
- end
109
- end # StartOpt
110
-
111
-
112
- # Class used to handle the ending of options
113
- class EndOpt < StartOpt
114
- # Returns regex used matching end of options
115
- def matcher(g)
116
- '())?'
117
- end
118
- end # EndOpt
119
-
120
-
121
- # Class used to handle scalar (ie.non-array) parameters
122
- class ScalarArg
123
-
124
- @@stdtype = {}
125
-
126
- # (re)set standard types
127
- def ScalarArg._reset_stdtype
128
- @@stdtype = {
129
- ':i' => { 'pattern' => '(?:(?:%T[+-]?)%D+)' },
130
- ':n' => { 'pattern' => '(?:(?:%T[+-]?)(?:%D+(?:%T\.%D*)?' +
131
- '(?:%T[eE](?:[+-])?%D+)?|%T\.%D+(?:%T[eE](?:[+-])?%D+)?))',
132
- },
133
- ':s' => { 'pattern' => '(?:%T(?:\S|\0))+(?=\s|\0|\z)' },
134
- ':qs' => { 'pattern' => %q{"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|(?:%T(?:\S|\0))+} },
135
- ':id' => { 'pattern' => '%T[a-zA-Z_](?:%T\w)*(?=\s|\0|\z)' },
136
- ':d' => { 'pattern' => '(?:%T(?:\S|\0))+',
137
- 'action' => %q%
138
- reject( (_VAL_.nil? || !test(?d, _VAL_) ),
139
- "in parameter '#{_PARAM_}' (\"#{_VAL_}\" is not a directory)")%
140
- },
141
- ':if' => { 'pattern' => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
142
- 'action' => %q%
143
- reject( (_VAL_.nil? || _VAL_ != "-" && !test(?r, _VAL_) ),
144
- "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not readable)")%
145
- },
146
- ':of' => { 'pattern' => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
147
- 'action' => %q%
148
- reject( (_VAL_.nil? || _VAL_ != "-" &&
149
- test(?r, _VAL_) && !test(?w, _VAL_)),
150
- "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not writable)")%
151
- },
152
- '' => { 'pattern' => ':s', 'ind' => 1 },
153
-
154
- ':+i' => { 'pattern' => ':i',
155
- 'action' => %q%reject( _VAL_ <= 0,
156
- "in parameter '#{_PARAM_}' (#{_VAL_} must be an integer greater than zero)")%,
157
- 'ind' => 1
158
- },
159
-
160
- ':+n' => { 'pattern' => ':n',
161
- 'action' => %q%reject( _VAL_ <= 0.0,
162
- "in parameter '#{_PARAM_}' (#{_VAL_} must be a number greater than zero)")%,
163
- 'ind' => 1
164
- },
165
-
166
- ':0+i' => { 'pattern' => ':i',
167
- 'action' => %q%reject( _VAL_ < 0,
168
- "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive integer)")%,
169
- 'ind' => 1
170
- },
171
-
172
- ':0+n' => {
173
- 'pattern' => ':n',
174
- 'action' => %q%reject( _VAL_ < 0,
175
- "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive number)")%,
176
- 'ind' => 1
177
- },
178
- }
179
-
180
- end # _reset_stdtype
181
-
182
-
183
- # Given a standard type name, return the corresponding regex
184
- # pattern or nil
185
- def ScalarArg.stdtype(name)
186
- seen = {}
187
- while (!seen[name] && @@stdtype[name] && @@stdtype[name]['ind'])
188
- seen[name] = 1; name = @@stdtype[name]['pattern']
189
- end
190
-
191
- return nil if seen[name] || !@@stdtype[name]
192
- @@stdtype[name]['pattern']
193
- end
194
-
195
- def stdtype(name)
196
- ScalarArg.stdtype(name)
197
- end
198
-
199
-
200
- # Given the name of a type, return its corresponding action(s)
201
- def ScalarArg.stdactions(name)
202
- seen = {}
203
- actions = []
204
- while (!seen[name] && @@stdtype[name] && @@stdtype[name]['ind'])
205
- seen[name] = 1
206
- if @@stdtype[name]['action']
207
- actions.push( @@stdtype[name]['action'] )
208
- end
209
- name = @@stdtype[name]['pattern']
210
- end
211
-
212
- if @@stdtype[name] && @@stdtype[name]['action']
213
- actions.push( @@stdtype[name]['action'] )
214
- end
215
-
216
- return actions
217
- end
218
-
219
- # Add a new (user defined) type to the standard types
220
- def ScalarArg.addtype(abbrev, pattern, action, ref)
221
-
222
- typeid = ":#{abbrev}"
223
- unless (pattern =~ /\S/)
224
- pattern = ":s"
225
- ref = 1
226
- end
227
-
228
- @@stdtype[typeid] = {}
229
- @@stdtype[typeid]['pattern'] = "(?:#{pattern})" if pattern && !ref
230
- @@stdtype[typeid]['pattern'] = ":#{pattern}" if pattern && ref
231
- @@stdtype[typeid]['action'] = action if action
232
- @@stdtype[typeid]['ind'] = ref
233
-
234
- end
235
-
236
- attr :name
237
- attr :type
238
- attr :nows
239
-
240
-
241
- # Constructor
242
- def initialize(name, type, nows)
243
- @name = name
244
- @type = type
245
- @nows = nows
246
- end
247
-
248
- # Create regexp to match parameter
249
- def matcher(g)
250
- trailing = g ? '(?!'+Regexp::quote(g)+')' : ''
251
-
252
- # Find type in list of standard (and user) types
253
- stdtype = stdtype(@type)
254
-
255
- # Handle stdtypes that are specified as regex in parameter
256
- if (!stdtype && @type =~ %r"\A:/([^/]+)/\Z" )
257
- stdtype = "#$1"
258
- end
259
-
260
- if stdtype.nil?
261
- raise "Error: bad type in Getopt::Declare parameter variable specification near '<#{@name}#{@type}>'\nValid types are:\n" + @@stdtype.keys.inspect
262
- end
263
-
264
- stdtype = stdtype.dup # make a copy, as we'll change it in place
265
- stdtype.gsub!(/\%D/,"(?:#{trailing}\\d)")
266
- stdtype.gsub!(/\%T/,trailing)
267
- unless ( stdtype.sub!("\%F","") )
268
- stdtype = Getopt::Declare::Arg::negflagpat + stdtype
269
- end
270
- return "(?:#{stdtype})"
271
- end
272
-
273
- # Return string with code to process parameter
274
- def code(*t)
275
- if t[0]
276
- pos1 = t[0].to_s
277
- else
278
- pos1 = '0'
279
- end
280
-
281
- c = conversion
282
- c = "\n _VAL_ = _VAL_#{c} if _VAL_" if c
283
-
284
- code = <<-EOS
285
- _VAR_ = %q|<#{@name}>|
286
- _VAL_ = @@m[#{pos1}]
287
- _VAL_.tr!("\\0"," ") if _VAL_#{c}
288
- EOS
289
-
290
- actions = Getopt::Declare::ScalarArg::stdactions(@type)
291
-
292
- for i in actions
293
- next if i.nil?
294
- # i.sub!(/(\s*\{)/, '\1 module '+t[1])
295
- code << "
296
- begin
297
- #{i}
298
- end
299
- "
300
- end
301
-
302
- code << " #{@name} = _VAL_\n"
303
- end
304
-
305
- # Based on parameter type, default conversion to apply
306
- def conversion
307
- pat = @@stdtype[@type] ? @@stdtype[@type]['pattern'] : ''
308
- [ @type, pat ].each { |t|
309
- case t
310
- when /^\:0?(\+)?i$/
311
- return '.to_i'
312
- when /^\:0?(\+)?n$/
313
- return '.to_f'
314
- end
315
- }
316
- return nil
317
- end
318
-
319
- # Return string with code to cache argument in Getopt::Declare's cache
320
- def cachecode(ownerflag, itemcount)
321
- if itemcount > 1
322
- " @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
323
- else
324
- " @cache['#{ownerflag}'] = #{@name}\n"
325
- end
326
- end
327
-
328
- # Helps build regex that matches parameters of flags
329
- def trailer
330
- nil # MEANS TRAILING PARAMETER VARIABLE (in Perl,was '')
331
- end
332
-
333
- # Helps build regex that matches parameters of flags
334
- # Wraps parameter passed for #$1, etc. matching
335
- def ows(g)
336
- return '[\s|\0]*(' + g + ')' unless @nows
337
- '('+ g +')'
338
- end
339
-
340
- end # ScalarArg
341
-
342
-
343
- # Class used to handle array arguments
344
- class ArrayArg < ScalarArg
345
-
346
- # Create regexp to match array
347
- def matcher(g)
348
- suffix = !g.nil? ? '([\s\0]+)' : ''
349
- scalar = super # contains regex to match a scalar element
350
- # we match one obligatory element, and one or more optionals ')*'
351
- return scalar + '(?:[\s\0]+' + scalar + ')*' + suffix
352
- end
353
-
354
- # Return string with code to process array parameter
355
- def code(*t)
356
-
357
- if t[0]
358
- pos1 = t[0].to_s
359
- else
360
- pos1 = '0'
361
- end
362
-
363
- code = <<-EOS
364
- _VAR_ = %q|<#{@name}>|
365
- _VAL_ = nil
366
- #{@name} = (@@m[#{pos1}]||'').split(' ').map { |i|
367
- i.tr("\\0", " ") }
368
- EOS
369
-
370
- # Handle conversion to proper type
371
- c = conversion
372
- if c
373
- code << " #{@name}.map! { |i| i#{c} }\n"
374
- end
375
-
376
- actions = Getopt::Declare::ScalarArg::stdactions(@type)
377
- if actions.size > 0
378
- code << " for _VAL_ in #{@name}\n"
379
- for i in actions
380
- code << " #{i}\n"
381
- end
382
- code << " end\n\n"
383
- end
384
- return code
385
- end
386
-
387
- # Return string with code to cache array in Getopt::Declare's cache
388
- def cachecode(ownerflag, itemcount)
389
- if itemcount > 1
390
- " @cache['#{ownerflag}']['<#{@name}>'] = [] unless @cache['#{ownerflag}']['<#{@name}>']
391
- @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
392
- else
393
- " @cache['#{ownerflag}'] = #{@name}\n"
394
- end
395
- end
396
- end # ArrayArg
397
-
398
-
399
- # Class used to handle punctuations (., -, etc.)
400
- class Punctuator
401
-
402
- # Constructor
403
- def initialize(text, nows)
404
- @text = text
405
- @nows = nows
406
- end
407
-
408
- # Return regex that matches this punctuation
409
- def matcher(g)
410
- Arg::negflagpat + Regexp::quote(@text)
411
- end
412
-
413
- # Return string with code to process punctuation
414
- def code(*t)
415
-
416
- if t[0]
417
- pos1 = t[0].to_s
418
- else
419
- pos1 = '0'
420
- end
421
- " if @@m[#{pos1}] && !@@m[#{pos1}].empty?
422
- _PUNCT_['#{@text}'] = @@m[#{pos1}]
423
- end
424
- "
425
- end
426
-
427
- # Return string with code to cache punctuation in Getopt::Declare's cache
428
- def cachecode(ownerflag, itemcount)
429
- if itemcount > 1
430
- " @cache['#{ownerflag}']['#{@text}'] = _PUNCT_['#{@text}']\n"
431
- else
432
- " unless @cache['#{ownerflag}']\n" +
433
- " @cache['#{ownerflag}'] = _PUNCT_['#{@text}'] || 1\n" +
434
- " end\n"
435
- end
436
- end
437
-
438
- # Helps build regex that matches parameters of flags
439
- def trailer
440
- @text
441
- end
442
-
443
- # Helps build regex that matches parameters of flags
444
- # Wraps parameter passed for #$1, etc. matching
445
- def ows(g)
446
- return '[\s\0]*(' + g + ')' unless @nows
447
- '(' + g + ')'
448
- end #ows
449
-
450
- end # Punctuator
451
-
452
-
453
- # Class used to handle other arguments (flags, etc)
454
- class Arg
455
-
456
- @@nextid = 0
457
-
458
-
459
- Helpcmd = %w( -help --help -Help --Help -HELP --HELP -h -H )
460
-
461
- @@helpcmdH = {}
462
- for i in Helpcmd; @@helpcmdH[i] = 1; end
463
-
464
- def Arg.besthelp
465
- for i in Helpcmd; return i if @@helpcmdH[i]; end
466
- end
467
-
468
- # Create regex of help flags based on help shortcuts left
469
- def Arg.helppat
470
- @@helpcmdH.keys.join('|')
471
- end
472
-
473
-
474
- Versioncmd = %w( -version --version -Version --Version
475
- -VERSION --VERSION -v -V )
476
- @@versioncmdH = {}
477
- for i in Versioncmd; @@versioncmdH[i] = 1; end
478
-
479
- def Arg.bestversion
480
- for i in Versioncmd; return i if @@versioncmdH[i]; end
481
- end
482
-
483
- # Create regex of version flags based on help shortcuts left
484
- def Arg.versionpat
485
- @@versioncmdH.keys.join('|')
486
- end
487
-
488
- @@flags = []
489
- @@posflagpat = nil
490
- @@negflagpat = nil
491
-
492
- def Arg.clear
493
- @@flags = []
494
- @@nextid = 0
495
- @@posflagpat = nil
496
- @@negflagpath = nil
497
- end
498
-
499
- # Return string with regex that avoids all flags in declaration
500
- def Arg.negflagpat(*t)
501
- if !@@negflagpat && @@flags
502
- @@negflagpat = ( @@flags.map { |i|
503
- "(?!" + Regexp::quote(i) + ")" } ).join('')
504
- else
505
- @@negflagpat
506
- end
507
- end
508
-
509
- # Return string with regex that matches any of the flags in declaration
510
- def Arg.posflagpat(*t)
511
- if !@@posflagpat && @@flags
512
- @@posflagpat = '(?:' + ( @@flags.map { |i|
513
- Regexp::quote(i) } ).join('|') + ')'
514
- else
515
- @@posflagpat
516
- end
517
- end
518
-
519
- attr_accessor :flag, :args, :actions, :ditto, :nocase
520
- attr_accessor :required, :requires, :id, :repeatable, :desc
521
-
522
-
523
- # Constructor
524
- def initialize(spec, desc, dittoflag)
525
- first = 1
526
-
527
-
528
- @@nextid += 1
529
- @flag = ''
530
- @foundid = nil
531
- @args = []
532
- @actions = []
533
- @ditto = dittoflag
534
- @required = false
535
- @requires = nil
536
- @id = @@nextid
537
- @desc = spec.dup
538
- @items = 0
539
- @nocase = false
540
-
541
- @desc.sub!(/\A\s*(.*?)\s*\Z/,'\1')
542
-
543
- while spec && spec != ''
544
- begin
545
-
546
- # OPTIONAL
547
- if spec.sub!( /\A(\s*)\[/, '\1' )
548
- @args.push( StartOpt.new )
549
- next
550
- elsif spec.sub!(/\A\s*\]/,"")
551
- @args.push( EndOpt.new )
552
- next
553
- end
554
-
555
- # ARG
556
-
557
- se = DelimScanner::new( spec )
558
- tmp = se.scanBracketed('<>')
559
-
560
- arg = nows = nil
561
- arg, spec, nows = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp
562
-
563
-
564
- if arg
565
- arg =~ /\A(\s*)(<)([a-zA-Z]\w*)(:[^>]+|)>/ or
566
- raise "Error: bad Getopt::Declare parameter variable specification near '#{arg}'\n"
567
-
568
- # NAME,TYPE,NOW
569
- details = [ "#$3", "#$4", !first && !(nows.length>0) ]
570
-
571
- if spec && spec.sub!( /\A\.\.\./, "") # ARRAY ARG
572
- @args.push( ArrayArg.new(*details) )
573
- else # SCALAR ARG
574
- @args.push( ScalarArg.new(*details) )
575
- end
576
- @items += 1
577
- next
578
-
579
- # PUNCTUATION
580
- elsif spec.sub!( /\A(\s*)((\\.|[^\] \t\n\[<])+)/, '' )
581
- ows, punct = $1, $2
582
- punct.gsub!( /\\(?!\\)(.)/, '\1' )
583
-
584
- if first
585
- spec =~ /\A(\S+)/
586
- @foundid = "#{punct}#{$1}"
587
- @flag = punct
588
- @@flags.push( punct )
589
- else
590
- @args.push( Punctuator.new(punct, !(ows.size > 0)) )
591
- @items += 1
592
- end
593
-
594
- else
595
- break
596
- end # if arg/spec.sub
597
- ensure
598
- first = nil
599
- end
600
- end # while
601
-
602
-
603
- @@helpcmdH.delete(@flag) if @@helpcmdH.key?(@flag)
604
- @@versioncmdH.delete(@flag) if @@versioncmdH.key?(@flag)
605
- end # initialize
606
-
607
-
608
-
609
- # Return String with code to parse this argument (ie. flag)
610
- def code(*t)
611
- owner = t[0]
612
- mod = t[1]
613
-
614
-
615
- code = "\n"
616
- flag = @flag
617
- clump = owner.clump
618
- i = 0
619
- nocasei = ((Getopt::Declare::nocase || @nocase) ? 'i' : '')
620
-
621
- code << " catch(:paramout) do\n"
622
- code += !@repeatable? " while !_FOUND_['" + self.foundid + "']" :
623
- " while 1"
624
- if (flag && (clump==1 && flag !~ /\A[^a-z0-9]+[a-z0-9]\Z/i ||
625
- (clump<3 && @args.size > 0 )))
626
- code << " && !_lastprefix"
627
- end
628
-
629
- code << '
630
- begin
631
- catch(:param) do
632
- _pos = _nextpos if _args
633
- _PUNCT_ = {}
634
- '
635
-
636
- if flag != ''
637
- # This boundary is to handle -- option, so that if user uses
638
- # --foo and --foo is not a flag, it does not become
639
- # -- and unused: 'foo', but an error saying flag '--foo' not defined.
640
- boundary = ''
641
- boundary = '(\s+|\Z)' if flag =~ /^(--|-|\+|\+\+)$/
642
-
643
- code << '
644
- _args && _pos = gindex( _args, /\G[\s|\0]*' +
645
- Regexp::quote(flag) + boundary + '/' + nocasei + ", _pos) or throw(:paramout)
646
- unless @_errormsg
647
- @_errormsg = %q|incorrect specification of '" + flag + "' parameter|
648
- end
649
- "
650
- elsif ( ScalarArg::stdtype(@args[0].type)||'') !~ /\%F/
651
- code << "\n throw(:paramout) if @_errormsg\n"
652
- end
653
-
654
-
655
- code << "\n _PARAM_ = '" + self.name + "'\n"
656
-
657
-
658
- trailer = []
659
- i = @args.size-1
660
- while i > 0
661
- trailer[i-1] = @args[i].trailer
662
- trailer[i-1] = trailer[i] unless trailer[i-1]
663
- i -= 1
664
- end # while i
665
-
666
- if @args
667
- code << "\n"+' _args && _pos = gindex( _args, /\G'
668
-
669
- @args.each_with_index { |arg, i|
670
- code << arg.ows(arg.matcher(trailer[i]))
671
- }
672
-
673
- code << '/x' + nocasei + ", _pos ) or throw(:paramout)\n"
674
- end # if @args
675
-
676
- @args.each_with_index { |arg, i|
677
- code << arg.code(i,mod) #, $flag ????
678
- }
679
-
680
- if flag
681
- mutexlist = owner.mutex[flag] ?
682
- ( owner.mutex[flag].map {|i| "'#{i}'"} ).join(',') : ''
683
-
684
- code << "
685
- if _invalid.has_key?('#{flag}')
686
- @_errormsg = %q|parameter '#{flag}' not allowed with parameter '| + _invalid['#{flag}'] + %q|'|
687
- throw(:paramout)
688
- else
689
- for i in [#{mutexlist}]
690
- _invalid[i] = '#{flag}'
691
- end
692
- end #if/then
693
-
694
- "
695
- end
696
-
697
-
698
-
699
- for action in @actions
700
- #action.sub!( /(\s*\{)/, '\1 module '+mod ) # @TODO
701
- code << "\n " + action + "\n"
702
- end
703
-
704
- if flag && @items==0
705
- code << "\n @cache['#{flag}'] = '#{flag}'\n"
706
- if @ditto
707
- code << "\n @cache['#{@ditto.flag}'] = '#{flag}'\n"
708
- end
709
- end
710
-
711
- if @items > 1
712
- code << " @cache['#{self.name}'] = {} unless @cache['#{self.name}'].kind_of?(Hash)\n"
713
- if @ditto
714
- code << "\n @cache['#{@ditto.name}'] = {} unless @cache['#{@ditto.name}'].kind_of?(Hash)\n"
715
- end
716
- end
717
-
718
- for subarg in @args
719
- code << subarg.cachecode(self.name,@items)
720
- if ditto
721
- code << subarg.cachecode(@ditto.name,@items)
722
- end
723
- end
724
-
725
- if flag =~ /\A([^a-z0-9]+)/i
726
- code << ' _lastprefix = "'+ Regexp::quote("#$1") + '"' + "\n"
727
- else
728
- code << " _lastprefix = nil\n"
729
- end
730
-
731
- code << "
732
- _FOUND_['"+ self.foundid + "'] = 1
733
- throw :arg if _pos > 0
734
- _nextpos = _args.size
735
- throw :alldone
736
- end # catch(:param)
737
- end # begin
738
- end # while
739
- end # catch(:paramout)
740
- "
741
-
742
- code
743
- end
744
-
745
- # Return name of argument, which can be flag's name or variable's name
746
- def name
747
- return @flag unless @flag.empty?
748
- for i in @args
749
- return "<#{i.name}>" if i.respond_to?(:name)
750
- end
751
- raise "Unknown flag name for parameter #{self.desc}"
752
- end
753
-
754
- # Return foundid of argument, which can be flag's name or variable's name
755
- def foundid
756
- return @foundid || self.name
757
- end
758
-
759
- end # Arg
760
-
761
-
762
- private
763
-
764
- class << self
765
- @nocase = false
766
- attr_accessor :nocase
767
- end
768
-
769
- #
770
- # This is an additional function added to the class to simulate Perl's
771
- # pos() \G behavior and m///g
772
- #
773
- # It performs a regex match, and returns the last index position of the
774
- # match or nil. On successive invocations, it allows doing regex matches
775
- # NOT from the beginning of the string easily.
776
- #
777
- # Class Array @@m stores the list of matches, as #$1 and similar
778
- # variables have short lifespan in ruby, unlike perl.
779
- #
780
- def gindex(str, re, pos)
781
- @@m.clear()
782
- if pos = str.index( re, pos )
783
- l = $&.size # length of match
784
- if l > 0
785
- @@m[0] = "#$1"
786
- @@m[1] = "#$2"
787
- @@m[2] = "#$3"
788
- @@m[3] = "#$4"
789
- @@m[4] = "#$5"
790
- @@m[5] = "#$6"
791
- @@m[6] = "#$7"
792
- @@m[7] = "#$8"
793
- @@m[8] = "#$9"
794
- pos += l
795
- end
796
- end
797
- pos
798
- end
799
-
800
- # Given an array or hash, flatten them to a string
801
- def flatten(val, nested = nil)
802
- case val
803
- when Array
804
- return val.map{ |i| flatten(i,1) }.join(" ")
805
- when Hash
806
- return val.keys.map{ |i| nested ||
807
- i =~ /^-/ ? [i, flatten(val[i],1)] :
808
- [flatten(val[i],1)] }.join(" ")
809
- else
810
- return val
811
- end
812
- end
813
-
814
- # Read the next line from stdin
815
- def _get_nextline
816
- $stdin.readline
817
- end
818
-
819
- # For each file provided and found, read it in
820
- def _load_sources( _get_nextline, files )
821
- text = ''
822
- found = []
823
-
824
- for i in files
825
- begin
826
- f = File.open(i,"r")
827
- rescue
828
- next
829
- end
830
-
831
- if f.tty?
832
- found.push( '<STDIN>' )
833
- _get_nextline = method(:_get_nextline)
834
- else
835
- found.push( i );
836
- t = f.readlines.join(' ')
837
- t.tr!('\t\n',' ')
838
- text += t
839
- end
840
- end
841
-
842
- return nil unless found.size > 0
843
- text = $stdin.readline if text.empty?
844
- return [text, found.join(' or ')]
845
- end
846
-
847
- # Turn boolean flags into their ascii equivalents (have lower precedence)
848
- def _enbool(expr)
849
- expr.gsub!(/\s*\|\|\s*/," or ")
850
- expr.gsub!(/\s*&&\s*/," and ")
851
- expr.gsub!(/\s*!\s*/," not ")
852
- expr
853
- end
854
-
855
- #
856
- def _enfound(original)
857
- expr = original.gsub(/((?:&&|\|\|)?\s*(?:[!(]\s*)*)([^ \t\n|&\)]+)/x,
858
- '\1_FOUND_[\'\2\']')
859
-
860
- if !valid_syntax?( expr )
861
- raise "Error: bad condition in [requires: #{original}]\n"
862
- end
863
- expr
864
- end
865
-
866
- # Check parameter description for special options
867
- def _infer(desc, arg, mutex)
868
- while desc.sub!(/\[\s*mutex:\s*(.*?)\]/i,"")
869
- _mutex(mutex, "#$1".split(' '))
870
- end
871
-
872
- if desc =~ /\[\s*no\s*case\s*\]/i
873
- if arg
874
- arg.nocase = true
875
- else
876
- nocase = true
877
- end
878
- end
879
-
880
- if !arg.nil?
881
- if desc =~ /.*\[\s*excludes:\s*(.*?)\]/i
882
- _exclude(mutex, arg.name, ("#$1".split(' ')))
883
- end
884
-
885
- if desc =~ /.*\[\s*requires:\s*(.*?)\]/i
886
- arg.requires = "#$1"
887
- end
888
-
889
- arg.required = ( desc =~ /\[\s*required\s*\]/i )
890
-
891
- arg.repeatable = ( desc =~ /\[\s*repeatable\s*\]/i )
892
- end
893
-
894
- _typedef(desc) while desc.sub!(/.*?\[\s*pvtype:\s*/,"")
895
-
896
- end
897
-
898
-
899
-
900
- # Extract a new type from the description and add it to the list
901
- # of standard types
902
- def _typedef(desc)
903
- se = DelimScanner::new( desc )
904
- tmp = se.scanQuotelike
905
-
906
- name = nil
907
- name, desc = tmp[:delimText], tmp[:suffix] if tmp
908
-
909
- unless name
910
- desc.sub!(/\A\s*([^\] \t\n]+)/,"") and name = "#$1"
911
- end
912
-
913
- raise "Error: bad type directive (missing type name): [pvtype: " +
914
- desc[0,desc.index(']')||20] + "....\n" unless name
915
-
916
- se = DelimScanner::new( desc )
917
- tmp = se.scanQuotelike('\s*:?\s*')
918
-
919
- # @TODO What is element 2 of extract_quotelike? :trail is a fake here
920
- # pat,desc,ind = (extract_quotelike(desc,'\s*:?\s*'))[5,1,2]
921
- pat = ind = nil
922
- pat, desc, ind = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp
923
- pat = pat[1..-2] if pat
924
-
925
- unless pat
926
- desc.sub!(/\A\s*(:?)\s*([^\] \t\n]+)/,"") and pat = "#$2" and ind = "#$1"
927
- end
928
-
929
- pat = '' unless pat
930
-
931
-
932
- se = DelimScanner::new( desc )
933
- action = se.extractCodeblock || ''
934
-
935
- desc.sub!( Regexp::quote(action).to_re, '' )
936
- action = action[1..-2]
937
-
938
- raise "Error: bad type directive (expected closing ']' but found " +
939
- "'#$1' instead): [pvtype: #{name} " + (pat ? "/#{pat}/" : '') +
940
- " action:#{action} #$1#$2....\n" if desc =~ /\A\s*([^\] \t\n])(\S*)/
941
-
942
-
943
- Getopt::Declare::ScalarArg::addtype(name,pat,action,ind=~/:/)
944
- end
945
-
946
- # Handle quote replacements for [ditto] flag
947
- def _ditto(originalflag, originaldesc, extra)
948
- if originaldesc =~ /\n.*\n/
949
- originaldesc = "Same as #{originalflag} "
950
- else
951
- originaldesc.chomp
952
- originaldesc.gsub!(/\S/,'"')
953
- while originaldesc.gsub!(/"("+)"/,' \1 ')
954
- end
955
- originaldesc.gsub!(/""/,'" ')
956
- end
957
-
958
- "#{originaldesc}#{extra}\n"
959
- end
960
-
961
- # Check mutex conditions
962
- def _mutex(mref, mutexlist)
963
- for flag in mutexlist
964
- mref[flag] = [] unless mref[flag]
965
- for otherflag in mutexlist
966
- next if flag == otherflag
967
- mref[flag].push( otherflag )
968
- end
969
- end
970
- end
971
-
972
- # Check exclude conditions
973
- def _exclude(mref, excluded, mutexlist)
974
- for flag in mutexlist
975
- unless flag == excluded
976
- mref[flag] = [] unless mref[flag]
977
- mref[excluded] = [] unless mref[excluded]
978
- mref[excluded].push( flag )
979
- mref[flag].push( excluded )
980
- end
981
- end
982
- end
983
-
984
- # Returns a regex to match a single argument line
985
- def re_argument
986
- /\A(.*?\S.*?#{@@separator})(.*?\n)/
987
- end
988
-
989
- # Returns a regex to keep matching a multi-line description
990
- # for an argument.
991
- def re_more_desc
992
- /\A((?![ \t]*(\{|\n)|.*?\S.*?#{@@separator}.*?\S).*?\S.*\n)/
993
- end
994
-
995
- public
996
-
997
- # Constructor
998
- def initialize(*opts)
999
- @cache = nil
1000
-
1001
- Getopt::Declare::Arg::clear
1002
-
1003
- # HANDLE SHORT-CIRCUITS
1004
- return if opts.size==2 && (!opts[1] || opts[1] == '-SKIP')
1005
-
1006
- grammar, source = opts
1007
-
1008
- if grammar.nil?
1009
- raise "Error: No grammar description provided."
1010
- end
1011
-
1012
- ### REMOVED PREDEF GRAMMAR AS IT WAS NOT DOCUMENTED NOR
1013
- ### WORKING IN PERL'S Declare.pm VERSION.
1014
-
1015
- # PRESERVE ESCAPED '['s
1016
- grammar.gsub!(/\\\[/,"\255")
1017
-
1018
- # MAKE SURE GRAMMAR ENDS WITH A NEWLINE.
1019
- grammar.sub!(/([^\n])\Z/,'\1'+"\n")
1020
-
1021
- @usage = grammar.dup
1022
-
1023
- # SET-UP
1024
- i = grammar
1025
- _args = []
1026
- _mutex = {}
1027
- _strict = false
1028
- _all_repeatable = false
1029
- _lastdesc = nil
1030
- arg = nil
1031
- Getopt::Declare::nocase = false
1032
- Getopt::Declare::ScalarArg::_reset_stdtype
1033
-
1034
-
1035
- # CONSTRUCT GRAMMAR
1036
- while i.length > 0
1037
-
1038
- # COMMENT:
1039
- i.sub!(/\A[ \t]*#.*\n/,"") and next
1040
-
1041
-
1042
- # TYPE DIRECTIVE:
1043
- se = DelimScanner::new( i )
1044
-
1045
- if i =~ /\A\s*\[\s*pvtype:/
1046
- _action = se.extractBracketed("[")
1047
- if _action
1048
- i.sub!( Regexp::quote( _action ).to_re, "" ) ### @GGA: added
1049
- i.sub!(/\A[ \t]*\n/,"") ### @GGA: added
1050
- _action.sub!(/.*?\[\s*pvtype:\s*/,"")
1051
- _typedef(_action)
1052
- next
1053
- end # if
1054
- end
1055
-
1056
- # ACTION
1057
- codeblockDelimiters = {
1058
- '{' => '}',
1059
- }
1060
-
1061
- _action = se.extractCodeblock(codeblockDelimiters)
1062
- if _action
1063
- i.sub!( Regexp::quote(_action ).to_re, "" )
1064
- i.sub!(/\A[ \t]*\n/,"")
1065
- _action = _action[1..-2]
1066
-
1067
- if !valid_syntax?( _action )
1068
- raise "Error: bad action in Getopt::Declare specification:" +
1069
- "\n\n#{_action}\n\n\n"
1070
- end
1071
-
1072
- if _args.length == 0
1073
- raise "Error: unattached action in Getopt::Declare specification:\n#{_action}\n" +
1074
- "\t(did you forget the tab after the preceding parameter specification?)\n"
1075
- end
1076
-
1077
- _args.last.actions.push( _action )
1078
- next
1079
- elsif i =~ /\A(\s*[{].*)/
1080
- raise "Error: incomplete action in Getopt::Declare specification:\n$1.....\n" +
1081
- "\t(did you forget a closing '}'?)\n"
1082
- end
1083
-
1084
-
1085
- # ARG + DESC:
1086
- if i.sub!(re_argument,"")
1087
- spec = "#$1".strip
1088
- desc = "#$2"
1089
- _strict ||= desc =~ /\[\s*strict\s*\]/
1090
-
1091
- while i.sub!(re_more_desc,"")
1092
- desc += "#$1"
1093
- end
1094
-
1095
- ditto = nil
1096
- if _lastdesc and desc.sub!(/\A\s*\[\s*ditto\s*\]/,_lastdesc)
1097
- ditto = arg
1098
- else
1099
- _lastdesc = desc
1100
- end
1101
-
1102
- # Check for GNU spec line like: -d, --debug
1103
- arg = nil
1104
- if spec =~ /(-[\w_\d]+),\s+(--[\w_\d]+)(\s+.*)?/
1105
- specs = ["#$1#$3", "#$2#$3"]
1106
- specs.each { |spec|
1107
- arg = Arg.new(spec,desc,ditto)
1108
- _args.push( arg )
1109
- _infer(desc, arg, _mutex)
1110
- ditto = arg
1111
- }
1112
- else
1113
- arg = Arg.new(spec,desc,ditto)
1114
- _args.push( arg )
1115
- _infer(desc, arg, _mutex)
1116
- end
1117
-
1118
-
1119
- next
1120
- end
1121
-
1122
- # OTHERWISE: DECORATION
1123
- i.sub!(/((?:(?!\[\s*pvtype:).)*)(\n|(?=\[\s*pvtype:))/,"")
1124
- decorator = "#$1"
1125
- _strict ||= decorator =~ /\[\s*strict\s*\]/
1126
- _infer(decorator, nil, _mutex)
1127
-
1128
- _all_repeatable = true if decorator =~ /\[\s*repeatable\s*\]/
1129
- @@debug = true if decorator =~ /\[\s*debug\s*\]/
1130
-
1131
- end # while i.length
1132
-
1133
-
1134
- _lastactions = nil
1135
- for i in _args
1136
- if _lastactions && i.ditto && i.actions.size == 0
1137
- i.actions = _lastactions
1138
- else
1139
- _lastactions = i.actions
1140
- end
1141
-
1142
- if _all_repeatable
1143
- i.repeatable = 1
1144
- end
1145
- end
1146
-
1147
- # Sort flags based on criteria described in docs
1148
- # Sadly, this cannot be reduced to sort_by
1149
- _args = _args.sort() { |a,b|
1150
- ( b.flag.length() <=> a.flag.length() ) or
1151
- ( b.flag == a.flag and ( b.args.length() <=> a.args.length() ) ) or
1152
- ( a.id <=> b.id )
1153
- }
1154
- # _args = _args.sort_by { |a| [a.flag.size, a.flag, a.args.size, a.id] }
1155
-
1156
-
1157
- # Handle clump
1158
- clump = (@usage =~ /\[\s*cluster:\s*none\s*\]/i) ? 0 :
1159
- (@usage =~ /\[\s*cluster:\s*singles?\s*\]/i) ? 1 :
1160
- (@usage =~ /\[\s*cluster:\s*flags?\s*\]/i) ? 2 :
1161
- (@usage =~ /\[\s*cluster:\s*any\s*\]/i) ? 3 :
1162
- (@usage =~ /\[\s*cluster:(.*)\s*\]/i) ? "r" : 3
1163
- raise "Error: unknown clustering mode: [cluster:#$1]\n" if clump == "r"
1164
-
1165
- # CONSTRUCT OBJECT ITSELF
1166
- @args = _args
1167
- @mutex = _mutex
1168
- @helppat = Arg::helppat()
1169
- @verspat = Arg::versionpat()
1170
-
1171
- @strict = _strict
1172
- @clump = clump
1173
- @source = ''
1174
- @tight = @usage =~ /\[\s*tight\s*\]/i
1175
- @caller = caller()
1176
-
1177
- # VESTIGAL DEBUGGING CODE
1178
- if @@debug
1179
- f = File.new(".CODE.rb","w") and
1180
- f.puts( code() ) and
1181
- f.close()
1182
- end
1183
-
1184
- # DO THE PARSE (IF APPROPRIATE)
1185
- if opts.size == 2
1186
- return nil unless parse(source)
1187
- else
1188
- return nil unless parse()
1189
- end
1190
-
1191
- end # initialize
1192
-
1193
-
1194
- # Parse the parameter description and in some cases,
1195
- # optionally eval it, too.
1196
- def parse(*opts)
1197
- source = opts[0]
1198
- _args = nil
1199
- _get_nextline = proc { nil }
1200
-
1201
- if source
1202
- case source
1203
- when Method
1204
- _get_nextline = source
1205
- _args = _get_nextline.call(self)
1206
- source = '[METHOD]'
1207
- when Proc
1208
- _get_nextline = source
1209
- _args = _get_nextline.call(self)
1210
- source = '[PROC]'
1211
- when IO
1212
- if source.fileno > 0 && source.tty?
1213
- _get_nextline = method(:_get_nextline)
1214
- _args = $stdin.readline
1215
- source = '<STDIN>'
1216
- else
1217
- _args = source.readlines.join(' ')
1218
- _args.tr!('\t\n',' ')
1219
- end
1220
- when :build, :skip
1221
- return 0
1222
- when Array
1223
- if source.length() == 1 && !source[0] ||
1224
- source[0] == "-BUILD" ||
1225
- source[0] == "-SKIP"
1226
- return 0
1227
- elsif source.length() == 2 && source[0] == "-ARGV"
1228
- if !source[1] or !source[1] === Array
1229
- raise 'Error: parse(["-ARGV"]) not passed an array as second parameter.'
1230
- end
1231
- _args = source[1].map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1232
- source = '<ARRAY>'
1233
- elsif source.length() == 1 && source[0] == "-STDIN"
1234
- _get_nextline = method(:_get_nextline)
1235
- _args = $stdin.readline
1236
- source = '<STDIN>'
1237
- elsif source.length() == 1 && source[0] == '-CONFIG'
1238
- progname = "#{$0}rc"
1239
- progname.sub!(%r#.*/#,'')
1240
- home = ENV['HOME'] || ''
1241
- _args, source = _load_sources( _get_nextline,
1242
- [ home+"/.#{progname}",
1243
- ".#{progname}" ] )
1244
- else
1245
- # Bunch of files to load passed to parse()
1246
- _args, source = _load_sources( _get_nextline, source )
1247
- end
1248
- when String # else/case LITERAL STRING TO PARSE
1249
- _args = source.dup
1250
- source = source[0,7] + '...' if source && source.length() > 7
1251
- source = "\"#{source[0..9]}\""
1252
- else
1253
- raise "Unknown source type for Getopt::Declare::parse"
1254
- end # case
1255
- return 0 unless _args
1256
- source = " (in #{source})"
1257
- else
1258
- _args = ARGV.map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1259
- source = ''
1260
- end
1261
-
1262
- @source = source
1263
- begin
1264
- err = eval( code(@caller) )
1265
- if $@
1266
- # oops, something wrong... exit
1267
- puts "#{$!}: #{$@.inspect}"
1268
- exit(1)
1269
- end
1270
- if !err
1271
- exit(1)
1272
- end
1273
- rescue
1274
- raise
1275
- end
1276
-
1277
-
1278
- true
1279
- end
1280
-
1281
- def type(*t)
1282
- Getopt::Declare::ScalarArg::addtype(t)
1283
- end
1284
-
1285
- # Print out version information and maybe exit
1286
- def version(*t)
1287
- prog = "#{$0}"
1288
- begin
1289
- filedate = File.stat( prog ).mtime.localtime()
1290
- rescue
1291
- filedate = 'Unknown date'
1292
- end
1293
- prog.sub!(%r#.*/#,'')
1294
- r = ''
1295
- if defined?($VERSION)
1296
- r << "\n#{prog}: version #{$VERSION} (#{filedate})\n\n"
1297
- else
1298
- r << "\n#{prog}: version dated #{filedate}\n\n"
1299
- end
1300
-
1301
- if t.empty?
1302
- return r
1303
- else
1304
- puts r
1305
- exit t[0]
1306
- end
1307
- end
1308
-
1309
- # Print out usage information
1310
- def usage(*opt)
1311
-
1312
- t = @usage
1313
-
1314
- lastflag = nil
1315
- lastdesc = nil
1316
- usage = ''
1317
-
1318
- while t.length() > 0
1319
-
1320
- # COMMENT:
1321
- t.sub!(/\A[ \t]*#.*\n/,".") and next
1322
-
1323
- # TYPE DIRECTIVE:
1324
- se = DelimScanner::new( t )
1325
-
1326
- if t =~ /\A\s*\[pvtype:/
1327
- if action = se.extractBracketed("[")
1328
- t.sub!(Regexp::quote( action ).to_re,'')
1329
- t.sub!(/\A[ \t]*\n/,"")
1330
- next
1331
- end
1332
- end
1333
-
1334
- # ACTION
1335
- codeblockDelimiters = {
1336
- '{' => '}'
1337
- }
1338
- se = DelimScanner::new( t )
1339
- if action = se.extractCodeblock(codeblockDelimiters)
1340
- t.sub!(Regexp::quote( action ).to_re,'')
1341
- t.sub!(/\A[ \t]*\n/,"")
1342
- decfirst = 0 unless !decfirst.nil?
1343
- next
1344
- end
1345
-
1346
-
1347
- # ARG + DESC:
1348
- if t.sub!(re_argument,"")
1349
- decfirst = 0 unless !decfirst.nil?
1350
- spec = "#$1".expand_tabs!()
1351
- desc = "#$2".expand_tabs!()
1352
-
1353
- while t.gsub!(re_more_desc, '')
1354
- desc += "#$1".expand_tabs!
1355
- end
1356
-
1357
- next if desc =~ /\[\s*undocumented\s*\]/i
1358
-
1359
- uoff = 0
1360
- spec.gsub!(/(<[a-zA-Z]\w*):([^>]+)>/e) { |i|
1361
- uoff += 1 + "#$2".length() and "#$1>"
1362
- }
1363
- spec.gsub!(/\t/,"=")
1364
-
1365
- ditto = desc =~ /\A\s*\[ditto\]/
1366
- desc.gsub!(/^\s*\[.*?\]\s*\n/m,"")
1367
- desc.gsub!(BracketDirectives,'')
1368
- #desc.gsub!(/\[.*?\]/,"")
1369
-
1370
-
1371
- if ditto
1372
- desc = (lastdesc ? _ditto(lastflag,lastdesc,desc) : "" )
1373
- elsif desc =~ /\A\s*\Z/
1374
- next
1375
- else
1376
- lastdesc = desc
1377
- end
1378
-
1379
- spec =~ /\A\s*(\S+)/ and lastflag = "#$1"
1380
-
1381
- desc.sub!(/\s+\Z/, "\n")
1382
- usage += spec + ' ' * uoff + desc
1383
- next
1384
- end
1385
-
1386
-
1387
-
1388
- # OTHERWISE, DECORATION
1389
- if t.sub!(/((?:(?!\[pvtype:).)*)(\n|(?=\[pvtype:))/,"")
1390
- desc = "#$1"+("#$2"||'')
1391
- #desc.gsub!(/^(\s*\[.*?\])+\s*\n/m,'')
1392
- #desc.gsub!(/\[.*?\]/,'') # eliminates anything in brackets
1393
- if @tight || desc !~ /\A\s*\Z/
1394
- desc.gsub!(BracketDirectives,'')
1395
- next if desc =~ /\A\s*\Z/
1396
- end
1397
- decfirst = 1 unless !decfirst.nil? or desc =~ /\A\s*\Z/
1398
- usage += desc
1399
- usage.rstrip!
1400
- end
1401
-
1402
- end #while
1403
-
1404
- required = ''
1405
-
1406
- for arg in @args
1407
- required += ' ' + arg.desc + ' ' if arg.required
1408
- end
1409
-
1410
- usage.gsub!(/\255/,"[/") # REINSTATE ESCAPED '['s
1411
-
1412
- required.gsub!(/<([a-zA-Z]\w*):[^>]+>/,'<\1>')
1413
- required.rstrip!
1414
-
1415
- helpcmd = Getopt::Declare::Arg::besthelp
1416
- versioncmd = Getopt::Declare::Arg::bestversion
1417
-
1418
-
1419
- header = ''
1420
- unless @source.nil?
1421
- header << version()
1422
- prog = "#{$0}"
1423
- prog.sub!(%r#.*/#,'')
1424
- header << "Usage: #{prog} [options]#{required}\n"
1425
- header << " #{prog} #{helpcmd}\n" if helpcmd
1426
- header << " #{prog} #{versioncmd}\n" if versioncmd
1427
- header << "\n" unless decfirst && decfirst == 1 && usage =~ /\A[ \t]*\n/
1428
- end
1429
-
1430
- header << "Options:\n" unless decfirst && decfirst == 1
1431
-
1432
- if opt.empty?
1433
- return header + usage + "\n"
1434
- end
1435
-
1436
- pager = $stdout
1437
- #begin
1438
- # eval('require "IO/Pager";')
1439
- # pager = IO::Pager.new()
1440
- #rescue
1441
- #end
1442
-
1443
- pager.puts "#{header}#{usage}"
1444
- exit(opt[0]) if opt[0]
1445
- end
1446
-
1447
- attr_accessor :unused
1448
-
1449
-
1450
- # Return list of used parameters (after parsing)
1451
- def used
1452
- used = @cache.keys
1453
- return used.join(' ')
1454
- end
1455
-
1456
- @@m = []
1457
-
1458
- # Main method to generate code to be evaluated for parsing.
1459
- def code(*t)
1460
- package = t[0] || ''
1461
- code = %q%
1462
-
1463
-
1464
- @_deferred = []
1465
- @_errormsg = nil
1466
- @_finished = nil
1467
-
1468
- begin
1469
-
1470
- begin
1471
- undef :defer
1472
- undef :reject
1473
- undef :finish
1474
- rescue
1475
- end
1476
-
1477
- def defer(&i)
1478
- @_deferred.push( i )
1479
- end
1480
-
1481
- def reject(*i)
1482
- if !i || i[0]
1483
- @_errormsg = i[1] if i[1]
1484
- throw :paramout
1485
- end
1486
- end
1487
-
1488
- def finish(*i)
1489
- if i.size
1490
- @_finished = i
1491
- else
1492
- @_finished = true
1493
- end
1494
- end
1495
-
1496
- @unused = []
1497
- @cache = {}
1498
- _FOUND_ = {}
1499
- _errors = 0
1500
- _invalid = {}
1501
- _lastprefix = nil
1502
-
1503
- _pos = 0 # current position to match from
1504
- _nextpos = 0 # next position to match from
1505
-
1506
- catch(:alldone) do
1507
- while !@_finished
1508
- begin
1509
- catch(:arg) do
1510
- @_errormsg = nil
1511
-
1512
- # This is used for clustering of flags
1513
- while _lastprefix
1514
- substr = _args[_nextpos..-1]
1515
- substr =~ /^(?!\s|\0|\Z)% +
1516
- Getopt::Declare::Arg::negflagpat() + %q%/ or
1517
- begin
1518
- _lastprefix=nil
1519
- break
1520
- end
1521
- "#{_lastprefix}#{substr}" =~ /^(% +
1522
- Getopt::Declare::Arg::posflagpat() + %q%)/ or
1523
- begin
1524
- _lastprefix=nil
1525
- break
1526
- end
1527
- _args = _args[0.._nextpos-1] + _lastprefix + _args[_nextpos..-1]
1528
- break
1529
- end # while _lastprefix
1530
-
1531
- % + '' + %q%
1532
- _pos = _nextpos if _args
1533
-
1534
- usage(0) if _args && gindex(_args,/\G(% + @helppat + %q%)(\s|\0|\Z)/,_pos)
1535
- version(0) if _args && _args =~ /\G(% + @verspat + %q%)(\s|\0|\Z)/
1536
- %
1537
-
1538
- for arg in @args
1539
- code << arg.code(self,package)
1540
- end
1541
-
1542
- code << %q%
1543
-
1544
- if _lastprefix
1545
- _pos = _nextpos + _lastprefix.length()
1546
- _lastprefix = nil
1547
- next
1548
- end
1549
-
1550
- _pos = _nextpos
1551
-
1552
- _args && _pos = gindex( _args, /\G[\s|\0]*(\S+)/, _pos ) or throw(:alldone)
1553
-
1554
- if @_errormsg
1555
- $stderr.puts( "Error#{source}: #{@_errormsg}\n" )
1556
- else
1557
- @unused.push( @@m[0] )
1558
- end
1559
-
1560
- _errors += 1 if @_errormsg
1561
-
1562
- end # catch(:arg)
1563
-
1564
- ensure # begin
1565
- _pos = 0 if _pos.nil?
1566
- _nextpos = _pos if _args
1567
- if _args and _args.index( /\G(\s|\0)*\Z/, _pos )
1568
- _args = _get_nextline.call(self) if !@_finished
1569
- throw(:alldone) unless _args
1570
- _pos = _nextpos = 0
1571
- _lastprefix = ''
1572
- end # if
1573
- end # begin/ensure
1574
- end # while @_finished
1575
- end # catch(:alldone)
1576
- end # begin
1577
-
1578
- %
1579
-
1580
-
1581
- ################################
1582
- # Check for required arguments #
1583
- ################################
1584
- for arg in @args
1585
- next unless arg.required
1586
-
1587
- code << %q%unless _FOUND_['% + arg.name + %q%'] %
1588
-
1589
- if @mutex[arg.name]
1590
- for m in @mutex[arg.name]
1591
- code << %q# or _FOUND_['# + m + %q#']#
1592
- end
1593
- end
1594
-
1595
- code << %q%
1596
- $stderr.puts "Error#{@source}: required parameter '% + arg.name + %q%' not found."
1597
- _errors += 1
1598
- end
1599
- %
1600
-
1601
- end
1602
-
1603
- ########################################
1604
- # Check for arguments requiring others #
1605
- ########################################
1606
-
1607
- for arg in @args
1608
- next unless arg.requires
1609
-
1610
- code << %q%
1611
- if _FOUND_['% + arg.name + %q%'] && !(% + _enfound(arg.requires) +
1612
- %q%)
1613
- $stderr.puts "Error#{@source}.: parameter '% + arg.name + %q%' can only be specified with '% + _enbool( arg.requires ) + %q%'"
1614
- _errors += 1
1615
- end
1616
- %
1617
- end
1618
-
1619
- code << %q%
1620
- #################### Add unused arguments
1621
- if _args && _nextpos > 0 && _args.length() > 0
1622
- @unused.replace( @unused + _args[_nextpos..-1].split(' ') )
1623
- end
1624
-
1625
- for i in @unused
1626
- i.tr!( "\0", " " )
1627
- end
1628
-
1629
- %
1630
-
1631
- if @strict
1632
- code << %q%
1633
- #################### Handle strict flag
1634
- unless _nextpos < ( _args ? _args.length : 0 )
1635
- for i in @unused
1636
- $stderr.puts "Error#{@source}: unrecognizable argument ('#{i}')"
1637
- _errors += 1
1638
- end
1639
- end
1640
- %
1641
- end
1642
-
1643
- code << %q%
1644
- #################### Print help hint
1645
- if _errors > 0 && !@source.nil?
1646
- $stderr.puts "\n(try '#$0 % + Getopt::Declare::Arg::besthelp + %q%' for more information)"
1647
- end
1648
-
1649
- ## cannot just assign unused to ARGV in ruby
1650
- unless @source != ''
1651
- ARGV.clear
1652
- @unused.map { |i| ARGV.push(i) }
1653
- end
1654
-
1655
- unless _errors > 0
1656
- for i in @_deferred
1657
- begin
1658
- i.call
1659
- rescue => e
1660
- STDERR.puts "Action in Getopt::Declare specification produced:\n#{e}"
1661
- _errors += 1
1662
- end
1663
- end
1664
- end
1665
-
1666
- !(_errors>0) # return true or false (false for errors)
1667
-
1668
- %
1669
- return code
1670
- end
1671
-
1672
-
1673
- # Inspect cache (not the declare object)
1674
- def inspect
1675
- return nil if !@cache
1676
- t = ''
1677
-
1678
- @cache.each { |a,b|
1679
- t << a + " => "
1680
- case b
1681
- when Hash
1682
- t << "{"
1683
- i = []
1684
- b.each { |c,d|
1685
- i.push( " '#{c}' => " + d.inspect )
1686
- }
1687
- t << i.join(',')
1688
- t << " }"
1689
- else
1690
- t << b.inspect
1691
- end
1692
- t << "\n"
1693
- }
1694
- t << "Unused: " + unused.join(', ')
1695
- end
1696
-
1697
- # Iterator for Getopt::Declare (travels thru all cache keys)
1698
- def each(&t)
1699
- @cache.each(&t)
1700
- end
1701
-
1702
- # Operator to easily create new value in of Getopt::Declare
1703
- def []=(name,val)
1704
- @cache = {} unless @cache
1705
- @cache[name] = val
1706
- end
1707
-
1708
- # Operator to easily return cache of Getopt::Declare
1709
- def [](name)
1710
- if @cache
1711
- return @cache[name]
1712
- else
1713
- return nil
1714
- end
1715
- end
1716
-
1717
- # Operator to return number of flags set
1718
- def size
1719
- return 0 unless @cache
1720
- return @cache.keys.size
1721
- end
1722
-
1723
- attr :mutex
1724
- attr :helppat
1725
- attr :verspat
1726
- attr :strict
1727
- attr :clump
1728
- attr :source
1729
-
1730
- end # class Declare
1731
-
1732
- end # module Getopt
1733
-
1734
-
1735
-
1736
-
1737
- __END__
1738
-
1
+ #
2
+ # Getopt::Declare - Declaratively Expressed Command-Line Arguments via Regular Expressions
3
+ #
4
+ # Ruby port of Perl's Getopt::Declare, version 1.21,
5
+ # released May 21, 1999.
6
+ #
7
+ # $Release Version: 1.26 $
8
+ # $Date: 2007/01/15 10:53:09 $
9
+ # by Gonzalo Garramu�o
10
+ #
11
+ # For detailed instructions, see Declare.rdoc file
12
+ #
13
+ # Ruby Port:
14
+ # Copyright (c) 2004, Gonzalo Garramuno. All Rights Reserved.
15
+ # This package is free software. It may be used, redistributed
16
+ # and/or modified under the terms of the Perl Artistic License
17
+ # (see http://www.perl.com/perl/misc/Artistic.html)
18
+ #
19
+ # Original Perl Implementation:
20
+ # Damian Conway (damian@conway.org)
21
+ # Copyright (c) 1997-2000, Damian Conway. All Rights Reserved.
22
+ # This package is free software. It may be used, redistributed
23
+ # and/or modified under the terms of the Perl Artistic License
24
+ # (see http://www.perl.com/perl/misc/Artistic.html)
25
+ #
26
+
27
+ require "Getopt/DelimScanner"
28
+
29
+
30
+ # Verifies that code is valid Ruby code. returns false if not
31
+ def valid_syntax?(code, fname = 'parser_code')
32
+ eval("BEGIN {return true}\n#{code}", nil, fname, 0)
33
+ rescue Exception
34
+ false
35
+ end
36
+
37
+
38
+ # An add-on to the String class
39
+ class String
40
+ # Expand all tabs to spaces
41
+ def expand_tabs!( tabstop = 8 )
42
+ while self.sub!(/(^|\n)([^\t\n]*)(\t+)/sex) { |f|
43
+ val = ( tabstop * "#$3".length() - ("#$2".length() % tabstop) )
44
+ "#$1#$2" + (" " * val)
45
+ }
46
+ end
47
+ self
48
+ end
49
+
50
+ # Return new string with all tabs set to spaces
51
+ def expand_tabs( tabstop = 8 )
52
+ h = self.dup
53
+ while h.sub!(/(^|\n)([^\t\n]*)(\t+)/sex) { |f|
54
+ val = ( tabstop * "#$3".length() - ("#$2".length() % tabstop) )
55
+ "#$1#$2" + (" " * val)
56
+ }
57
+ end
58
+ h
59
+ end
60
+ end
61
+
62
+
63
+ # Regex for removing bracket directives
64
+ BracketDirectives =
65
+ /\[\s*(?:ditto|tight|strict|no\s*case|repeatable|debug|required|mutex:.*|implies:.*|excludes:.*|requires:.*|cluster:.*)\s*\]/
66
+
67
+
68
+ module Getopt
69
+
70
+ # Main Class
71
+ class Declare
72
+
73
+ VERSION = '1.26'
74
+
75
+ # For debugging, use [debug] and it will output the ruby code as .CODE.rb
76
+ @@debug = false
77
+
78
+ # Main separator used to distinguish arguments in Getopt/Declare spec.
79
+ # By default, one or more tabs or 3 spaces or more.
80
+ @@separator = '(?:\t+| {3})'
81
+
82
+ # Class used to handle the beginning of options
83
+ class StartOpt
84
+
85
+ # Returns regex used matching start of options
86
+ def matcher(g)
87
+ '(?:()'
88
+ end
89
+
90
+ # Returns code used
91
+ def code(*t)
92
+ ''
93
+ end
94
+
95
+ # Returns how to cache code in class
96
+ def cachecode(a,b)
97
+ ''
98
+ end
99
+
100
+ # Helps build regex that matches parameters of flags
101
+ def trailer
102
+ nil
103
+ end
104
+
105
+ # Helps build regex that matches parameters of flags
106
+ def ows(g)
107
+ g
108
+ end
109
+ end # StartOpt
110
+
111
+
112
+ # Class used to handle the ending of options
113
+ class EndOpt < StartOpt
114
+ # Returns regex used matching end of options
115
+ def matcher(g)
116
+ '())?'
117
+ end
118
+ end # EndOpt
119
+
120
+
121
+ # Class used to handle scalar (ie.non-array) parameters
122
+ class ScalarArg
123
+
124
+ @@stdtype = {}
125
+
126
+ # (re)set standard types
127
+ def ScalarArg._reset_stdtype
128
+ @@stdtype = {
129
+ ':i' => { 'pattern' => '(?:(?:%T[+-]?)%D+)' },
130
+ ':n' => { 'pattern' => '(?:(?:%T[+-]?)(?:%D+(?:%T\.%D*)?' +
131
+ '(?:%T[eE](?:[+-])?%D+)?|%T\.%D+(?:%T[eE](?:[+-])?%D+)?))',
132
+ },
133
+ ':s' => { 'pattern' => '(?:%T(?:\S|\0))+(?=\s|\0|\z)' },
134
+ ':qs' => { 'pattern' => %q{"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|(?:%T(?:\S|\0))+} },
135
+ ':id' => { 'pattern' => '%T[a-zA-Z_](?:%T\w)*(?=\s|\0|\z)' },
136
+ ':d' => { 'pattern' => '(?:%T(?:\S|\0))+',
137
+ 'action' => %q%
138
+ reject( (_VAL_.nil? || !test(?d, _VAL_) ),
139
+ "in parameter '#{_PARAM_}' (\"#{_VAL_}\" is not a directory)")%
140
+ },
141
+ ':if' => { 'pattern' => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
142
+ 'action' => %q%
143
+ reject( (_VAL_.nil? || _VAL_ != "-" && !test(?r, _VAL_) ),
144
+ "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not readable)")%
145
+ },
146
+ ':of' => { 'pattern' => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
147
+ 'action' => %q%
148
+ reject( (_VAL_.nil? || _VAL_ != "-" &&
149
+ test(?r, _VAL_) && !test(?w, _VAL_)),
150
+ "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not writable)")%
151
+ },
152
+ '' => { 'pattern' => ':s', 'ind' => 1 },
153
+
154
+ ':+i' => { 'pattern' => ':i',
155
+ 'action' => %q%reject( _VAL_ <= 0,
156
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an integer greater than zero)")%,
157
+ 'ind' => 1
158
+ },
159
+
160
+ ':+n' => { 'pattern' => ':n',
161
+ 'action' => %q%reject( _VAL_ <= 0.0,
162
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be a number greater than zero)")%,
163
+ 'ind' => 1
164
+ },
165
+
166
+ ':0+i' => { 'pattern' => ':i',
167
+ 'action' => %q%reject( _VAL_ < 0,
168
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive integer)")%,
169
+ 'ind' => 1
170
+ },
171
+
172
+ ':0+n' => {
173
+ 'pattern' => ':n',
174
+ 'action' => %q%reject( _VAL_ < 0,
175
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive number)")%,
176
+ 'ind' => 1
177
+ },
178
+ }
179
+
180
+ end # _reset_stdtype
181
+
182
+
183
+ # Given a standard type name, return the corresponding regex
184
+ # pattern or nil
185
+ def ScalarArg.stdtype(name)
186
+ seen = {}
187
+ while (!seen[name] && @@stdtype[name] && @@stdtype[name]['ind'])
188
+ seen[name] = 1; name = @@stdtype[name]['pattern']
189
+ end
190
+
191
+ return nil if seen[name] || !@@stdtype[name]
192
+ @@stdtype[name]['pattern']
193
+ end
194
+
195
+ def stdtype(name)
196
+ ScalarArg.stdtype(name)
197
+ end
198
+
199
+
200
+ # Given the name of a type, return its corresponding action(s)
201
+ def ScalarArg.stdactions(name)
202
+ seen = {}
203
+ actions = []
204
+ while (!seen[name] && @@stdtype[name] && @@stdtype[name]['ind'])
205
+ seen[name] = 1
206
+ if @@stdtype[name]['action']
207
+ actions.push( @@stdtype[name]['action'] )
208
+ end
209
+ name = @@stdtype[name]['pattern']
210
+ end
211
+
212
+ if @@stdtype[name] && @@stdtype[name]['action']
213
+ actions.push( @@stdtype[name]['action'] )
214
+ end
215
+
216
+ return actions
217
+ end
218
+
219
+ # Add a new (user defined) type to the standard types
220
+ def ScalarArg.addtype(abbrev, pattern, action, ref)
221
+
222
+ typeid = ":#{abbrev}"
223
+ unless (pattern =~ /\S/)
224
+ pattern = ":s"
225
+ ref = 1
226
+ end
227
+
228
+ @@stdtype[typeid] = {}
229
+ @@stdtype[typeid]['pattern'] = "(?:#{pattern})" if pattern && !ref
230
+ @@stdtype[typeid]['pattern'] = ":#{pattern}" if pattern && ref
231
+ @@stdtype[typeid]['action'] = action if action
232
+ @@stdtype[typeid]['ind'] = ref
233
+
234
+ end
235
+
236
+ attr :name
237
+ attr :type
238
+ attr :nows
239
+
240
+
241
+ # Constructor
242
+ def initialize(name, type, nows)
243
+ @name = name
244
+ @type = type
245
+ @nows = nows
246
+ end
247
+
248
+ # Create regexp to match parameter
249
+ def matcher(g)
250
+ trailing = g ? '(?!'+Regexp::quote(g)+')' : ''
251
+
252
+ # Find type in list of standard (and user) types
253
+ stdtype = stdtype(@type)
254
+
255
+ # Handle stdtypes that are specified as regex in parameter
256
+ if (!stdtype && @type =~ %r"\A:/([^/]+)/\Z" )
257
+ stdtype = "#$1"
258
+ end
259
+
260
+ if stdtype.nil?
261
+ raise "Error: bad type in Getopt::Declare parameter variable specification near '<#{@name}#{@type}>'\nValid types are:\n" + @@stdtype.keys.inspect
262
+ end
263
+
264
+ stdtype = stdtype.dup # make a copy, as we'll change it in place
265
+ stdtype.gsub!(/\%D/,"(?:#{trailing}\\d)")
266
+ stdtype.gsub!(/\%T/,trailing)
267
+ unless ( stdtype.sub!("\%F","") )
268
+ stdtype = Getopt::Declare::Arg::negflagpat + stdtype
269
+ end
270
+ return "(?:#{stdtype})"
271
+ end
272
+
273
+ # Return string with code to process parameter
274
+ def code(*t)
275
+ if t[0]
276
+ pos1 = t[0].to_s
277
+ else
278
+ pos1 = '0'
279
+ end
280
+
281
+ c = conversion
282
+ c = "\n _VAL_ = _VAL_#{c} if _VAL_" if c
283
+
284
+ code = <<-EOS
285
+ _VAR_ = %q|<#{@name}>|
286
+ _VAL_ = @@m[#{pos1}]
287
+ _VAL_.tr!("\\0"," ") if _VAL_#{c}
288
+ EOS
289
+
290
+ actions = Getopt::Declare::ScalarArg::stdactions(@type)
291
+
292
+ for i in actions
293
+ next if i.nil?
294
+ # i.sub!(/(\s*\{)/, '\1 module '+t[1])
295
+ code << "
296
+ begin
297
+ #{i}
298
+ end
299
+ "
300
+ end
301
+
302
+ code << " #{@name} = _VAL_\n"
303
+ end
304
+
305
+ # Based on parameter type, default conversion to apply
306
+ def conversion
307
+ pat = @@stdtype[@type] ? @@stdtype[@type]['pattern'] : ''
308
+ [ @type, pat ].each { |t|
309
+ case t
310
+ when /^\:0?(\+)?i$/
311
+ return '.to_i'
312
+ when /^\:0?(\+)?n$/
313
+ return '.to_f'
314
+ end
315
+ }
316
+ return nil
317
+ end
318
+
319
+ # Return string with code to cache argument in Getopt::Declare's cache
320
+ def cachecode(ownerflag, itemcount)
321
+ if itemcount > 1
322
+ " @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
323
+ else
324
+ " @cache['#{ownerflag}'] = #{@name}\n"
325
+ end
326
+ end
327
+
328
+ # Helps build regex that matches parameters of flags
329
+ def trailer
330
+ nil # MEANS TRAILING PARAMETER VARIABLE (in Perl,was '')
331
+ end
332
+
333
+ # Helps build regex that matches parameters of flags
334
+ # Wraps parameter passed for #$1, etc. matching
335
+ def ows(g)
336
+ return '[\s|\0]*(' + g + ')' unless @nows
337
+ '('+ g +')'
338
+ end
339
+
340
+ end # ScalarArg
341
+
342
+
343
+ # Class used to handle array arguments
344
+ class ArrayArg < ScalarArg
345
+
346
+ # Create regexp to match array
347
+ def matcher(g)
348
+ suffix = !g.nil? ? '([\s\0]+)' : ''
349
+ scalar = super # contains regex to match a scalar element
350
+ # we match one obligatory element, and one or more optionals ')*'
351
+ return scalar + '(?:[\s\0]+' + scalar + ')*' + suffix
352
+ end
353
+
354
+ # Return string with code to process array parameter
355
+ def code(*t)
356
+
357
+ if t[0]
358
+ pos1 = t[0].to_s
359
+ else
360
+ pos1 = '0'
361
+ end
362
+
363
+ code = <<-EOS
364
+ _VAR_ = %q|<#{@name}>|
365
+ _VAL_ = nil
366
+ #{@name} = (@@m[#{pos1}]||'').split(' ').map { |i|
367
+ i.tr("\\0", " ") }
368
+ EOS
369
+
370
+ # Handle conversion to proper type
371
+ c = conversion
372
+ if c
373
+ code << " #{@name}.map! { |i| i#{c} }\n"
374
+ end
375
+
376
+ actions = Getopt::Declare::ScalarArg::stdactions(@type)
377
+ if actions.size > 0
378
+ code << " for _VAL_ in #{@name}\n"
379
+ for i in actions
380
+ code << " #{i}\n"
381
+ end
382
+ code << " end\n\n"
383
+ end
384
+ return code
385
+ end
386
+
387
+ # Return string with code to cache array in Getopt::Declare's cache
388
+ def cachecode(ownerflag, itemcount)
389
+ if itemcount > 1
390
+ " @cache['#{ownerflag}']['<#{@name}>'] = [] unless @cache['#{ownerflag}']['<#{@name}>']
391
+ @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
392
+ else
393
+ " @cache['#{ownerflag}'] = #{@name}\n"
394
+ end
395
+ end
396
+ end # ArrayArg
397
+
398
+
399
+ # Class used to handle punctuations (., -, etc.)
400
+ class Punctuator
401
+
402
+ # Constructor
403
+ def initialize(text, nows)
404
+ @text = text
405
+ @nows = nows
406
+ end
407
+
408
+ # Return regex that matches this punctuation
409
+ def matcher(g)
410
+ Arg::negflagpat + Regexp::quote(@text)
411
+ end
412
+
413
+ # Return string with code to process punctuation
414
+ def code(*t)
415
+
416
+ if t[0]
417
+ pos1 = t[0].to_s
418
+ else
419
+ pos1 = '0'
420
+ end
421
+ " if @@m[#{pos1}] && !@@m[#{pos1}].empty?
422
+ _PUNCT_['#{@text}'] = @@m[#{pos1}]
423
+ end
424
+ "
425
+ end
426
+
427
+ # Return string with code to cache punctuation in Getopt::Declare's cache
428
+ def cachecode(ownerflag, itemcount)
429
+ if itemcount > 1
430
+ " @cache['#{ownerflag}']['#{@text}'] = _PUNCT_['#{@text}']\n"
431
+ else
432
+ " unless @cache['#{ownerflag}']\n" +
433
+ " @cache['#{ownerflag}'] = _PUNCT_['#{@text}'] || 1\n" +
434
+ " end\n"
435
+ end
436
+ end
437
+
438
+ # Helps build regex that matches parameters of flags
439
+ def trailer
440
+ @text
441
+ end
442
+
443
+ # Helps build regex that matches parameters of flags
444
+ # Wraps parameter passed for #$1, etc. matching
445
+ def ows(g)
446
+ return '[\s\0]*(' + g + ')' unless @nows
447
+ '(' + g + ')'
448
+ end #ows
449
+
450
+ end # Punctuator
451
+
452
+
453
+ # Class used to handle other arguments (flags, etc)
454
+ class Arg
455
+
456
+ @@nextid = 0
457
+
458
+
459
+ Helpcmd = %w( -help --help -Help --Help -HELP --HELP -h -H )
460
+
461
+ @@helpcmdH = {}
462
+ for i in Helpcmd; @@helpcmdH[i] = 1; end
463
+
464
+ def Arg.besthelp
465
+ for i in Helpcmd; return i if @@helpcmdH[i]; end
466
+ end
467
+
468
+ # Create regex of help flags based on help shortcuts left
469
+ def Arg.helppat
470
+ @@helpcmdH.keys.join('|')
471
+ end
472
+
473
+
474
+ Versioncmd = %w( -version --version -Version --Version
475
+ -VERSION --VERSION -v -V )
476
+ @@versioncmdH = {}
477
+ for i in Versioncmd; @@versioncmdH[i] = 1; end
478
+
479
+ def Arg.bestversion
480
+ for i in Versioncmd; return i if @@versioncmdH[i]; end
481
+ end
482
+
483
+ # Create regex of version flags based on help shortcuts left
484
+ def Arg.versionpat
485
+ @@versioncmdH.keys.join('|')
486
+ end
487
+
488
+ @@flags = []
489
+ @@posflagpat = nil
490
+ @@negflagpat = nil
491
+
492
+ def Arg.clear
493
+ @@flags = []
494
+ @@nextid = 0
495
+ @@posflagpat = nil
496
+ @@negflagpath = nil
497
+ end
498
+
499
+ # Return string with regex that avoids all flags in declaration
500
+ def Arg.negflagpat(*t)
501
+ if !@@negflagpat && @@flags
502
+ @@negflagpat = ( @@flags.map { |i|
503
+ "(?!" + Regexp::quote(i) + ")" } ).join('')
504
+ else
505
+ @@negflagpat
506
+ end
507
+ end
508
+
509
+ # Return string with regex that matches any of the flags in declaration
510
+ def Arg.posflagpat(*t)
511
+ if !@@posflagpat && @@flags
512
+ @@posflagpat = '(?:' + ( @@flags.map { |i|
513
+ Regexp::quote(i) } ).join('|') + ')'
514
+ else
515
+ @@posflagpat
516
+ end
517
+ end
518
+
519
+ attr_accessor :flag, :args, :actions, :ditto, :nocase
520
+ attr_accessor :required, :id, :repeatable, :desc
521
+ attr_writer :requires
522
+
523
+
524
+ #
525
+ def _enfound(original)
526
+ expr = original.gsub(/((?:&&|\|\|)?\s*(?:[!(]\s*)*)([^ \t\n|&\)]+)/x,
527
+ '\1_FOUND_[\'\2\']')
528
+
529
+ if !valid_syntax?( expr )
530
+ raise "Error: bad condition in [requires: #{original}]\n"
531
+ end
532
+ expr
533
+ end
534
+
535
+ def requires
536
+ return nil unless @requires
537
+ _enfound(@requires)
538
+ end
539
+
540
+ # Constructor
541
+ def initialize(spec, desc, dittoflag)
542
+ first = 1
543
+
544
+
545
+ @@nextid += 1
546
+ @flag = ''
547
+ @foundid = nil
548
+ @args = []
549
+ @actions = []
550
+ @ditto = dittoflag
551
+ @required = false
552
+ @requires = nil
553
+ @id = @@nextid
554
+ @desc = spec.dup
555
+ @items = 0
556
+ @nocase = false
557
+
558
+ @desc.sub!(/\A\s*(.*?)\s*\Z/,'\1')
559
+
560
+ while spec && spec != ''
561
+ begin
562
+
563
+ # OPTIONAL
564
+ if spec.sub!( /\A(\s*)\[/, '\1' )
565
+ @args.push( StartOpt.new )
566
+ next
567
+ elsif spec.sub!(/\A\s*\]/,"")
568
+ @args.push( EndOpt.new )
569
+ next
570
+ end
571
+
572
+ # ARG
573
+
574
+ se = DelimScanner::new( spec )
575
+ tmp = se.scanBracketed('<>')
576
+
577
+ arg = nows = nil
578
+ arg, spec, nows = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp
579
+
580
+
581
+ if arg
582
+ arg =~ /\A(\s*)(<)([a-zA-Z]\w*)(:[^>]+|)>/ or
583
+ raise "Error: bad Getopt::Declare parameter variable specification near '#{arg}'\n"
584
+
585
+ # NAME,TYPE,NOW
586
+ details = [ "#$3", "#$4", !first && !(nows.length>0) ]
587
+
588
+ if spec && spec.sub!( /\A\.\.\./, "") # ARRAY ARG
589
+ @args.push( ArrayArg.new(*details) )
590
+ else # SCALAR ARG
591
+ @args.push( ScalarArg.new(*details) )
592
+ end
593
+ @items += 1
594
+ next
595
+
596
+ # PUNCTUATION
597
+ elsif spec.sub!( /\A(\s*)((\\.|[^\] \t\n\[<])+)/, '' )
598
+ ows, punct = $1, $2
599
+ punct.gsub!( /\\(?!\\)(.)/, '\1' )
600
+
601
+ if first
602
+ spec =~ /\A(\S+)/
603
+ @foundid = "#{punct}#{$1}"
604
+ @flag = punct
605
+ @@flags.push( punct )
606
+ else
607
+ @args.push( Punctuator.new(punct, !(ows.size > 0)) )
608
+ @items += 1
609
+ end
610
+
611
+ else
612
+ break
613
+ end # if arg/spec.sub
614
+ ensure
615
+ first = nil
616
+ end
617
+ end # while
618
+
619
+
620
+ @@helpcmdH.delete(@flag) if @@helpcmdH.key?(@flag)
621
+ @@versioncmdH.delete(@flag) if @@versioncmdH.key?(@flag)
622
+ end # initialize
623
+
624
+
625
+
626
+ # Return String with code to parse this argument (ie. flag)
627
+ def code(*t)
628
+ owner = t[0]
629
+ mod = t[1]
630
+
631
+
632
+ code = "\n"
633
+ flag = @flag
634
+ clump = owner.clump
635
+ i = 0
636
+ nocasei = ((Getopt::Declare::nocase || @nocase) ? 'i' : '')
637
+
638
+ code << " catch(:paramout) do\n"
639
+ code += !@repeatable? " while !_FOUND_['" + self.foundid + "']" :
640
+ " while true"
641
+ if (flag && (clump==1 && flag !~ /\A[^a-z0-9]+[a-z0-9]\Z/i ||
642
+ (clump<3 && @args.size > 0 )))
643
+ code << ' && !_lastprefix'
644
+ end
645
+
646
+ code << '
647
+ begin
648
+ catch(:param) do
649
+ _pos = _nextpos if _args
650
+ _PUNCT_ = {}
651
+ '
652
+
653
+ if flag != ''
654
+ # This boundary is to handle -- option, so that if user uses
655
+ # --foo and --foo is not a flag, it does not become
656
+ # -- and unused: 'foo', but an error saying flag '--foo' not defined.
657
+ boundary = ''
658
+ boundary = '(\s+|\Z)' if flag =~ /^(--|-|\+|\+\+)$/
659
+
660
+ code << '
661
+ _args && _pos = gindex( _args, /\G[\s|\0]*' +
662
+ Regexp::quote(flag) + boundary + '/' + nocasei + ", _pos) or throw(:paramout)
663
+ unless @_errormsg
664
+ @_errormsg = %q|incorrect specification of '" + flag + "' parameter|
665
+ end
666
+ "
667
+ elsif ( ScalarArg::stdtype(@args[0].type)||'') !~ /\%F/
668
+ code << "\n throw(:paramout) if @_errormsg\n"
669
+ end
670
+
671
+
672
+ code << "\n _PARAM_ = '" + self.name + "'\n"
673
+
674
+
675
+ trailer = []
676
+ i = @args.size-1
677
+ while i > 0
678
+ trailer[i-1] = @args[i].trailer
679
+ trailer[i-1] = trailer[i] unless trailer[i-1]
680
+ i -= 1
681
+ end # while i
682
+
683
+ if @args
684
+ code << "\n"+' _args && _pos = gindex( _args, /\G'
685
+
686
+ @args.each_with_index { |arg, i|
687
+ code << arg.ows(arg.matcher(trailer[i]))
688
+ }
689
+
690
+ code << '/x' + nocasei + ", _pos ) or throw(:paramout)\n"
691
+ end # if @args
692
+
693
+ @args.each_with_index { |arg, i|
694
+ code << arg.code(i,mod) #, $flag ????
695
+ }
696
+
697
+ if flag
698
+ mutexlist = owner.mutex[flag] ?
699
+ ( owner.mutex[flag].map {|i| "'#{i}'"} ).join(',') : ''
700
+
701
+ code << "
702
+ if _invalid.has_key?('#{flag}')
703
+ @_errormsg = %q|parameter '#{flag}' not allowed with parameter '| + _invalid['#{flag}'] + %q|'|
704
+ throw(:paramout)
705
+ else
706
+ for i in [#{mutexlist}]
707
+ _invalid[i] = '#{flag}'
708
+ end
709
+ end #if/then
710
+
711
+ "
712
+ end
713
+
714
+
715
+
716
+ for action in @actions
717
+ #action.sub!( /(\s*\{)/, '\1 module '+mod ) # @TODO
718
+ code << "\n " + action + "\n"
719
+ end
720
+
721
+ if flag && @items==0
722
+ code << "\n @cache['#{flag}'] = '#{flag}'\n"
723
+ if @ditto
724
+ code << "\n @cache['#{@ditto.flag}'] = '#{flag}'\n"
725
+ end
726
+ end
727
+
728
+ if @items > 1
729
+ code << " @cache['#{self.name}'] = {} unless @cache['#{self.name}'].kind_of?(Hash)\n"
730
+ if @ditto
731
+ code << "\n @cache['#{@ditto.name}'] = {} unless @cache['#{@ditto.name}'].kind_of?(Hash)\n"
732
+ end
733
+ end
734
+
735
+ for subarg in @args
736
+ code << subarg.cachecode(self.name,@items)
737
+ if ditto
738
+ code << subarg.cachecode(@ditto.name,@items)
739
+ end
740
+ end
741
+
742
+ if flag =~ /\A([^a-z0-9]+)/i
743
+ code << ' _lastprefix = "'+ Regexp::quote("#$1") + '"' + "\n"
744
+ else
745
+ code << " _lastprefix = nil\n"
746
+ end
747
+
748
+ code << "
749
+ _FOUND_['"+ self.foundid + "'] = 1
750
+ throw :arg if _pos > 0
751
+ _nextpos = _args.size
752
+ throw :alldone
753
+ end # catch(:param)
754
+ end # begin
755
+ end # while
756
+ end # catch(:paramout)
757
+ "
758
+
759
+ code
760
+ end
761
+
762
+ # Return name of argument, which can be flag's name or variable's name
763
+ def name
764
+ return @flag unless @flag.empty?
765
+ for i in @args
766
+ return "<#{i.name}>" if i.respond_to?(:name)
767
+ end
768
+ raise "Unknown flag name for parameter #{self.desc}"
769
+ end
770
+
771
+ # Return foundid of argument, which can be flag's name or variable's name
772
+ def foundid
773
+ return @foundid || self.name
774
+ end
775
+
776
+ end # Arg
777
+
778
+
779
+ private
780
+
781
+ class << self
782
+ @nocase = false
783
+ attr_accessor :nocase
784
+ end
785
+
786
+ #
787
+ # This is an additional function added to the class to simulate Perl's
788
+ # pos() \G behavior and m///g
789
+ #
790
+ # It performs a regex match, and returns the last index position of the
791
+ # match or nil. On successive invocations, it allows doing regex matches
792
+ # NOT from the beginning of the string easily.
793
+ #
794
+ # Class Array @@m stores the list of matches, as #$1 and similar
795
+ # variables have short lifespan in ruby, unlike perl.
796
+ #
797
+ def gindex(str, re, pos)
798
+ @@m.clear()
799
+ if pos = str.index( re, pos )
800
+ l = $&.size # length of match
801
+ if l > 0
802
+ @@m[0] = "#$1"
803
+ @@m[1] = "#$2"
804
+ @@m[2] = "#$3"
805
+ @@m[3] = "#$4"
806
+ @@m[4] = "#$5"
807
+ @@m[5] = "#$6"
808
+ @@m[6] = "#$7"
809
+ @@m[7] = "#$8"
810
+ @@m[8] = "#$9"
811
+ pos += l
812
+ end
813
+ end
814
+ pos
815
+ end
816
+
817
+ # Given an array or hash, flatten them to a string
818
+ def flatten(val, nested = nil)
819
+ case val
820
+ when Array
821
+ return val.map{ |i| flatten(i,1) }.join(" ")
822
+ when Hash
823
+ return val.keys.map{ |i| nested ||
824
+ i =~ /^-/ ? [i, flatten(val[i],1)] :
825
+ [flatten(val[i],1)] }.join(" ")
826
+ else
827
+ return val
828
+ end
829
+ end
830
+
831
+ # Read the next line from stdin
832
+ def _get_nextline
833
+ $stdin.readline
834
+ end
835
+
836
+ # For each file provided and found, read it in
837
+ def _load_sources( _get_nextline, files )
838
+ text = ''
839
+ found = []
840
+
841
+ for i in files
842
+ begin
843
+ f = File.open(i,"r")
844
+ rescue
845
+ next
846
+ end
847
+
848
+ if f.tty?
849
+ found.push( '<STDIN>' )
850
+ _get_nextline = method(:_get_nextline)
851
+ else
852
+ found.push( i );
853
+ t = f.readlines.join(' ')
854
+ t.tr!('\t\n',' ')
855
+ text += t
856
+ end
857
+ end
858
+
859
+ return nil unless found.size > 0
860
+ text = $stdin.readline if text.empty?
861
+ return [text, found.join(' or ')]
862
+ end
863
+
864
+
865
+ # Check parameter description for special options
866
+ def _infer(desc, arg, mutex)
867
+ while desc.sub!(/\[\s*mutex:\s*(.*?)\]/i,"")
868
+ _mutex(mutex, "#$1".split(' '))
869
+ end
870
+
871
+ if desc =~ /\[\s*no\s*case\s*\]/i
872
+ if arg
873
+ arg.nocase = true
874
+ else
875
+ nocase = true
876
+ end
877
+ end
878
+
879
+ if !arg.nil?
880
+ if desc =~ /.*\[\s*excludes:\s*(.*?)\]/i
881
+ _exclude(mutex, arg.name, ("#$1".split(' ')))
882
+ end
883
+
884
+ if desc =~ /.*\[\s*requires:\s*(.*?)\]/i
885
+ arg.requires = "#$1"
886
+ end
887
+
888
+ arg.required = ( desc =~ /\[\s*required\s*\]/i )
889
+
890
+ arg.repeatable = ( desc =~ /\[\s*repeatable\s*\]/i )
891
+ end
892
+
893
+ _typedef(desc) while desc.sub!(/.*?\[\s*pvtype:\s*/,"")
894
+
895
+ end
896
+
897
+
898
+
899
+ # Extract a new type from the description and add it to the list
900
+ # of standard types
901
+ def _typedef(desc)
902
+ se = DelimScanner::new( desc )
903
+ tmp = se.scanQuotelike
904
+
905
+ name = nil
906
+ name, desc = tmp[:delimText], tmp[:suffix] if tmp
907
+
908
+ unless name
909
+ desc.sub!(/\A\s*([^\] \t\n]+)/,"") and name = "#$1"
910
+ end
911
+
912
+ raise "Error: bad type directive (missing type name): [pvtype: " +
913
+ desc[0,desc.index(']')||20] + "....\n" unless name
914
+
915
+ se = DelimScanner::new( desc )
916
+ tmp = se.scanQuotelike('\s*:?\s*')
917
+
918
+ # @TODO What is element 2 of extract_quotelike? :trail is a fake here
919
+ # pat,desc,ind = (extract_quotelike(desc,'\s*:?\s*'))[5,1,2]
920
+ pat = ind = nil
921
+ pat, desc, ind = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp
922
+ pat = pat[1..-2] if pat
923
+
924
+ unless pat
925
+ desc.sub!(/\A\s*(:?)\s*([^\] \t\n]+)/,"") and pat = "#$2" and ind = "#$1"
926
+ end
927
+
928
+ pat = '' unless pat
929
+
930
+
931
+ se = DelimScanner::new( desc )
932
+ action = se.extractCodeblock || ''
933
+
934
+ desc.sub!( Regexp::quote(action).to_re, '' )
935
+ action = action[1..-2]
936
+
937
+ raise "Error: bad type directive (expected closing ']' but found " +
938
+ "'#$1' instead): [pvtype: #{name} " + (pat ? "/#{pat}/" : '') +
939
+ " action:#{action} #$1#$2....\n" if desc =~ /\A\s*([^\] \t\n])(\S*)/
940
+
941
+
942
+ Getopt::Declare::ScalarArg::addtype(name,pat,action,ind=~/:/)
943
+ end
944
+
945
+ # Handle quote replacements for [ditto] flag
946
+ def _ditto(originalflag, originaldesc, extra)
947
+ if originaldesc =~ /\n.*\n/
948
+ originaldesc = "Same as #{originalflag} "
949
+ else
950
+ originaldesc.chomp
951
+ originaldesc.gsub!(/\S/,'"')
952
+ while originaldesc.gsub!(/"("+)"/,' \1 ')
953
+ end
954
+ originaldesc.gsub!(/""/,'" ')
955
+ end
956
+
957
+ "#{originaldesc}#{extra}\n"
958
+ end
959
+
960
+ # Check mutex conditions
961
+ def _mutex(mref, mutexlist)
962
+ for flag in mutexlist
963
+ mref[flag] = [] unless mref[flag]
964
+ for otherflag in mutexlist
965
+ next if flag == otherflag
966
+ mref[flag].push( otherflag )
967
+ end
968
+ end
969
+ end
970
+
971
+ # Check exclude conditions
972
+ def _exclude(mref, excluded, mutexlist)
973
+ for flag in mutexlist
974
+ unless flag == excluded
975
+ mref[flag] = [] unless mref[flag]
976
+ mref[excluded] = [] unless mref[excluded]
977
+ mref[excluded].push( flag )
978
+ mref[flag].push( excluded )
979
+ end
980
+ end
981
+ end
982
+
983
+ # Returns a regex to match a single argument line
984
+ def re_argument
985
+ /\A(.*?\S.*?#{@@separator})(.*?\n)/
986
+ end
987
+
988
+ # Returns a regex to keep matching a multi-line description
989
+ # for an argument.
990
+ def re_more_desc
991
+ /\A((?![ \t]*(\{|\n)|.*?\S.*?#{@@separator}.*?\S).*?\S.*\n)/
992
+ end
993
+
994
+ public
995
+
996
+ # Constructor
997
+ def initialize(*opts)
998
+ @cache = nil
999
+
1000
+ Getopt::Declare::Arg::clear
1001
+
1002
+ # HANDLE SHORT-CIRCUITS
1003
+ return if opts.size==2 && (!opts[1] || opts[1] == '-SKIP')
1004
+
1005
+ grammar, source = opts
1006
+
1007
+ if grammar.nil?
1008
+ raise "Error: No grammar description provided."
1009
+ end
1010
+
1011
+ ### REMOVED PREDEF GRAMMAR AS IT WAS NOT DOCUMENTED NOR
1012
+ ### WORKING IN PERL'S Declare.pm VERSION.
1013
+
1014
+ # PRESERVE ESCAPED '['s
1015
+ grammar.gsub!(/\\\[/,"\255")
1016
+
1017
+ # MAKE SURE GRAMMAR ENDS WITH A NEWLINE.
1018
+ grammar.sub!(/([^\n])\Z/,'\1'+"\n")
1019
+
1020
+ @usage = grammar.dup
1021
+
1022
+ # SET-UP
1023
+ i = grammar
1024
+ _args = []
1025
+ _mutex = {}
1026
+ _strict = false
1027
+ _all_repeatable = false
1028
+ _lastdesc = nil
1029
+ arg = nil
1030
+ Getopt::Declare::nocase = false
1031
+ Getopt::Declare::ScalarArg::_reset_stdtype
1032
+
1033
+
1034
+ # CONSTRUCT GRAMMAR
1035
+ while i.length > 0
1036
+
1037
+ # COMMENT:
1038
+ i.sub!(/\A[ \t]*#.*\n/,"") and next
1039
+
1040
+
1041
+ # TYPE DIRECTIVE:
1042
+ se = DelimScanner::new( i )
1043
+
1044
+ if i =~ /\A\s*\[\s*pvtype:/
1045
+ _action = se.extractBracketed("[")
1046
+ if _action
1047
+ i.sub!( Regexp::quote( _action ).to_re, "" ) ### @GGA: added
1048
+ i.sub!(/\A[ \t]*\n/,"") ### @GGA: added
1049
+ _action.sub!(/.*?\[\s*pvtype:\s*/,"")
1050
+ _typedef(_action)
1051
+ next
1052
+ end # if
1053
+ end
1054
+
1055
+ # ACTION
1056
+ codeblockDelimiters = {
1057
+ '{' => '}',
1058
+ }
1059
+
1060
+ _action = se.extractCodeblock(codeblockDelimiters)
1061
+ if _action
1062
+ i.sub!( Regexp::quote(_action ).to_re, "" )
1063
+ i.sub!(/\A[ \t]*\n/,"")
1064
+ _action = _action[1..-2]
1065
+
1066
+ if !valid_syntax?( _action )
1067
+ raise "Error: bad action in Getopt::Declare specification:" +
1068
+ "\n\n#{_action}\n\n\n"
1069
+ end
1070
+
1071
+ if _args.length == 0
1072
+ raise "Error: unattached action in Getopt::Declare specification:\n#{_action}\n" +
1073
+ "\t(did you forget the tab after the preceding parameter specification?)\n"
1074
+ end
1075
+
1076
+ _args.last.actions.push( _action )
1077
+ next
1078
+ elsif i =~ /\A(\s*[{].*)/
1079
+ raise "Error: incomplete action in Getopt::Declare specification:\n$1.....\n" +
1080
+ "\t(did you forget a closing '}'?)\n"
1081
+ end
1082
+
1083
+
1084
+ # ARG + DESC:
1085
+ if i.sub!(re_argument,"")
1086
+ spec = "#$1".strip
1087
+ desc = "#$2"
1088
+ _strict ||= desc =~ /\[\s*strict\s*\]/
1089
+
1090
+ while i.sub!(re_more_desc,"")
1091
+ desc += "#$1"
1092
+ end
1093
+
1094
+ ditto = nil
1095
+ if _lastdesc and desc.sub!(/\A\s*\[\s*ditto\s*\]/,_lastdesc)
1096
+ ditto = arg
1097
+ else
1098
+ _lastdesc = desc
1099
+ end
1100
+
1101
+ # Check for GNU spec line like: -d, --debug
1102
+ arg = nil
1103
+ if spec =~ /(-[\w_\d]+),\s+(--[\w_\d]+)(\s+.*)?/
1104
+ specs = ["#$1#$3", "#$2#$3"]
1105
+ specs.each { |spec|
1106
+ arg = Arg.new(spec,desc,ditto)
1107
+ _args.push( arg )
1108
+ _infer(desc, arg, _mutex)
1109
+ ditto = arg
1110
+ }
1111
+ else
1112
+ arg = Arg.new(spec,desc,ditto)
1113
+ _args.push( arg )
1114
+ _infer(desc, arg, _mutex)
1115
+ end
1116
+
1117
+
1118
+ next
1119
+ end
1120
+
1121
+ # OTHERWISE: DECORATION
1122
+ i.sub!(/((?:(?!\[\s*pvtype:).)*)(\n|(?=\[\s*pvtype:))/,"")
1123
+ decorator = "#$1"
1124
+ _strict ||= decorator =~ /\[\s*strict\s*\]/
1125
+ _infer(decorator, nil, _mutex)
1126
+
1127
+ _all_repeatable = true if decorator =~ /\[\s*repeatable\s*\]/
1128
+ @@debug = true if decorator =~ /\[\s*debug\s*\]/
1129
+
1130
+ end # while i.length
1131
+
1132
+
1133
+ _lastactions = nil
1134
+ for i in _args
1135
+ if _lastactions && i.ditto && i.actions.size == 0
1136
+ i.actions = _lastactions
1137
+ else
1138
+ _lastactions = i.actions
1139
+ end
1140
+
1141
+ if _all_repeatable
1142
+ i.repeatable = 1
1143
+ end
1144
+ end
1145
+
1146
+ # Sort flags based on criteria described in docs
1147
+ # Sadly, this cannot be reduced to sort_by
1148
+ _args = _args.sort() { |a,b|
1149
+ ( b.flag.length() <=> a.flag.length() ) or
1150
+ ( b.flag == a.flag and ( b.args.length() <=> a.args.length() ) ) or
1151
+ ( a.id <=> b.id )
1152
+ }
1153
+ # _args = _args.sort_by { |a| [a.flag.size, a.flag, a.args.size, a.id] }
1154
+
1155
+
1156
+ # Handle clump
1157
+ clump = (@usage =~ /\[\s*cluster:\s*none\s*\]/i) ? 0 :
1158
+ (@usage =~ /\[\s*cluster:\s*singles?\s*\]/i) ? 1 :
1159
+ (@usage =~ /\[\s*cluster:\s*flags?\s*\]/i) ? 2 :
1160
+ (@usage =~ /\[\s*cluster:\s*any\s*\]/i) ? 3 :
1161
+ (@usage =~ /\[\s*cluster:(.*)\s*\]/i) ? "r" : 3
1162
+ raise "Error: unknown clustering mode: [cluster:#$1]\n" if clump == "r"
1163
+
1164
+ # CONSTRUCT OBJECT ITSELF
1165
+ @args = _args
1166
+ @mutex = _mutex
1167
+ @helppat = Arg::helppat()
1168
+ @verspat = Arg::versionpat()
1169
+
1170
+ @strict = _strict
1171
+ @clump = clump
1172
+ @source = ''
1173
+ @tight = @usage =~ /\[\s*tight\s*\]/i
1174
+ @caller = caller()
1175
+
1176
+ # VESTIGAL DEBUGGING CODE
1177
+ if @@debug
1178
+ f = File.new(".CODE.rb","w") and
1179
+ f.puts( code() ) and
1180
+ f.close()
1181
+ end
1182
+
1183
+ # DO THE PARSE (IF APPROPRIATE)
1184
+ if opts.size == 2
1185
+ return nil unless parse(source)
1186
+ else
1187
+ return nil unless parse()
1188
+ end
1189
+
1190
+ end # initialize
1191
+
1192
+
1193
+ # Parse the parameter description and in some cases,
1194
+ # optionally eval it, too.
1195
+ def parse(*opts)
1196
+ source = opts[0]
1197
+ _args = nil
1198
+ _get_nextline = proc { nil }
1199
+
1200
+ if source
1201
+ case source
1202
+ when Method
1203
+ _get_nextline = source
1204
+ _args = _get_nextline.call(self)
1205
+ source = '[METHOD]'
1206
+ when Proc
1207
+ _get_nextline = source
1208
+ _args = _get_nextline.call(self)
1209
+ source = '[PROC]'
1210
+ when IO
1211
+ if source.fileno > 0 && source.tty?
1212
+ _get_nextline = method(:_get_nextline)
1213
+ _args = $stdin.readline
1214
+ source = '<STDIN>'
1215
+ else
1216
+ _args = source.readlines.join(' ')
1217
+ _args.tr!('\t\n',' ')
1218
+ end
1219
+ when :build, :skip
1220
+ return 0
1221
+ when Array
1222
+ if source.length() == 1 && !source[0] ||
1223
+ source[0] == "-BUILD" ||
1224
+ source[0] == "-SKIP"
1225
+ return 0
1226
+ elsif source.length() == 2 && source[0] == "-ARGV"
1227
+ if !source[1] or !source[1] === Array
1228
+ raise 'Error: parse(["-ARGV"]) not passed an array as second parameter.'
1229
+ end
1230
+ _args = source[1].map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1231
+ source = '<ARRAY>'
1232
+ elsif source.length() == 1 && source[0] == "-STDIN"
1233
+ _get_nextline = method(:_get_nextline)
1234
+ _args = $stdin.readline
1235
+ source = '<STDIN>'
1236
+ elsif source.length() == 1 && source[0] == '-CONFIG'
1237
+ progname = "#{$0}rc"
1238
+ progname.sub!(%r#.*/#,'')
1239
+ home = ENV['HOME'] || ''
1240
+ _args, source = _load_sources( _get_nextline,
1241
+ [ home+"/.#{progname}",
1242
+ ".#{progname}" ] )
1243
+ else
1244
+ # Bunch of files to load passed to parse()
1245
+ _args, source = _load_sources( _get_nextline, source )
1246
+ end
1247
+ when String # else/case LITERAL STRING TO PARSE
1248
+ _args = source.dup
1249
+ source = source[0,7] + '...' if source && source.length() > 7
1250
+ source = "\"#{source[0..9]}\""
1251
+ else
1252
+ raise "Unknown source type for Getopt::Declare::parse"
1253
+ end # case
1254
+ return 0 unless _args
1255
+ source = " (in #{source})"
1256
+ else
1257
+ _args = ARGV.map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1258
+ source = ''
1259
+ end
1260
+
1261
+ @source = source
1262
+ begin
1263
+ err = eval( code(@caller) )
1264
+ if $@
1265
+ # oops, something wrong... exit
1266
+ puts "#{$!}: #{$@.inspect}"
1267
+ exit(1)
1268
+ end
1269
+ if !err
1270
+ exit(1)
1271
+ end
1272
+ rescue
1273
+ raise
1274
+ end
1275
+
1276
+
1277
+ true
1278
+ end
1279
+
1280
+ def type(*t)
1281
+ Getopt::Declare::ScalarArg::addtype(t)
1282
+ end
1283
+
1284
+ # Print out version information and maybe exit
1285
+ def version(*t)
1286
+ prog = "#{$0}"
1287
+ begin
1288
+ filedate = File.stat( prog ).mtime.localtime()
1289
+ rescue
1290
+ filedate = 'Unknown date'
1291
+ end
1292
+ prog.sub!(%r#.*/#,'')
1293
+ r = ''
1294
+ if defined?($VERSION)
1295
+ r << "\n#{prog}: version #{$VERSION} (#{filedate})\n\n"
1296
+ else
1297
+ r << "\n#{prog}: version dated #{filedate}\n\n"
1298
+ end
1299
+
1300
+ if t.empty?
1301
+ return r
1302
+ else
1303
+ puts r
1304
+ exit t[0]
1305
+ end
1306
+ end
1307
+
1308
+ # Print out usage information
1309
+ def usage(*opt)
1310
+
1311
+ t = @usage
1312
+
1313
+ lastflag = nil
1314
+ lastdesc = nil
1315
+ usage = ''
1316
+
1317
+ while t.length() > 0
1318
+
1319
+ # COMMENT:
1320
+ t.sub!(/\A[ \t]*#.*\n/,".") and next
1321
+
1322
+ # TYPE DIRECTIVE:
1323
+ se = DelimScanner::new( t )
1324
+
1325
+ if t =~ /\A\s*\[pvtype:/
1326
+ if action = se.extractBracketed("[")
1327
+ t.sub!(Regexp::quote( action ).to_re,'')
1328
+ t.sub!(/\A[ \t]*\n/,"")
1329
+ next
1330
+ end
1331
+ end
1332
+
1333
+ # ACTION
1334
+ codeblockDelimiters = {
1335
+ '{' => '}'
1336
+ }
1337
+ se = DelimScanner::new( t )
1338
+ if action = se.extractCodeblock(codeblockDelimiters)
1339
+ t.sub!(Regexp::quote( action ).to_re,'')
1340
+ t.sub!(/\A[ \t]*\n/,"")
1341
+ decfirst = 0 unless !decfirst.nil?
1342
+ next
1343
+ end
1344
+
1345
+
1346
+ # ARG + DESC:
1347
+ if t.sub!(re_argument,"")
1348
+ decfirst = 0 unless !decfirst.nil?
1349
+ spec = "#$1".expand_tabs!()
1350
+ desc = "#$2".expand_tabs!()
1351
+
1352
+ while t.gsub!(re_more_desc, '')
1353
+ desc += "#$1".expand_tabs!
1354
+ end
1355
+
1356
+ next if desc =~ /\[\s*undocumented\s*\]/i
1357
+
1358
+ uoff = 0
1359
+ spec.gsub!(/(<[a-zA-Z]\w*):([^>]+)>/e) { |i|
1360
+ uoff += 1 + "#$2".length() and "#$1>"
1361
+ }
1362
+ spec.gsub!(/\t/,"=")
1363
+
1364
+ ditto = desc =~ /\A\s*\[ditto\]/
1365
+ desc.gsub!(/^\s*\[.*?\]\s*\n/m,"")
1366
+ desc.gsub!(BracketDirectives,'')
1367
+ #desc.gsub!(/\[.*?\]/,"")
1368
+
1369
+
1370
+ if ditto
1371
+ desc = (lastdesc ? _ditto(lastflag,lastdesc,desc) : "" )
1372
+ elsif desc =~ /\A\s*\Z/
1373
+ next
1374
+ else
1375
+ lastdesc = desc
1376
+ end
1377
+
1378
+ spec =~ /\A\s*(\S+)/ and lastflag = "#$1"
1379
+
1380
+ desc.sub!(/\s+\Z/, "\n")
1381
+ usage += spec + ' ' * uoff + desc
1382
+ next
1383
+ end
1384
+
1385
+
1386
+
1387
+ # OTHERWISE, DECORATION
1388
+ if t.sub!(/((?:(?!\[pvtype:).)*)(\n|(?=\[pvtype:))/,"")
1389
+ desc = "#$1"+("#$2"||'')
1390
+ #desc.gsub!(/^(\s*\[.*?\])+\s*\n/m,'')
1391
+ #desc.gsub!(/\[.*?\]/,'') # eliminates anything in brackets
1392
+ if @tight || desc !~ /\A\s*\Z/
1393
+ desc.gsub!(BracketDirectives,'')
1394
+ next if desc =~ /\A\s*\Z/
1395
+ end
1396
+ decfirst = 1 unless !decfirst.nil? or desc =~ /\A\s*\Z/
1397
+ usage += desc
1398
+ end
1399
+
1400
+ end #while
1401
+
1402
+ required = ''
1403
+
1404
+ for arg in @args
1405
+ required += ' ' + arg.desc + ' ' if arg.required
1406
+ end
1407
+
1408
+ usage.gsub!(/\255/,"[/") # REINSTATE ESCAPED '['s
1409
+
1410
+ required.gsub!(/<([a-zA-Z]\w*):[^>]+>/,'<\1>')
1411
+ required.rstrip!
1412
+
1413
+ helpcmd = Getopt::Declare::Arg::besthelp
1414
+ versioncmd = Getopt::Declare::Arg::bestversion
1415
+
1416
+
1417
+ header = ''
1418
+ unless @source.nil?
1419
+ header << version()
1420
+ prog = "#{$0}"
1421
+ prog.sub!(%r#.*/#,'')
1422
+ header << "Usage: #{prog} [options]#{required}\n"
1423
+ header << " #{prog} #{helpcmd}\n" if helpcmd
1424
+ header << " #{prog} #{versioncmd}\n" if versioncmd
1425
+ header << "\n" unless decfirst && decfirst == 1 && usage =~ /\A[ \t]*\n/
1426
+ end
1427
+
1428
+ header << "Options:\n" unless decfirst && decfirst == 1
1429
+
1430
+ usage.sub!(/[\s\n]+$/, '')
1431
+
1432
+ if opt.empty?
1433
+ return header + usage + "\n"
1434
+ end
1435
+
1436
+ pager = $stdout
1437
+ #begin
1438
+ # eval('require "IO/Pager";')
1439
+ # pager = IO::Pager.new()
1440
+ #rescue
1441
+ #end
1442
+
1443
+ #usage.sub!(/\A[\s\n]+/m, '')
1444
+ pager.puts "#{header}#{usage}"
1445
+ exit(opt[0]) if opt[0]
1446
+ end
1447
+
1448
+ attr_accessor :unused
1449
+
1450
+
1451
+ # Return list of used parameters (after parsing)
1452
+ def used
1453
+ used = @cache.keys
1454
+ return used.join(' ')
1455
+ end
1456
+
1457
+ @@m = []
1458
+
1459
+ # Main method to generate code to be evaluated for parsing.
1460
+ def code(*t)
1461
+ package = t[0] || ''
1462
+ code = %q%
1463
+
1464
+
1465
+ @_deferred = []
1466
+ @_errormsg = nil
1467
+ @_finished = nil
1468
+
1469
+ begin
1470
+
1471
+ begin
1472
+ undef :defer
1473
+ undef :reject
1474
+ undef :finish
1475
+ rescue
1476
+ end
1477
+
1478
+ def defer(&i)
1479
+ @_deferred.push( i )
1480
+ end
1481
+
1482
+ def reject(*i)
1483
+ if !i || i[0]
1484
+ @_errormsg = i[1] if i[1]
1485
+ throw :paramout
1486
+ end
1487
+ end
1488
+
1489
+ def finish(*i)
1490
+ if i.size
1491
+ @_finished = i
1492
+ else
1493
+ @_finished = true
1494
+ end
1495
+ end
1496
+
1497
+ @unused = []
1498
+ @cache = {}
1499
+ _FOUND_ = {}
1500
+ _errors = 0
1501
+ _invalid = {}
1502
+ _lastprefix = nil
1503
+
1504
+ _pos = 0 # current position to match from
1505
+ _nextpos = 0 # next position to match from
1506
+
1507
+ catch(:alldone) do
1508
+ while !@_finished
1509
+ begin
1510
+ catch(:arg) do
1511
+ @_errormsg = nil
1512
+
1513
+ # This is used for clustering of flags
1514
+ while _lastprefix
1515
+ substr = _args[_nextpos..-1]
1516
+ substr =~ /^(?!\s|\0|\Z)% +
1517
+ Getopt::Declare::Arg::negflagpat() + %q%/ or
1518
+ begin
1519
+ _lastprefix=nil
1520
+ break
1521
+ end
1522
+ "#{_lastprefix}#{substr}" =~ /^(% +
1523
+ Getopt::Declare::Arg::posflagpat() + %q%)/ or
1524
+ begin
1525
+ _lastprefix=nil
1526
+ break
1527
+ end
1528
+ _args = _args[0.._nextpos-1] + _lastprefix + _args[_nextpos..-1]
1529
+ break
1530
+ end # while _lastprefix
1531
+
1532
+ % + '' + %q%
1533
+ _pos = _nextpos if _args
1534
+
1535
+ usage(0) if _args && gindex(_args,/\G(% + @helppat + %q%)(\s|\0|\Z)/,_pos)
1536
+ version(0) if _args && _args =~ /\G(% + @verspat + %q%)(\s|\0|\Z)/
1537
+ %
1538
+
1539
+ for arg in @args
1540
+ code << arg.code(self,package)
1541
+ end
1542
+
1543
+ code << %q%
1544
+
1545
+ if _lastprefix
1546
+ _pos = _nextpos + _lastprefix.length()
1547
+ _lastprefix = nil
1548
+ next
1549
+ end
1550
+
1551
+ _pos = _nextpos
1552
+
1553
+ _args && _pos = gindex( _args, /\G[\s|\0]*(\S+)/, _pos ) or throw(:alldone)
1554
+
1555
+ if @_errormsg
1556
+ $stderr.puts( "Error#{source}: #{@_errormsg}\n" )
1557
+ else
1558
+ @unused.push( @@m[0] )
1559
+ end
1560
+
1561
+ _errors += 1 if @_errormsg
1562
+
1563
+ end # catch(:arg)
1564
+
1565
+ ensure # begin
1566
+ _pos = 0 if _pos.nil?
1567
+ _nextpos = _pos if _args
1568
+ if _args and _args.index( /\G(\s|\0)*\Z/, _pos )
1569
+ _args = _get_nextline.call(self) if !@_finished
1570
+ throw(:alldone) unless _args
1571
+ _pos = _nextpos = 0
1572
+ _lastprefix = ''
1573
+ end # if
1574
+ end # begin/ensure
1575
+ end # while @_finished
1576
+ end # catch(:alldone)
1577
+ end # begin
1578
+
1579
+ %
1580
+
1581
+
1582
+ ################################
1583
+ # Check for required arguments #
1584
+ ################################
1585
+ for arg in @args
1586
+ next unless arg.required
1587
+
1588
+ code << %q%unless _FOUND_['% + arg.name + %q%'] %
1589
+
1590
+ if @mutex[arg.name]
1591
+ for m in @mutex[arg.name]
1592
+ code << %q# or _FOUND_['# + m + %q#']#
1593
+ end
1594
+ end
1595
+
1596
+ code << %q%
1597
+ $stderr.puts "Error#{@source}: required parameter '% + arg.name + %q%' not found."
1598
+ _errors += 1
1599
+ end
1600
+ %
1601
+
1602
+ end
1603
+
1604
+ ########################################
1605
+ # Check for arguments requiring others #
1606
+ ########################################
1607
+
1608
+ for arg in @args
1609
+ next unless arg.requires
1610
+
1611
+ code << %q%
1612
+ if _FOUND_['% + arg.name + %q%'] && !(% + arg.requires +
1613
+ %q%)
1614
+ $stderr.puts "Error#{@source}: parameter '% + arg.name + %q%' can only be specified with '% + arg.requires + %q%'"
1615
+ _errors += 1
1616
+ end
1617
+ %
1618
+ end
1619
+
1620
+ code << %q%
1621
+ #################### Add unused arguments
1622
+ if _args && _nextpos > 0 && _args.length() > 0
1623
+ @unused.replace( @unused + _args[_nextpos..-1].split(' ') )
1624
+ end
1625
+
1626
+ for i in @unused
1627
+ i.tr!( "\0", " " )
1628
+ end
1629
+
1630
+ %
1631
+
1632
+ if @strict
1633
+ code << %q%
1634
+ #################### Handle strict flag
1635
+ unless _nextpos < ( _args ? _args.length : 0 )
1636
+ for i in @unused
1637
+ $stderr.puts "Error#{@source}: unrecognizable argument ('#{i}')"
1638
+ _errors += 1
1639
+ end
1640
+ end
1641
+ %
1642
+ end
1643
+
1644
+ code << %q%
1645
+ #################### Print help hint
1646
+ if _errors > 0 && !@source.nil?
1647
+ $stderr.puts "\n(try '#$0 % + Getopt::Declare::Arg::besthelp + %q%' for more information)"
1648
+ end
1649
+
1650
+ ## cannot just assign unused to ARGV in ruby
1651
+ unless @source != ''
1652
+ ARGV.clear
1653
+ @unused.map { |i| ARGV.push(i) }
1654
+ end
1655
+
1656
+ unless _errors > 0
1657
+ for i in @_deferred
1658
+ begin
1659
+ i.call
1660
+ rescue => e
1661
+ STDERR.puts "Action in Getopt::Declare specification produced:\n#{e}"
1662
+ _errors += 1
1663
+ end
1664
+ end
1665
+ end
1666
+
1667
+ !(_errors>0) # return true or false (false for errors)
1668
+
1669
+ %
1670
+ return code
1671
+ end
1672
+
1673
+
1674
+ # Inspect cache (not the declare object)
1675
+ def inspect
1676
+ return nil if !@cache
1677
+ t = ''
1678
+
1679
+ @cache.each { |a,b|
1680
+ t << a + " => "
1681
+ case b
1682
+ when Hash
1683
+ t << "{"
1684
+ i = []
1685
+ b.each { |c,d|
1686
+ i.push( " '#{c}' => " + d.inspect )
1687
+ }
1688
+ t << i.join(',')
1689
+ t << " }"
1690
+ else
1691
+ t << b.inspect
1692
+ end
1693
+ t << "\n"
1694
+ }
1695
+ t << "Unused: " + unused.join(', ')
1696
+ end
1697
+
1698
+ # Iterator for Getopt::Declare (travels thru all cache keys)
1699
+ def each(&t)
1700
+ @cache.each(&t)
1701
+ end
1702
+
1703
+ # Operator to easily create new value in of Getopt::Declare
1704
+ def []=(name,val)
1705
+ @cache = {} unless @cache
1706
+ @cache[name] = val
1707
+ end
1708
+
1709
+ # Operator to easily return cache of Getopt::Declare
1710
+ def [](name)
1711
+ if @cache
1712
+ return @cache[name]
1713
+ else
1714
+ return nil
1715
+ end
1716
+ end
1717
+
1718
+ # Operator to return number of flags set
1719
+ def size
1720
+ return 0 unless @cache
1721
+ return @cache.keys.size
1722
+ end
1723
+
1724
+ attr :mutex
1725
+ attr :helppat
1726
+ attr :verspat
1727
+ attr :strict
1728
+ attr :clump
1729
+ attr :source
1730
+
1731
+ end # class Declare
1732
+
1733
+ end # module Getopt
1734
+
1735
+
1736
+
1737
+
1738
+ __END__
1739
+