timetrap 1.8.5 → 1.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.travis.yml CHANGED
@@ -3,3 +3,4 @@ rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
5
  - 1.9.3
6
+ - 2.0.0
data/Gemfile CHANGED
@@ -3,7 +3,6 @@ source 'http://rubygems.org'
3
3
  gem 'sequel', ">= 3.9.0"
4
4
  gem 'sqlite3', "~> 1.3.3"
5
5
  gem 'chronic', ">= 0.6.4"
6
- gem 'getopt-declare', ">= 1.28"
7
6
  gem 'json', ">= 1.4.6"
8
7
  gem 'icalendar', "~>1.1.5"
9
8
  gem 'rake'
data/Rakefile CHANGED
@@ -42,7 +42,6 @@ begin
42
42
  s.add_dependency("sequel", ">= 3.9.0")
43
43
  s.add_dependency("sqlite3", "~> 1.3.3")
44
44
  s.add_dependency("chronic", ">= 0.6.4")
45
- s.add_dependency("getopt-declare", ">= 1.28")
46
45
  end
47
46
  rescue LoadError
48
47
  puts "Jeweler not available."
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
3
  :minor: 8
4
- :patch: 5
4
+ :patch: 6
@@ -0,0 +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.28 $
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 File.expand_path(File.join(File.dirname(__FILE__), "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.28'
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' => {
137
+ :pattern => '(?:%T(?:\S|\0))+',
138
+ :action => %q%
139
+ reject( (_VAL_.nil? || !test(?d, _VAL_) ),
140
+ "in parameter '#{_PARAM_}' (\"#{_VAL_}\" is not a directory)")%
141
+ },
142
+ ':if' => {
143
+ :pattern => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
144
+ :action => %q%
145
+ reject( (_VAL_.nil? || _VAL_ != "-" && !test(?r, _VAL_) ),
146
+ "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not readable)")%
147
+ },
148
+ ':of' => {
149
+ :pattern => '%F(?:%T(?:\S|\0))+(?=\s|\0|\z)',
150
+ :action => %q%
151
+ reject( (_VAL_.nil? || _VAL_ != "-" &&
152
+ test(?r, _VAL_) && !test(?w, _VAL_)),
153
+ "in parameter '#{_PARAM_}' (file \"#{_VAL_}\" is not writable)")%
154
+ },
155
+ '' => { :pattern => ':s', :ind => 1 },
156
+
157
+ ':+i' => {
158
+ :pattern => ':i',
159
+ :action => %q%reject( _VAL_ <= 0,
160
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an integer greater than zero)")%,
161
+ :ind => 1
162
+ },
163
+
164
+ ':+n' => {
165
+ :pattern => ':n',
166
+ :action => %q%reject( _VAL_ <= 0.0,
167
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be a number greater than zero)")%,
168
+ :ind => 1
169
+ },
170
+
171
+ ':0+i' => {
172
+ :pattern => ':i',
173
+ :action => %q%reject( _VAL_ < 0,
174
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive integer)")%,
175
+ :ind => 1
176
+ },
177
+
178
+ ':0+n' => {
179
+ :pattern => ':n',
180
+ :action => %q%reject( _VAL_ < 0,
181
+ "in parameter '#{_PARAM_}' (#{_VAL_} must be an positive number)")%,
182
+ :ind => 1
183
+ },
184
+ }
185
+
186
+ end # _reset_stdtype
187
+
188
+
189
+ # Given a standard type name, return the corresponding regex
190
+ # pattern or nil
191
+ def ScalarArg.stdtype(name)
192
+ seen = {}
193
+ while (!seen[name] && @@stdtype[name] && @@stdtype[name][:ind])
194
+ seen[name] = 1; name = @@stdtype[name][:pattern]
195
+ end
196
+
197
+ return nil if seen[name] || !@@stdtype[name]
198
+ @@stdtype[name][:pattern]
199
+ end
200
+
201
+ def stdtype(name)
202
+ ScalarArg.stdtype(name)
203
+ end
204
+
205
+
206
+ # Given the name of a type, return its corresponding action(s)
207
+ def ScalarArg.stdactions(name)
208
+ seen = {}
209
+ actions = []
210
+ while (!seen[name] && @@stdtype[name] && @@stdtype[name][:ind])
211
+ seen[name] = 1
212
+ if @@stdtype[name][:action]
213
+ actions.push( @@stdtype[name][:action] )
214
+ end
215
+ name = @@stdtype[name][:pattern]
216
+ end
217
+
218
+ if @@stdtype[name] && @@stdtype[name][:action]
219
+ actions.push( @@stdtype[name][:action] )
220
+ end
221
+
222
+ return actions
223
+ end
224
+
225
+ # Add a new (user defined) type to the standard types
226
+ def ScalarArg.addtype(abbrev, pattern, action, ref)
227
+
228
+ typeid = ":#{abbrev}"
229
+ unless (pattern =~ /\S/)
230
+ pattern = ":s"
231
+ ref = 1
232
+ end
233
+
234
+ @@stdtype[typeid] = {}
235
+ @@stdtype[typeid][:pattern] = "(?:#{pattern})" if pattern && !ref
236
+ @@stdtype[typeid][:pattern] = ":#{pattern}" if pattern && ref
237
+ @@stdtype[typeid][:action] = action if action
238
+ @@stdtype[typeid][:ind] = ref
239
+
240
+ end
241
+
242
+ attr :name
243
+ attr :type
244
+ attr :nows
245
+
246
+
247
+ # Constructor
248
+ def initialize(name, type, nows)
249
+ @name = name
250
+ @type = type
251
+ @nows = nows
252
+ end
253
+
254
+ # Create regexp to match parameter
255
+ def matcher(g)
256
+ trailing = g ? '(?!'+Regexp::quote(g)+')' : ''
257
+
258
+ # Find type in list of standard (and user) types
259
+ stdtype = stdtype(@type)
260
+
261
+ # Handle stdtypes that are specified as regex in parameter
262
+ if (!stdtype && @type =~ %r"\A:/([^/]+)/\Z" )
263
+ stdtype = "#$1"
264
+ end
265
+
266
+ if stdtype.nil?
267
+ raise "Error: bad type in Getopt::Declare parameter variable specification near '<#{@name}#{@type}>'\nValid types are:\n" + @@stdtype.keys.inspect
268
+ end
269
+
270
+ stdtype = stdtype.dup # make a copy, as we'll change it in place
271
+ stdtype.gsub!(/\%D/,"(?:#{trailing}\\d)")
272
+ stdtype.gsub!(/\%T/,trailing)
273
+ unless ( stdtype.sub!("\%F","") )
274
+ stdtype = Getopt::Declare::Arg::negflagpat + stdtype
275
+ end
276
+ return "(?:#{stdtype})"
277
+ end
278
+
279
+ # Return string with code to process parameter
280
+ def code(*t)
281
+ if t[0]
282
+ pos1 = t[0].to_s
283
+ else
284
+ pos1 = '0'
285
+ end
286
+
287
+ c = conversion
288
+ c = "\n _VAL_ = _VAL_#{c} if _VAL_" if c
289
+
290
+ code = <<-EOS
291
+ _VAR_ = %q|<#{@name}>|
292
+ _VAL_ = @@m[#{pos1}]
293
+ _VAL_.tr!("\\0"," ") if _VAL_#{c}
294
+ EOS
295
+
296
+ actions = Getopt::Declare::ScalarArg::stdactions(@type)
297
+
298
+ for i in actions
299
+ next if i.nil?
300
+ # i.sub!(/(\s*\{)/, '\1 module '+t[1])
301
+ code << "
302
+ begin
303
+ #{i}
304
+ end
305
+ "
306
+ end
307
+
308
+ code << " #{@name} = _VAL_\n"
309
+ end
310
+
311
+ # Based on parameter type, default conversion to apply
312
+ def conversion
313
+ pat = @@stdtype[@type] ? @@stdtype[@type][:pattern] : ''
314
+ [ @type, pat ].each { |t|
315
+ case t
316
+ when /^\:0?(\+)?i$/
317
+ return '.to_i'
318
+ when /^\:0?(\+)?n$/
319
+ return '.to_f'
320
+ end
321
+ }
322
+ return nil
323
+ end
324
+
325
+ # Return string with code to cache argument in Getopt::Declare's cache
326
+ def cachecode(ownerflag, itemcount)
327
+ if itemcount > 1
328
+ " @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
329
+ else
330
+ " @cache['#{ownerflag}'] = #{@name}\n"
331
+ end
332
+ end
333
+
334
+ # Helps build regex that matches parameters of flags
335
+ def trailer
336
+ nil # MEANS TRAILING PARAMETER VARIABLE (in Perl,was '')
337
+ end
338
+
339
+ # Helps build regex that matches parameters of flags
340
+ # Wraps parameter passed for #$1, etc. matching
341
+ def ows(g)
342
+ return '[\s|\0]*(' + g + ')' unless @nows
343
+ '('+ g +')'
344
+ end
345
+
346
+ end # ScalarArg
347
+
348
+
349
+ # Class used to handle array arguments
350
+ class ArrayArg < ScalarArg
351
+
352
+ # Create regexp to match array
353
+ def matcher(g)
354
+ suffix = !g.nil? ? '([\s\0]+)' : ''
355
+ scalar = super # contains regex to match a scalar element
356
+ # we match one obligatory element, and one or more optionals ')*'
357
+ return scalar + '(?:[\s\0]+' + scalar + ')*' + suffix
358
+ end
359
+
360
+ # Return string with code to process array parameter
361
+ def code(*t)
362
+
363
+ if t[0]
364
+ pos1 = t[0].to_s
365
+ else
366
+ pos1 = '0'
367
+ end
368
+
369
+ code = <<-EOS
370
+ _VAR_ = %q|<#{@name}>|
371
+ _VAL_ = nil
372
+ #{@name} = (@@m[#{pos1}]||'').split(' ').map { |i|
373
+ i.tr("\\0", " ") }
374
+ EOS
375
+
376
+ # Handle conversion to proper type
377
+ c = conversion
378
+ if c
379
+ code << " #{@name}.map! { |i| i#{c} }\n"
380
+ end
381
+
382
+ actions = Getopt::Declare::ScalarArg::stdactions(@type)
383
+ if actions.size > 0
384
+ code << " for _VAL_ in #{@name}\n"
385
+ for i in actions
386
+ code << " #{i}\n"
387
+ end
388
+ code << " end\n\n"
389
+ end
390
+ return code
391
+ end
392
+
393
+ # Return string with code to cache array in Getopt::Declare's cache
394
+ def cachecode(ownerflag, itemcount)
395
+ if itemcount > 1
396
+ " @cache['#{ownerflag}']['<#{@name}>'] = [] unless @cache['#{ownerflag}']['<#{@name}>']
397
+ @cache['#{ownerflag}']['<#{@name}>'] = #{@name}\n"
398
+ else
399
+ " @cache['#{ownerflag}'] = #{@name}\n"
400
+ end
401
+ end
402
+ end # ArrayArg
403
+
404
+
405
+ # Class used to handle punctuations (., -, etc.)
406
+ class Punctuator
407
+
408
+ # Constructor
409
+ def initialize(text, nows)
410
+ @text = text
411
+ @nows = nows
412
+ end
413
+
414
+ # Return regex that matches this punctuation
415
+ def matcher(g)
416
+ Arg::negflagpat + Regexp::quote(@text)
417
+ end
418
+
419
+ # Return string with code to process punctuation
420
+ def code(*t)
421
+
422
+ if t[0]
423
+ pos1 = t[0].to_s
424
+ else
425
+ pos1 = '0'
426
+ end
427
+ " if @@m[#{pos1}] && !@@m[#{pos1}].empty?
428
+ _PUNCT_['#{@text}'] = @@m[#{pos1}]
429
+ end
430
+ "
431
+ end
432
+
433
+ # Return string with code to cache punctuation in Getopt::Declare's cache
434
+ def cachecode(ownerflag, itemcount)
435
+ if itemcount > 1
436
+ " @cache['#{ownerflag}']['#{@text}'] = _PUNCT_['#{@text}']\n"
437
+ else
438
+ " unless @cache['#{ownerflag}']\n" +
439
+ " @cache['#{ownerflag}'] = _PUNCT_['#{@text}'] || 1\n" +
440
+ " end\n"
441
+ end
442
+ end
443
+
444
+ # Helps build regex that matches parameters of flags
445
+ def trailer
446
+ @text
447
+ end
448
+
449
+ # Helps build regex that matches parameters of flags
450
+ # Wraps parameter passed for #$1, etc. matching
451
+ def ows(g)
452
+ return '[\s\0]*(' + g + ')' unless @nows
453
+ '(' + g + ')'
454
+ end #ows
455
+
456
+ end # Punctuator
457
+
458
+
459
+ # Class used to handle other arguments (flags, etc)
460
+ class Arg
461
+
462
+ @@nextid = 0
463
+
464
+
465
+ Helpcmd = %w( -help --help -Help --Help -HELP --HELP -h -H )
466
+
467
+ @@helpcmdH = {}
468
+ for i in Helpcmd; @@helpcmdH[i] = 1; end
469
+
470
+ def Arg.besthelp
471
+ for i in Helpcmd; return i if @@helpcmdH[i]; end
472
+ end
473
+
474
+ # Create regex of help flags based on help shortcuts left
475
+ def Arg.helppat
476
+ @@helpcmdH.keys.join('|')
477
+ end
478
+
479
+
480
+ Versioncmd = %w( -version --version -Version --Version
481
+ -VERSION --VERSION -v -V )
482
+ @@versioncmdH = {}
483
+ for i in Versioncmd; @@versioncmdH[i] = 1; end
484
+
485
+ def Arg.bestversion
486
+ for i in Versioncmd; return i if @@versioncmdH[i]; end
487
+ end
488
+
489
+ # Create regex of version flags based on help shortcuts left
490
+ def Arg.versionpat
491
+ @@versioncmdH.keys.join('|')
492
+ end
493
+
494
+ @@flags = []
495
+ @@posflagpat = nil
496
+ @@negflagpat = nil
497
+
498
+ def Arg.clear
499
+ @@flags = []
500
+ @@nextid = 0
501
+ @@posflagpat = nil
502
+ @@negflagpath = nil
503
+ end
504
+
505
+ # Return string with regex that avoids all flags in declaration
506
+ def Arg.negflagpat(*t)
507
+ if !@@negflagpat && @@flags
508
+ @@negflagpat = ( @@flags.map { |i|
509
+ "(?!" + Regexp::quote(i) + ")" } ).join('')
510
+ else
511
+ @@negflagpat
512
+ end
513
+ end
514
+
515
+ # Return string with regex that matches any of the flags in declaration
516
+ def Arg.posflagpat(*t)
517
+ if !@@posflagpat && @@flags
518
+ @@posflagpat = '(?:' + ( @@flags.map { |i|
519
+ Regexp::quote(i) } ).join('|') + ')'
520
+ else
521
+ @@posflagpat
522
+ end
523
+ end
524
+
525
+ attr_accessor :flag, :args, :actions, :ditto, :nocase
526
+ attr_accessor :required, :id, :repeatable, :desc
527
+ attr_accessor :requires
528
+
529
+
530
+ #
531
+ def found_requires
532
+ expr = @requires.gsub(/((?:&&|\|\|)?\s*(?:[!(]\s*)*)([^ \t\n|&\)]+)/x,
533
+ '\1_FOUND_[\'\2\']')
534
+
535
+ if !valid_syntax?( expr )
536
+ raise "Error: bad condition in [requires: #{original}]\n"
537
+ end
538
+ expr
539
+ end
540
+
541
+
542
+ # Constructor
543
+ def initialize(spec, desc, dittoflag)
544
+ first = 1
545
+
546
+
547
+ @@nextid += 1
548
+ @flag = ''
549
+ @foundid = nil
550
+ @args = []
551
+ @actions = []
552
+ @ditto = dittoflag
553
+ @required = false
554
+ @requires = nil
555
+ @id = @@nextid
556
+ @desc = spec.dup
557
+ @items = 0
558
+ @nocase = false
559
+
560
+ @desc.sub!(/\A\s*(.*?)\s*\Z/,'\1')
561
+
562
+ while spec && spec != ''
563
+ begin
564
+
565
+ # OPTIONAL
566
+ if spec.sub!( /\A(\s*)\[/, '\1' )
567
+ @args.push( StartOpt.new )
568
+ next
569
+ elsif spec.sub!(/\A\s*\]/,"")
570
+ @args.push( EndOpt.new )
571
+ next
572
+ end
573
+
574
+ # ARG
575
+
576
+ se = DelimScanner::new( spec )
577
+ tmp = se.scanBracketed('<>')
578
+
579
+ arg = nows = nil
580
+ arg, spec, nows = tmp[:match], tmp[:suffix], tmp[:prefix] if tmp
581
+
582
+
583
+ if arg
584
+ arg =~ /\A(\s*)(<)([a-zA-Z]\w*)(:[^>]+|)>/ or
585
+ raise "Error: bad Getopt::Declare parameter variable specification near '#{arg}'\n"
586
+
587
+ # NAME,TYPE,NOW
588
+ details = [ "#$3", "#$4", !first && !(nows.length>0) ]
589
+
590
+ if spec && spec.sub!( /\A\.\.\./, "") # ARRAY ARG
591
+ @args.push( ArrayArg.new(*details) )
592
+ else # SCALAR ARG
593
+ @args.push( ScalarArg.new(*details) )
594
+ end
595
+ @items += 1
596
+ next
597
+
598
+ # PUNCTUATION
599
+ elsif spec.sub!( /\A(\s*)((\\.|[^\] \t\n\[<])+)/, '' )
600
+ ows, punct = $1, $2
601
+ punct.gsub!( /\\(?!\\)(.)/, '\1' )
602
+
603
+ if first
604
+ spec =~ /\A(\S+)/
605
+ @foundid = "#{punct}#{$1}"
606
+ @flag = punct
607
+ @@flags.push( punct )
608
+ else
609
+ @args.push( Punctuator.new(punct, !(ows.size > 0)) )
610
+ @items += 1
611
+ end
612
+
613
+ else
614
+ break
615
+ end # if arg/spec.sub
616
+ ensure
617
+ first = nil
618
+ end
619
+ end # while
620
+
621
+ @@helpcmdH.delete(@flag) if @@helpcmdH.key?(@flag)
622
+ @@versioncmdH.delete(@flag) if @@versioncmdH.key?(@flag)
623
+ end # initialize
624
+
625
+
626
+
627
+ # Return String with code to parse this argument (ie. flag)
628
+ def code(*t)
629
+ owner = t[0]
630
+ mod = t[1]
631
+
632
+
633
+ code = "\n"
634
+ flag = @flag
635
+ clump = owner.clump
636
+ i = 0
637
+ nocasei = ((Getopt::Declare::nocase || @nocase) ? 'i' : '')
638
+
639
+ code << " catch(:paramout) do\n while "
640
+ code += !@repeatable? "!_FOUND_['" + self.foundid + "']" : "true"
641
+
642
+ if (flag && (clump==1 && flag !~ /\A[^a-z0-9]+[a-z0-9]\Z/i ||
643
+ (clump<3 && @args.size > 0 )))
644
+ code << ' and !_lastprefix'
645
+ end
646
+
647
+ code <<'
648
+ begin
649
+ catch(:param) do
650
+ _pos = _nextpos if _args
651
+ _PUNCT_ = {}
652
+ '
653
+
654
+ if flag != ''
655
+ # This boundary is to handle -- option, so that if user uses
656
+ # --foo and --foo is not a flag, it does not become
657
+ # -- and unused: 'foo', but an error saying flag '--foo' not defined.
658
+ boundary = ''
659
+ boundary = '(\s+|\Z)' if flag =~ /^(--|-|\+|\+\+)$/
660
+
661
+ code << '
662
+ _args && _pos = gindex( _args, /\G[\s|\0]*' +
663
+ Regexp::quote(flag) + boundary + '/' + nocasei + ", _pos) or throw(:paramout)
664
+ unless @_errormsg
665
+ @_errormsg = %q|incorrect specification of '" + flag + "' parameter|
666
+ end
667
+ "
668
+ elsif ( ScalarArg::stdtype(@args[0].type)||'') !~ /\%F/
669
+ code << "\n throw(:paramout) if @_errormsg\n"
670
+ end
671
+
672
+
673
+ code << "\n _PARAM_ = '" + self.name + "'\n"
674
+
675
+
676
+ trailer = []
677
+ i = @args.size-1
678
+ while i > 0
679
+ trailer[i-1] = @args[i].trailer
680
+ trailer[i-1] = trailer[i] unless trailer[i-1]
681
+ i -= 1
682
+ end # while i
683
+
684
+ if @args
685
+ code << "\n"+' _args && _pos = gindex( _args, /\G'
686
+
687
+ @args.each_with_index { |arg, i|
688
+ code << arg.ows(arg.matcher(trailer[i]))
689
+ }
690
+
691
+ code << '/x' + nocasei + ", _pos ) or throw(:paramout)\n"
692
+ end # if @args
693
+
694
+ @args.each_with_index { |arg, i|
695
+ code << arg.code(i,mod) #, $flag ????
696
+ }
697
+
698
+ if flag
699
+ mutexlist = owner.mutex[flag] ?
700
+ ( owner.mutex[flag].map {|i| "'#{i}'"} ).join(',') : ''
701
+
702
+ code << "
703
+ if _invalid.has_key?('#{flag}')
704
+ @_errormsg = %q|parameter '#{flag}' not allowed with parameter '| + _invalid['#{flag}'] + %q|'|
705
+ throw(:paramout)
706
+ else
707
+ for i in [#{mutexlist}]
708
+ _invalid[i] = '#{flag}'
709
+ end
710
+ end #if/then
711
+
712
+ "
713
+ end
714
+
715
+
716
+
717
+ for action in @actions
718
+ #action.sub!( /(\s*\{)/, '\1 module '+mod ) # @TODO
719
+ code << "\n " + action + "\n"
720
+ end
721
+
722
+ if flag && @items==0
723
+ code << "\n @cache['#{flag}'] = '#{flag}'\n"
724
+ if @ditto
725
+ code << "\n @cache['#{@ditto.flag}'] = '#{flag}'\n"
726
+ end
727
+ end
728
+
729
+ if @items > 1
730
+ code << " @cache['#{self.name}'] = {} unless @cache['#{self.name}'].kind_of?(Hash)\n"
731
+ if @ditto
732
+ code << "\n @cache['#{@ditto.name}'] = {} unless @cache['#{@ditto.name}'].kind_of?(Hash)\n"
733
+ end
734
+ end
735
+
736
+ for subarg in @args
737
+ code << subarg.cachecode(self.name,@items)
738
+ if ditto
739
+ code << subarg.cachecode(@ditto.name,@items)
740
+ end
741
+ end
742
+
743
+ if flag =~ /\A([^a-z0-9]+)/i
744
+ code << ' _lastprefix = "'+ Regexp::quote("#$1") + '"' + "\n"
745
+ else
746
+ code << " _lastprefix = nil\n"
747
+ end
748
+
749
+ code << "
750
+ _FOUND_['"+ self.foundid + "'] = 1
751
+ throw :arg if _pos > 0
752
+ _nextpos = _args.size
753
+ throw :alldone
754
+ end # catch(:param)
755
+ end # begin
756
+ end # while
757
+ end # catch(:paramout)
758
+ "
759
+
760
+ code
761
+ end
762
+
763
+ # Return name of argument, which can be flag's name or variable's name
764
+ def name
765
+ return @flag unless @flag.empty?
766
+ for i in @args
767
+ return "<#{i.name}>" if i.respond_to?(:name)
768
+ end
769
+ raise "Unknown flag name for parameter #{self.desc}"
770
+ end
771
+
772
+ # Return foundid of argument, which can be flag's name or variable's name
773
+ def foundid
774
+ return @foundid || self.name
775
+ end
776
+
777
+ end # Arg
778
+
779
+
780
+ private
781
+
782
+ class << self
783
+ @nocase = false
784
+ attr_accessor :nocase
785
+ end
786
+
787
+ #
788
+ # This is an additional function added to the class to simulate Perl's
789
+ # pos() \G behavior and m///g
790
+ #
791
+ # It performs a regex match, and returns the last index position of the
792
+ # match or nil. On successive invocations, it allows doing regex matches
793
+ # NOT from the beginning of the string easily.
794
+ #
795
+ # Class Array @@m stores the list of matches, as #$1 and similar
796
+ # variables have short lifespan in ruby, unlike perl.
797
+ #
798
+ def gindex(str, re, pos)
799
+ @@m.clear()
800
+ if pos = str.index( re, pos )
801
+ l = $&.size # length of match
802
+ if l > 0
803
+ @@m[0] = "#$1"
804
+ @@m[1] = "#$2"
805
+ @@m[2] = "#$3"
806
+ @@m[3] = "#$4"
807
+ @@m[4] = "#$5"
808
+ @@m[5] = "#$6"
809
+ @@m[6] = "#$7"
810
+ @@m[7] = "#$8"
811
+ @@m[8] = "#$9"
812
+ pos += l
813
+ end
814
+ end
815
+ pos
816
+ end
817
+
818
+ # Given an array or hash, flatten them to a string
819
+ def flatten(val, nested = nil)
820
+ case val
821
+ when Array
822
+ return val.map{ |i| flatten(i,1) }.join(" ")
823
+ when Hash
824
+ return val.keys.map{ |i| nested ||
825
+ i =~ /^-/ ? [i, flatten(val[i],1)] :
826
+ [flatten(val[i],1)] }.join(" ")
827
+ else
828
+ return val
829
+ end
830
+ end
831
+
832
+ # Read the next line from stdin
833
+ def _get_nextline
834
+ $stdin.readline
835
+ end
836
+
837
+ # For each file provided and found, read it in
838
+ def _load_sources( _get_nextline, files )
839
+ text = ''
840
+ found = []
841
+
842
+ for i in files
843
+ begin
844
+ f = File.open(i,"r")
845
+ rescue
846
+ next
847
+ end
848
+
849
+ if f.tty?
850
+ found.push( '<STDIN>' )
851
+ _get_nextline = method(:_get_nextline)
852
+ else
853
+ found.push( i );
854
+ t = f.readlines.join(' ')
855
+ t.tr!('\t\n',' ')
856
+ text += t
857
+ end
858
+ end
859
+
860
+ return nil unless found.size > 0
861
+ text = $stdin.readline if text.empty?
862
+ return [text, found.join(' or ')]
863
+ end
864
+
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*(.*?)\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!(/\\\[/,"\29")
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
+
1135
+ _lastactions = nil
1136
+ for i in _args
1137
+ if _lastactions && i.ditto && i.actions.size == 0
1138
+ i.actions = _lastactions
1139
+ else
1140
+ _lastactions = i.actions
1141
+ end
1142
+
1143
+ if _all_repeatable
1144
+ i.repeatable = 1
1145
+ end
1146
+ end
1147
+
1148
+ # Sort flags based on criteria described in docs
1149
+ # Sadly, this cannot be reduced to sort_by
1150
+ _args = _args.sort() { |a,b|
1151
+ cond1 = ( b.flag.size <=> a.flag.size )
1152
+ cond2 = ( b.flag == a.flag and ( b.args.size <=> a.args.size ) )
1153
+ cond3 = ( a.id <=> b.id )
1154
+ cond1 = nil if cond1 == 0
1155
+ cond2 = nil if cond2 == 0
1156
+ cond1 or cond2 or cond3
1157
+ }
1158
+
1159
+ # Handle clump
1160
+ clump = (@usage =~ /\[\s*cluster:\s*none\s*\]/i) ? 0 :
1161
+ (@usage =~ /\[\s*cluster:\s*singles?\s*\]/i) ? 1 :
1162
+ (@usage =~ /\[\s*cluster:\s*flags?\s*\]/i) ? 2 :
1163
+ (@usage =~ /\[\s*cluster:\s*any\s*\]/i) ? 3 :
1164
+ (@usage =~ /\[\s*cluster:(.*)\s*\]/i) ? "r" : 3
1165
+ raise "Error: unknown clustering mode: [cluster:#$1]\n" if clump == "r"
1166
+
1167
+ # CONSTRUCT OBJECT ITSELF
1168
+ @args = _args
1169
+ @mutex = _mutex
1170
+ @helppat = Arg::helppat()
1171
+ @verspat = Arg::versionpat()
1172
+
1173
+ @strict = _strict
1174
+ @clump = clump
1175
+ @source = ''
1176
+ @tight = @usage =~ /\[\s*tight\s*\]/i
1177
+ @caller = caller()
1178
+
1179
+ # VESTIGAL DEBUGGING CODE
1180
+ if @@debug
1181
+ f = File.new(".CODE.rb","w") and
1182
+ f.puts( code() ) and
1183
+ f.close()
1184
+ end
1185
+
1186
+ # DO THE PARSE (IF APPROPRIATE)
1187
+ if opts.size == 2
1188
+ return nil unless parse(source)
1189
+ else
1190
+ return nil unless parse()
1191
+ end
1192
+
1193
+ end # initialize
1194
+
1195
+
1196
+ # Parse the parameter description and in some cases,
1197
+ # optionally eval it, too.
1198
+ def parse(*opts)
1199
+ source = opts[0]
1200
+ _args = nil
1201
+ _get_nextline = proc { nil }
1202
+
1203
+ if source
1204
+ case source
1205
+ when Method
1206
+ _get_nextline = source
1207
+ _args = _get_nextline.call(self)
1208
+ source = '[METHOD]'
1209
+ when Proc
1210
+ _get_nextline = source
1211
+ _args = _get_nextline.call(self)
1212
+ source = '[PROC]'
1213
+ when IO
1214
+ if source.fileno > 0 && source.tty?
1215
+ _get_nextline = method(:_get_nextline)
1216
+ _args = $stdin.readline
1217
+ source = '<STDIN>'
1218
+ else
1219
+ _args = source.readlines.join(' ')
1220
+ _args.tr!('\t\n',' ')
1221
+ end
1222
+ when :build, :skip
1223
+ return 0
1224
+ when Array
1225
+ if source.length() == 1 && !source[0] ||
1226
+ source[0] == "-BUILD" ||
1227
+ source[0] == "-SKIP"
1228
+ return 0
1229
+ elsif source.length() == 2 && source[0] == "-ARGV"
1230
+ if !source[1] or !source[1] === Array
1231
+ raise 'Error: parse(["-ARGV"]) not passed an array as second parameter.'
1232
+ end
1233
+ _args = source[1].map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1234
+ source = '<ARRAY>'
1235
+ elsif source.length() == 1 && source[0] == "-STDIN"
1236
+ _get_nextline = method(:_get_nextline)
1237
+ _args = $stdin.readline
1238
+ source = '<STDIN>'
1239
+ elsif source.length() == 1 && source[0] == '-CONFIG'
1240
+ progname = "#{$0}rc"
1241
+ progname.sub!(%r#.*/#,'')
1242
+ home = ENV['HOME'] || ''
1243
+ _args, source = _load_sources( _get_nextline,
1244
+ [ home+"/.#{progname}",
1245
+ ".#{progname}" ] )
1246
+ else
1247
+ # Bunch of files to load passed to parse()
1248
+ _args, source = _load_sources( _get_nextline, source )
1249
+ end
1250
+ when String # else/case LITERAL STRING TO PARSE
1251
+ _args = source.dup
1252
+ source = source[0,7] + '...' if source && source.length() > 7
1253
+ source = "\"#{source[0..9]}\""
1254
+ else
1255
+ raise "Unknown source type for Getopt::Declare::parse"
1256
+ end # case
1257
+ return 0 unless _args
1258
+ source = " (in #{source})"
1259
+ else
1260
+ _args = ARGV.map { |i| i.tr( " \t\n", "\0\0\0" ) }.join(' ')
1261
+ source = ''
1262
+ end
1263
+
1264
+ @source = source
1265
+ begin
1266
+ err = eval( code(@caller) )
1267
+ if $@
1268
+ # oops, something wrong... exit
1269
+ puts "#{$!}: #{$@.inspect}"
1270
+ exit(1)
1271
+ end
1272
+ if !err
1273
+ exit(1)
1274
+ end
1275
+ rescue
1276
+ raise
1277
+ end
1278
+
1279
+
1280
+ true
1281
+ end
1282
+
1283
+ def type(*t)
1284
+ Getopt::Declare::ScalarArg::addtype(t)
1285
+ end
1286
+
1287
+ # Print out version information and maybe exit
1288
+ def version(*t)
1289
+ prog = "#{$0}"
1290
+ begin
1291
+ filedate = File.stat( prog ).mtime.localtime()
1292
+ rescue
1293
+ filedate = 'Unknown date'
1294
+ end
1295
+ prog.sub!(%r#.*/#,'')
1296
+ r = ''
1297
+ if defined?($VERSION)
1298
+ r << "\n#{prog}: version #{$VERSION} (#{filedate})\n\n"
1299
+ else
1300
+ r << "\n#{prog}: version dated #{filedate}\n\n"
1301
+ end
1302
+
1303
+ if t.empty?
1304
+ return r
1305
+ else
1306
+ puts r
1307
+ exit t[0]
1308
+ end
1309
+ end
1310
+
1311
+ # Print out usage information
1312
+ def usage(*opt)
1313
+
1314
+ t = @usage
1315
+
1316
+ lastflag = nil
1317
+ lastdesc = nil
1318
+ usage = ''
1319
+
1320
+ while !t.empty?
1321
+
1322
+ # COMMENT:
1323
+ t.sub!(/\A[ \t]*#.*\n/,".") and next
1324
+
1325
+ # TYPE DIRECTIVE:
1326
+ se = DelimScanner::new( t )
1327
+
1328
+ if t =~ /\A\s*\[\s*pvtype:/
1329
+ if action = se.extractBracketed("[")
1330
+ t.sub!(Regexp::quote( action ).to_re,'')
1331
+ t.sub!(/\A[ \t]*\n/,"")
1332
+ next
1333
+ end
1334
+ end
1335
+
1336
+ # ACTION
1337
+ codeblockDelimiters = {
1338
+ '{' => '}'
1339
+ }
1340
+ se = DelimScanner::new( t )
1341
+ if action = se.extractCodeblock(codeblockDelimiters)
1342
+ t.sub!(Regexp::quote( action ).to_re,'')
1343
+ t.sub!(/\A[ \t]*\n/,"")
1344
+ decfirst = 0 unless !decfirst.nil?
1345
+ next
1346
+ end
1347
+
1348
+
1349
+ # ARG + DESC:
1350
+ if t.sub!(re_argument,"")
1351
+ decfirst = 0 unless !decfirst.nil?
1352
+ spec = "#$1".expand_tabs!()
1353
+ desc = "#$2".expand_tabs!()
1354
+
1355
+ while t.gsub!(re_more_desc, '')
1356
+ desc += "#$1".expand_tabs!
1357
+ end
1358
+
1359
+ next if desc =~ /\[\s*undocumented\s*\]/i
1360
+
1361
+ uoff = 0
1362
+ spec.gsub!(/(<[a-zA-Z]\w*):([^>]+)>/e) { |i|
1363
+ uoff += 1 + "#$2".length() and "#$1>"
1364
+ }
1365
+ spec.gsub!(/\t/,"=")
1366
+
1367
+ ditto = desc =~ /\A\s*\[ditto\]/
1368
+ desc.gsub!(/^\s*\[.*?\]\s*\n/m,"")
1369
+ desc.gsub!(BracketDirectives,'')
1370
+ #desc.gsub!(/\[.*?\]/,"")
1371
+
1372
+
1373
+ if ditto
1374
+ desc = (lastdesc ? _ditto(lastflag,lastdesc,desc) : "" )
1375
+ elsif desc =~ /\A\s*\Z/
1376
+ next
1377
+ else
1378
+ lastdesc = desc
1379
+ end
1380
+
1381
+ spec =~ /\A\s*(\S+)/ and lastflag = "#$1"
1382
+
1383
+ desc.sub!(/\s+\Z/, "\n")
1384
+ usage += spec + ' ' * uoff + desc
1385
+ next
1386
+ end
1387
+
1388
+
1389
+
1390
+ # OTHERWISE, DECORATION
1391
+ if t.sub!(/((?:(?!\[\s*pvtype:).)*)(\n|(?=\[\s*pvtype:))/,"")
1392
+ desc = "#$1"+("#$2"||'')
1393
+ #desc.gsub!(/^(\s*\[.*?\])+\s*\n/m,'')
1394
+ #desc.gsub!(/\[.*?\]/,'') # eliminates anything in brackets
1395
+ if @tight || desc !~ /\A\s*\Z/
1396
+ desc.gsub!(BracketDirectives,'')
1397
+ next if desc =~ /\A\s*\Z/
1398
+ end
1399
+ decfirst = 1 unless !decfirst.nil? or desc =~ /\A\s*\Z/
1400
+ usage += desc
1401
+ end
1402
+
1403
+ end #while
1404
+
1405
+ required = ''
1406
+
1407
+ for arg in @args
1408
+ required += ' ' + arg.desc + ' ' if arg.required
1409
+ end
1410
+
1411
+ usage.gsub!(Regexp.new("\29"),"[/") # REINSTATE ESCAPED '['s
1412
+
1413
+ required.gsub!(/<([a-zA-Z]\w*):[^>]+>/,'<\1>')
1414
+ required.rstrip!
1415
+
1416
+ helpcmd = Getopt::Declare::Arg::besthelp
1417
+ versioncmd = Getopt::Declare::Arg::bestversion
1418
+
1419
+
1420
+ header = ''
1421
+ unless @source.nil?
1422
+ header << version()
1423
+ prog = "#{$0}"
1424
+ prog.sub!(%r#.*/#,'')
1425
+ header << "Usage: #{prog} [options]#{required}\n"
1426
+ header << " #{prog} #{helpcmd}\n" if helpcmd
1427
+ header << " #{prog} #{versioncmd}\n" if versioncmd
1428
+ header << "\n" unless decfirst && decfirst == 1 && usage =~ /\A[ \t]*\n/
1429
+ end
1430
+
1431
+ header << "Options:\n" unless decfirst && decfirst == 1
1432
+
1433
+ usage.sub!(/[\s\n]+\Z/m, '')
1434
+
1435
+ pager = $stdout
1436
+
1437
+ #begin
1438
+ # eval('require "IO/Pager";')
1439
+ # pager = IO::Pager.new()
1440
+ #rescue
1441
+ #end
1442
+
1443
+ if opt.empty?
1444
+ pager.puts "#{header}#{usage}"
1445
+ return 0
1446
+ ### usage
1447
+ end
1448
+
1449
+ #usage.sub!(/\A[\s\n]+/m, '')
1450
+ pager.puts "#{header}#{usage}"
1451
+ exit(opt[0]) if opt[0]
1452
+ end
1453
+
1454
+ attr_accessor :unused
1455
+
1456
+
1457
+ # Return list of used parameters (after parsing)
1458
+ def used
1459
+ used = @cache.keys
1460
+ return used.join(' ')
1461
+ end
1462
+
1463
+ @@m = []
1464
+
1465
+ # Main method to generate code to be evaluated for parsing.
1466
+ def code(*t)
1467
+ package = t[0] || ''
1468
+ code = %q%
1469
+
1470
+
1471
+ @_deferred = []
1472
+ @_errormsg = nil
1473
+ @_finished = nil
1474
+
1475
+ begin
1476
+
1477
+ begin
1478
+ undef :defer
1479
+ undef :reject
1480
+ undef :finish
1481
+ rescue
1482
+ end
1483
+
1484
+ def defer(&i)
1485
+ @_deferred.push( i )
1486
+ end
1487
+
1488
+ def reject(*i)
1489
+ if !i || i[0]
1490
+ @_errormsg = i[1] if i[1]
1491
+ throw :paramout
1492
+ end
1493
+ end
1494
+
1495
+ def finish(*i)
1496
+ if i.size
1497
+ @_finished = i
1498
+ else
1499
+ @_finished = true
1500
+ end
1501
+ end
1502
+
1503
+ @unused = []
1504
+ @cache = {}
1505
+ _FOUND_ = {}
1506
+ _errors = 0
1507
+ _invalid = {}
1508
+ _lastprefix = nil
1509
+
1510
+ _pos = 0 # current position to match from
1511
+ _nextpos = 0 # next position to match from
1512
+
1513
+ catch(:alldone) do
1514
+ while !@_finished
1515
+ begin
1516
+ catch(:arg) do
1517
+ @_errormsg = nil
1518
+
1519
+ # This is used for clustering of flags
1520
+ while _lastprefix
1521
+ substr = _args[_nextpos..-1]
1522
+ substr =~ /^(?!\s|\0|\Z)% +
1523
+ Getopt::Declare::Arg::negflagpat() + %q%/ or
1524
+ begin
1525
+ _lastprefix=nil
1526
+ break
1527
+ end
1528
+ "#{_lastprefix}#{substr}" =~ /^(% +
1529
+ Getopt::Declare::Arg::posflagpat() + %q%)/ or
1530
+ begin
1531
+ _lastprefix=nil
1532
+ break
1533
+ end
1534
+ _args = _args[0.._nextpos-1] + _lastprefix + _args[_nextpos..-1]
1535
+ break
1536
+ end # while _lastprefix
1537
+
1538
+ % + '' + %q%
1539
+ _pos = _nextpos if _args
1540
+
1541
+ usage(0) if _args && gindex(_args,/\G(% + @helppat + %q%)(\s|\0|\Z)/,_pos)
1542
+ version(0) if _args && _args =~ /\G(% + @verspat + %q%)(\s|\0|\Z)/
1543
+ %
1544
+
1545
+ for arg in @args
1546
+ code << arg.code(self,package)
1547
+ end
1548
+
1549
+ code << %q%
1550
+
1551
+ if _lastprefix
1552
+ _pos = _nextpos + _lastprefix.length()
1553
+ _lastprefix = nil
1554
+ next
1555
+ end
1556
+
1557
+ _pos = _nextpos
1558
+
1559
+ _args && _pos = gindex( _args, /\G[\s|\0]*(\S+)/, _pos ) or throw(:alldone)
1560
+
1561
+ if @_errormsg
1562
+ $stderr.puts( "Error#{source}: #{@_errormsg}\n" )
1563
+ else
1564
+ @unused.push( @@m[0] )
1565
+ end
1566
+
1567
+ _errors += 1 if @_errormsg
1568
+
1569
+ end # catch(:arg)
1570
+
1571
+ ensure # begin
1572
+ _pos = 0 if _pos.nil?
1573
+ _nextpos = _pos if _args
1574
+ if _args and _args.index( /\G(\s|\0)*\Z/, _pos )
1575
+ _args = _get_nextline.call(self) if !@_finished
1576
+ throw(:alldone) unless _args
1577
+ _pos = _nextpos = 0
1578
+ _lastprefix = ''
1579
+ end # if
1580
+ end # begin/ensure
1581
+ end # while @_finished
1582
+ end # catch(:alldone)
1583
+ end # begin
1584
+
1585
+ %
1586
+
1587
+
1588
+ ################################
1589
+ # Check for required arguments #
1590
+ ################################
1591
+ for arg in @args
1592
+ next unless arg.required
1593
+
1594
+ code << %q%unless _FOUND_['% + arg.name + %q%'] %
1595
+
1596
+ if @mutex[arg.name]
1597
+ for m in @mutex[arg.name]
1598
+ code << %q# or _FOUND_['# + m + %q#']#
1599
+ end
1600
+ end
1601
+
1602
+ code << %q%
1603
+ $stderr.puts "Error#{@source}: required parameter '% + arg.name + %q%' not found."
1604
+ _errors += 1
1605
+ end
1606
+ %
1607
+
1608
+ end
1609
+
1610
+ ########################################
1611
+ # Check for arguments requiring others #
1612
+ ########################################
1613
+
1614
+ for arg in @args
1615
+ next unless arg.requires
1616
+
1617
+ code << %q%
1618
+ if _FOUND_['% + arg.name + %q%'] && !(% + arg.found_requires +
1619
+ %q%)
1620
+ $stderr.puts "Error#{@source}: parameter '% + arg.name + %q%' can only be specified with '% + arg.requires + %q%'"
1621
+ _errors += 1
1622
+ end
1623
+ %
1624
+ end
1625
+
1626
+ code << %q%
1627
+ #################### Add unused arguments
1628
+ if _args && _nextpos > 0 && _args.length() > 0
1629
+ @unused.replace( @unused + _args[_nextpos..-1].split(' ') )
1630
+ end
1631
+
1632
+ for i in @unused
1633
+ i.tr!( "\0", " " )
1634
+ end
1635
+
1636
+ %
1637
+
1638
+ if @strict
1639
+ code << %q%
1640
+ #################### Handle strict flag
1641
+ unless _nextpos < ( _args ? _args.length : 0 )
1642
+ for i in @unused
1643
+ $stderr.puts "Error#{@source}: unrecognizable argument ('#{i}')"
1644
+ _errors += 1
1645
+ end
1646
+ end
1647
+ %
1648
+ end
1649
+
1650
+ code << %q%
1651
+ #################### Print help hint
1652
+ if _errors > 0 && !@source.nil?
1653
+ $stderr.puts "\n(try '#$0 % + Getopt::Declare::Arg::besthelp + %q%' for more information)"
1654
+ end
1655
+
1656
+ ## cannot just assign unused to ARGV in ruby
1657
+ unless @source != ''
1658
+ ARGV.clear
1659
+ @unused.map { |i| ARGV.push(i) }
1660
+ end
1661
+
1662
+ unless _errors > 0
1663
+ for i in @_deferred
1664
+ begin
1665
+ i.call
1666
+ rescue => e
1667
+ STDERR.puts "Action in Getopt::Declare specification produced:\n#{e}"
1668
+ _errors += 1
1669
+ end
1670
+ end
1671
+ end
1672
+
1673
+ !(_errors>0) # return true or false (false for errors)
1674
+
1675
+ %
1676
+ return code
1677
+ end
1678
+
1679
+
1680
+ # Inspect cache (not the declare object)
1681
+ def inspect
1682
+ return nil if !@cache
1683
+ t = ''
1684
+
1685
+ @cache.each { |a,b|
1686
+ t << a + " => "
1687
+ case b
1688
+ when Hash
1689
+ t << "{"
1690
+ i = []
1691
+ b.each { |c,d|
1692
+ i.push( " '#{c}' => " + d.inspect )
1693
+ }
1694
+ t << i.join(',')
1695
+ t << " }"
1696
+ else
1697
+ t << b.inspect
1698
+ end
1699
+ t << "\n"
1700
+ }
1701
+ t << "Unused: " + unused.join(', ')
1702
+ end
1703
+
1704
+ # Iterator for Getopt::Declare (travels thru all cache keys)
1705
+ def each(&t)
1706
+ @cache.each(&t)
1707
+ end
1708
+
1709
+ # Operator to easily create new value in of Getopt::Declare
1710
+ def []=(name,val)
1711
+ @cache = {} unless @cache
1712
+ @cache[name] = val
1713
+ end
1714
+
1715
+ # Operator to easily return cache of Getopt::Declare
1716
+ def [](name)
1717
+ if @cache
1718
+ return @cache[name]
1719
+ else
1720
+ return nil
1721
+ end
1722
+ end
1723
+
1724
+ # Operator to return number of flags set
1725
+ def size
1726
+ return 0 unless @cache
1727
+ return @cache.keys.size
1728
+ end
1729
+
1730
+ attr :mutex
1731
+ attr :helppat
1732
+ attr :verspat
1733
+ attr :strict
1734
+ attr :clump
1735
+ attr :source
1736
+
1737
+ end # class Declare
1738
+
1739
+ end # module Getopt