alib 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: alib
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.1
7
- date: 2005-11-30 00:00:00.000000 -07:00
6
+ version: 0.4.0
7
+ date: 2006-08-23 00:00:00.000000 -06:00
8
8
  summary: alib
9
9
  require_paths:
10
10
  - lib
@@ -29,8 +29,28 @@ cert_chain:
29
29
  authors:
30
30
  - Ara T. Howard
31
31
  files:
32
+ - lib
33
+ - install.rb
34
+ - install
35
+ - gemspec.rb
36
+ - build
37
+ - alib-0.4.0.gem
38
+ - b.rb
39
+ - a.rb
40
+ - lib/alib-0.4.0.rb
32
41
  - lib/alib.rb
33
- - lib/alib-0.3.1.rb
42
+ - lib/alib-0.4.0
43
+ - lib/alib-0.4.0/util.rb
44
+ - lib/alib-0.4.0/logging.rb
45
+ - lib/alib-0.4.0/configfile.rb
46
+ - lib/alib-0.4.0/listfile.rb
47
+ - lib/alib-0.4.0/autohash.rb
48
+ - lib/alib-0.4.0/orderedautohash.rb
49
+ - lib/alib-0.4.0/orderedhash.rb
50
+ - lib/alib-0.4.0/find2.rb
51
+ - lib/alib-0.4.0/bsearch.rb
52
+ - lib/alib-0.4.0/main.rb
53
+ - lib/alib-0.4.0/open4.rb
34
54
  test_files: []
35
55
  rdoc_options: []
36
56
  extra_rdoc_files: []
@@ -1,3872 +0,0 @@
1
- #
2
- # the ALib module is a namespace for things i've found useful
3
- #
4
- module ALib
5
- #--{{{
6
- VERSION = '0.3.1'
7
-
8
- require 'pathname'
9
- require 'socket'
10
- require 'tmpdir'
11
- require 'rbconfig'
12
- require 'logger'
13
- require 'yaml'
14
- require 'drb/drb'
15
- require 'fileutils'
16
- require 'tempfile'
17
- require 'optparse'
18
- require 'sync'
19
- require 'time'
20
-
21
- def ALib::export e
22
- #--{{{
23
- (@__exported ||= []) << e
24
- @__exported.uniq!
25
- @__exported
26
- #--}}}
27
- end
28
-
29
- #
30
- # the utility module is a namespace for things which otherwise wouldn't have a
31
- # home. the methods of Util can be used as module methods or included into a
32
- # class and then used as instance OR class methods
33
- #
34
- module Util
35
- #--{{{
36
- class << self
37
- def export(*syms)
38
- #--{{{
39
- syms.each do |sym|
40
- sym = "#{ sym }".intern
41
- module_function sym
42
- public sym
43
- end
44
- #--}}}
45
- end
46
- def append_features c
47
- #--{{{
48
- super
49
- c.extend self
50
- #--}}}
51
- end
52
- end
53
- #
54
- # requires a certain version of ruby or higher
55
- # require_version '1.8.0'
56
- #
57
- def require_version version
58
- #--{{{
59
- major, minor, teeny = "#{ version }".split(%r/\./o).map{|n| Integer(n)}
60
- required = "#{ major }.#{ minor }.#{ teeny }"
61
- _major, _minor, _teeny =
62
- %w( MAJOR MINOR TEENY ).map{|k| Integer(::Config::CONFIG[k])}
63
- actual = "#{ _major }.#{ _minor }.#{ _teeny }"
64
- unless _major > major or _major == major and _minor >= minor
65
- STDERR.puts("=" * 79)
66
- STDERR.puts "this program requires a ruby version >= <#{ required }>"
67
- STDERR.puts
68
- STDERR.puts "you are currenlty running ruby version <#{ actual }>"
69
- STDERR.puts
70
- STDERR.puts "possible problems which could cause this are:"
71
- STDERR.puts " - improper PATH environment variable setting"
72
- STDERR.puts " - ruby > <#{ required }> has not been installed"
73
- STDERR.puts("=" * 79)
74
- exit 1
75
- end
76
- #--}}}
77
- end
78
- #
79
- # the basename of $0
80
- #
81
- def prognam
82
- #--{{{
83
- File::basename $0
84
- #--}}}
85
- end
86
- export 'prognam'
87
- #
88
- # marshal'd 'deep' copy of obj
89
- #
90
- def mcp obj
91
- #--{{{
92
- Marshal.load(Marshal.dump(obj))
93
- #--}}}
94
- end
95
- export 'mcp'
96
- #
97
- # self.class
98
- #
99
- def klass
100
- #--{{{
101
- self.class
102
- #--}}}
103
- end
104
- export 'klass'
105
- #
106
- # File::expand_path + link resolution
107
- #
108
- def realpath path
109
- #--{{{
110
- path = File::expand_path "#{ path }"
111
- begin
112
- Pathname.new(path).realpath.to_s
113
- rescue Errno::ENOENT, Errno::ENOTDIR
114
- path
115
- end
116
- #--}}}
117
- end
118
- export 'realpath'
119
- #
120
- # collect n hashed into one hash - later keys overried earlier keys
121
- #
122
- def hashify(*hashes)
123
- #--{{{
124
- hashes.inject(accum={}){|accum,hash| accum.update hash}
125
- #--}}}
126
- end
127
- export 'hashify'
128
- #
129
- # look up key in hash as key, then string of key, then intern of key -
130
- # returning the value or, if key is not found, nil or default
131
- #
132
- def getopt opt, hash, default = nil
133
- #--{{{
134
- keys = opt.respond_to?('each') ? opt : [opt]
135
-
136
- keys.each do |key|
137
- return hash[key] if hash.has_key? key
138
- key = "#{ key }"
139
- return hash[key] if hash.has_key? key
140
- key = key.intern
141
- return hash[key] if hash.has_key? key
142
- end
143
-
144
- return default
145
- #--}}}
146
- end
147
- alias get_opt getopt
148
- export 'getopt'
149
- export 'get_opt'
150
- #
151
- # determine if a key, key.to_s, or key.to_s.intern is in hash
152
- # see getopt
153
- #
154
- def hasopt opt, hash, default = false
155
- #--{{{
156
- keys = opt.respond_to?('each') ? opt : [opt]
157
-
158
- keys.each do |key|
159
- return key if hash.has_key? key
160
- key = "#{ key }"
161
- return key if hash.has_key? key
162
- key = key.intern
163
- return key if hash.has_key? key
164
- end
165
-
166
- return default
167
- #--}}}
168
- end
169
- alias has_opt hasopt
170
- alias hasopt? hasopt
171
- alias has_opt? hasopt
172
- export 'hasopt'
173
- export 'hasopt?'
174
- export 'has_opt'
175
- export 'has_opt?'
176
- #
177
- # delete key in hash as key, then string of key, then intern of key -
178
- # returning the value or, if key is not found, nil or default
179
- #
180
- def delopt opt, hash, default = nil
181
- #--{{{
182
- keys = opt.respond_to?('each') ? opt : [opt]
183
-
184
- keys.each do |key|
185
- return hash.delete(key) if hash.has_key? key
186
- key = "#{ key }"
187
- return hash.delete(key) if hash.has_key? key
188
- key = key.intern
189
- return hash.delete(key) if hash.has_key? key
190
- end
191
-
192
- return default
193
- #--}}}
194
- end
195
- alias delete_opt delopt
196
- alias extract_opt delopt
197
- alias extractopt delopt
198
- alias xopt delopt
199
- export 'delete_opt'
200
- export 'extract_opt'
201
- export 'extractopt'
202
- export 'xopt'
203
- export 'delopt'
204
- #
205
- # returns true if pid is running, false otherwise
206
- #
207
- def alive pid
208
- #--{{{
209
- pid = Integer("#{ pid }")
210
- begin
211
- Process::kill 0, pid
212
- true
213
- rescue Errno::ESRCH
214
- false
215
- end
216
- #--}}}
217
- end
218
- alias alive? alive
219
- export 'alive', 'alive?'
220
- #
221
- # brutally shut down a process. opts can contain the keys 'signals' which
222
- # should be a list of signals used to send to the process and the key
223
- # 'suspend' which is the amount of time to wait after firing each signal
224
- # before seeing if the process is dead. the defaults are %w(TERM QUIT KILL)
225
- # and 4 respectively
226
- #
227
- def maim(pid, opts = {})
228
- #--{{{
229
- sigs = Util::getopt 'signals', opts, %w(SIGTERM SIGQUIT SIGKILL)
230
- suspend = Util::getopt 'suspend', opts, 4
231
- pid = Integer("#{ pid }")
232
- existed = false
233
- sigs.each do |sig|
234
- begin
235
- Process::kill(sig, pid)
236
- existed = true
237
- rescue Errno::ESRCH
238
- unless existed
239
- return nil
240
- else
241
- return true
242
- end
243
- end
244
- return true unless alive?(pid)
245
- sleep suspend
246
- return true unless alive?(pid)
247
- end
248
- return(not alive?(pid))
249
- #--}}}
250
- end
251
- export 'maim'
252
- #
253
- # YYYY-MM-DD hh:mm:ss.uuuuuu representation of time. if the option
254
- # 'nospace' is true spaces are replaced with underscores/or the value of the
255
- # nospace option - useful for constructing filenames
256
- #
257
- def timestamp arg = Time::now
258
- #--{{{
259
- if Time === arg
260
- arg.iso8601 2
261
- else
262
- opts =
263
- case arg
264
- when Hash
265
- opts = arg
266
- when Time
267
- {'time' => arg}
268
- else
269
- raise ArgumentError, "#{ arg.inspect } (#{ arg.class })"
270
- end
271
- time = Util::getopt 'time', opts, Time::now
272
- local = Util::getopt 'local', opts, false
273
- nospace = Util::getopt('nospace', opts, Util::getopt('no_space', opts, false))
274
- dateonly = Util::getopt('dateonly', opts, Util::getopt('date_only', opts, false))
275
- time = time.utc unless local
276
- usec = "#{ time.usec }"
277
- usec << ('0' * (6 - usec.size)) if usec.size < 6
278
- stamp =
279
- unless dateonly
280
- time.strftime('%Y-%m-%d %H:%M:%S.') << usec
281
- else
282
- time.strftime('%Y-%m-%d')
283
- end
284
- if nospace
285
- spc = TrueClass === nospace ? 'T' : "#{ nospace }"
286
- stamp.gsub! %r/\s+/, spc
287
- end
288
- stamp
289
- end
290
- #--}}}
291
- end
292
- export 'timestamp'
293
- #
294
- # inverse of timestamp. the option 'local' determines whether the timestamp
295
- # is interpreted as a local or utc time.
296
- #
297
- # TODO - review hack to fix Time::parse bug with ms and tz
298
- # TODO - review hack to fix Time::parse bug with ms and tz
299
- # TODO - review hack to fix Time::parse bug with ms and tz
300
- def stamptime string, opts = {}
301
- #--{{{
302
- tz = string[ %r/-\d\d:\d\d\s*$/ ]
303
- time = nil
304
- if opts.empty? or tz
305
- u = string[%r/\.\d+/]
306
- string[%r/\.\d+/] = '' if u
307
- time = Time::parse string
308
- time += u.to_f if u
309
- else
310
- local = Util::getopt 'local', opts, false
311
- string = "#{ string }"
312
- pat = %r/^\s*(\d\d\d\d)-(\d\d)-(\d\d)[\s_tT]+(\d\d):(\d\d):(\d\d)(?:.(\d+))?\s*$/o
313
- match = pat.match string
314
- raise ArgumentError, "<#{ string.inspect }>" unless match
315
- yyyy,mm,dd,h,m,s,u = match.to_a[1..-1].map{|m| (m || 0).to_i}
316
- if local
317
- time = Time::local yyyy,mm,dd,h,m,s,u
318
- else
319
- time = Time::gm yyyy,mm,dd,h,m,s,u
320
- end
321
- end
322
- return time
323
- #--}}}
324
- end
325
- export 'stamptime'
326
- #
327
- # escapes any occurances of char in s with esc modifying s inplace
328
- #
329
- def escape! s, char, esc
330
- #--{{{
331
- # re = %r/([#{ 0x5c.chr << esc }]*)#{ char }/
332
- re = %r/([#{ Regexp::quote esc }]*)#{ Regexp::quote char }/
333
- s.gsub!(re) do
334
- (($1.size % 2 == 0) ? ($1 << esc) : $1) + char
335
- end
336
- #--}}}
337
- end
338
- export 'escape!'
339
- #
340
- # new copy of s with any occurances of char escaped with esc
341
- #
342
- def escape s, char, esc
343
- #--{{{
344
- escape! "#{ s }", char, esc
345
- #--}}}
346
- end
347
- export 'escape'
348
- #
349
- # a quiet fork
350
- #
351
- def fork(*args, &block)
352
- #--{{{
353
- begin
354
- verbose = $VERBOSE
355
- $VERBOSE = nil
356
- Process::fork(*args, &block)
357
- ensure
358
- $VERBOSE = verbose
359
- end
360
- #--}}}
361
- end
362
- export 'fork'
363
- #
364
- # an quiet exec
365
- #
366
- def exec(*args, &block)
367
- #--{{{
368
- begin
369
- verbose = $VERBOSE
370
- $VERBOSE = nil
371
- Kernel::exec(*args, &block)
372
- ensure
373
- $VERBOSE = verbose
374
- end
375
- #--}}}
376
- end
377
- export 'exec'
378
- #
379
- # a quiet system
380
- #
381
- def system(*args, &block)
382
- #--{{{
383
- begin
384
- verbose = $VERBOSE
385
- $VERBOSE = nil
386
- Kernel::system(*args, &block)
387
- ensure
388
- $VERBOSE = verbose
389
- end
390
- #--}}}
391
- end
392
- export 'system'
393
- #
394
- # a quiet system which succeeds or throws errors
395
- #
396
- def spawn cmd, opts = {}
397
- #--{{{
398
- exitstatus = Util::getopt(%w( exitstatus exit_status status ), opts, 0)
399
- Util::system cmd
400
- status = $?.exitstatus
401
- raise "cmd <#{ cmd }> failed with <#{ status }>" unless
402
- status == exitstatus
403
- status
404
- #--}}}
405
- end
406
- export 'spawn'
407
- #
408
- # lookup, and cache, the hostname
409
- #
410
- def hostname
411
- #--{{{
412
- @__hostname__ ||= Socket::gethostname
413
- #--}}}
414
- end
415
- export 'hostname'
416
- #
417
- # lookup, and cache, the host (first bit of hostname quad)
418
- #
419
- def host
420
- #--{{{
421
- @__host__ ||= hostname.gsub(%r/\..*$/o,'')
422
- #--}}}
423
- end
424
- export 'host'
425
- #
426
- # format exception as Logger class does - no backtrace
427
- #
428
- def emsg e
429
- #--{{{
430
- "#{ e.message } - (#{ e.class })"
431
- #--}}}
432
- end
433
- export 'emsg'
434
- #
435
- # format exception backtrace as string
436
- #
437
- def btrace e
438
- #--{{{
439
- (e.backtrace or []).join("\n")
440
- #--}}}
441
- end
442
- export 'btrace'
443
- #
444
- # format exception as Logger class does - with backtrace
445
- #
446
- def errmsg e
447
- #--{{{
448
- emsg(e) << "\n" << btrace(e)
449
- #--}}}
450
- end
451
- export 'errmsg'
452
- #
453
- # determine equality of two exceptions
454
- #
455
- def erreq a, b
456
- #--{{{
457
- a.class == b.class and
458
- a.message == b.message and
459
- a.backtrace == b.backtrace
460
- #--}}}
461
- end
462
- export 'erreq'
463
- #
464
- # generate a temporary filename for the directory dir using seed as a
465
- # basename
466
- #
467
- def tmpnam opts = {}
468
- #--{{{
469
- dir = Util::getopt 'dir', opts, Dir::tmpdir
470
- seed = Util::getopt 'seed', opts, Util::prognam
471
- path =
472
- "%s_%s_%s_%s_%d" % [
473
- Util::hostname,
474
- seed,
475
- Process::pid,
476
- Util::timestamp('nospace' => true),
477
- rand(101010)
478
- ]
479
- dirname, basename = File::dirname(path), File::basename(path)
480
- tn = File::join(dir, dirname, basename.gsub(%r/[^0-9a-zA-Z]/,'_')).gsub(%r/\s+/, '_')
481
- File::expand_path tn
482
- #--}}}
483
- end
484
- export 'tmpnam'
485
- def tmpdir(*argv)
486
- #--{{{
487
- args, opts = Util::optfilter argv
488
- retries = Util::getopt 'retries', opts, 42
489
- opts['dir'] ||= (args.first || Util::getopt('base', opts) || '.')
490
- d = nil
491
- retries.times do
492
- td = Util::tmpnam(opts)
493
- break if ((d = FileUtils::mkdir_p td rescue nil))
494
- end
495
- raise "surpassed max retries <#{ retries }>" unless d
496
- d = File::expand_path d
497
- if block_given?
498
- cwd = Dir::pwd
499
- begin
500
- Dir::chdir d
501
- yield [cwd,d]
502
- ensure
503
- Dir::chdir cwd if cwd
504
- Dir[File::join(d, "**")].each{|e| FileUtils::rm_rf e}
505
- FileUtils::rm_rf d
506
- end
507
- else
508
- at_exit{ FileUtils::rm_rf d }
509
- return d
510
- end
511
- #--}}}
512
- end
513
- export 'tmpdir'
514
- #
515
- # make best effort to invalidate any inode caching done by nfs clients
516
- #
517
- def uncache file
518
- #--{{{
519
- refresh = nil
520
- begin
521
- is_a_file = File === file
522
- path = (is_a_file ? file.path : file.to_s)
523
- stat = (is_a_file ? file.stat : File::stat(file.to_s))
524
- refresh = tmpnam(File::dirname(path))
525
- File::link path, refresh rescue File::symlink path, refresh
526
- File::chmod stat.mode, path
527
- File::utime stat.atime, stat.mtime, path
528
- open(File::dirname(path)){|d| d.fsync rescue nil}
529
- ensure
530
- begin
531
- File::unlink refresh if refresh
532
- rescue Errno::ENOENT
533
- end
534
- end
535
- #--}}}
536
- end
537
- export 'uncache'
538
- #
539
- # wrap a string using options width (default 80) and indent using the indent
540
- # option (default 0)
541
- #
542
- def columnize buf, opts = {}
543
- #--{{{
544
- width = Util::getopt 'width', opts, 80
545
- indent = Util::getopt 'indent', opts
546
- indent = Fixnum === indent ? (' ' * indent) : "#{ indent }"
547
- column = []
548
- words = buf.split %r/\s+/o
549
- row = "#{ indent }"
550
- while((word = words.shift))
551
- if((row.size + word.size) < (width - 1))
552
- row << word
553
- else
554
- column << row
555
- row = "#{ indent }"
556
- row << word
557
- end
558
- row << ' ' unless row.size == (width - 1)
559
- end
560
- column << row unless row.strip.empty?
561
- column.join "\n"
562
- #--}}}
563
- end
564
- export 'columnize'
565
- #
566
- # search for a default value for 'var' using
567
- # * DEFAULT_VAR
568
- # * self.class.var
569
- # returning the option default, or nil
570
- #
571
- def defval var, opts = {}
572
- #--{{{
573
- default = Util::getopt 'default', opts, nil
574
- v = "#{ var }"
575
- c0, c1 = "DEFAULT_#{ v }".upcase, "#{ v }".upcase
576
- begin
577
- klass.send(v) || klass.const_get(c0) || klass.const_get(c1)
578
- rescue NameError
579
- default
580
- end
581
- #--}}}
582
- end
583
- export 'defval'
584
- #
585
- # initiates a catch block to do 'something'. if the method try_again! is
586
- # called the block is done over - if the method give_up! is called the block
587
- # is aborted. calls to attempt may be nested.
588
- #
589
- def attempt label = 'attempt'
590
- #--{{{
591
- ret = nil
592
- n_attempts = 0
593
- loop{ break unless catch("#{ label }"){ ret = yield(n_attempts += 1) } == 'try_again' }
594
- ret
595
- #--}}}
596
- end
597
- export 'attempt'
598
- #
599
- # see attempt
600
- #
601
- def try_again! label = 'attempt'
602
- #--{{{
603
- throw "#{ label }", 'try_again'
604
- #--}}}
605
- end
606
- alias try_again try_again!
607
- alias again! try_again!
608
- export 'try_again!', 'again!', 'try_again'
609
- #
610
- # see attempt
611
- #
612
- def give_up! label = 'attempt'
613
- #--{{{
614
- throw "#{ label }", 'give_up'
615
- #--}}}
616
- end
617
- alias giveup! give_up!
618
- alias give_up give_up!
619
- export 'give_up!', 'giveup!', 'give_up'
620
- #
621
- # creates a class by class name
622
- #
623
- def klass_stamp(hierachy, *a, &b)
624
- #--{{{
625
- ancestors = hierachy.split(%r/::/)
626
- parent = Object
627
- while((child = ancestors.shift))
628
- klass = parent.const_get child
629
- parent = klass
630
- end
631
- klass::new(*a, &b)
632
- #--}}}
633
- end
634
- export 'klass_stamp'
635
- #
636
- # shortcut to Find2
637
- #
638
- def find(*a, &b)
639
- #--{{{
640
- a << '.' if a.empty?
641
- Find2::find(*a, &b)
642
- #--}}}
643
- end
644
- export 'find'
645
- #
646
- # shortcut to Find2
647
- #
648
- def find2(*a, &b)
649
- #--{{{
650
- a << '.' if a.empty?
651
- Find2::find2(*a, &b)
652
- #--}}}
653
- end
654
- export 'find2'
655
- #
656
- # shortcut to Find2.prune
657
- #
658
- def prune
659
- #--{{{
660
- Find2.prune
661
- #--}}}
662
- end
663
- export 'prune'
664
- #
665
- # pull out options from arglist
666
- #
667
- def optfilter(*list)
668
- #--{{{
669
- args, opts = [ list ].flatten.partition{|item| not Hash === item}
670
- [args, Util::hashify(*opts)]
671
- #--}}}
672
- end
673
- export 'optfilter'
674
- #
675
- # pop of options from an arglist
676
- #
677
- def argv_split(argv)
678
- #--{{{
679
- args = argv
680
- opts = args.pop if Hash === args.last
681
- puts "args : #{ args.inspect }"
682
- puts "opts : #{ opts.inspect }"
683
- [args, opts]
684
- #--}}}
685
- end
686
- export 'argv_split'
687
- #
688
- # split a path into dirname, basename, extension
689
- #
690
- def splitpath path
691
- #--{{{
692
- path = "#{ path }"
693
- dirname, basename = File::split path
694
- [ dirname, (%r/^([^\.]*)(.*)$/).match(basename)[1,2] ].flatten
695
- #--}}}
696
- end
697
- export 'splitpath'
698
- #
699
- # handle a pathname after unzipping (iff needed)
700
- #
701
- def unzipped path, z_pat = %r/\.(?:z|gz)$/io
702
- #--{{{
703
- zipped = zipped?(path, z_pat)
704
- unless zipped
705
- yield path
706
- else
707
- unzipped = unzip path
708
- begin
709
- yield unzipped
710
- ensure
711
- zip unzipped
712
- end
713
- end
714
- #--}}}
715
- end
716
- export 'unzipped'
717
- #
718
- # zip a file - return zipped name
719
- #
720
- def zip path, z_ext = nil
721
- #--{{{
722
- z_ext ||= '.gz'
723
- z_ext.gsub! %r/^\s*\.+/, '.'
724
- Util::spawn "gzip --suffix #{ z_ext } --force #{ path }"
725
- zipped = "#{ path }#{ z_ext }"
726
- raise "could not create <#{ zipped }>" unless test ?e, zipped
727
- if block_given?
728
- yield zipped
729
- else
730
- zipped
731
- end
732
- #--}}}
733
- end
734
- alias gzip zip
735
- export 'gzip'
736
- export 'zip'
737
- #
738
- # return the zipped name of a path
739
- #
740
- def zipped_name path, z_ext = nil
741
- #--{{{
742
- z_ext ||= '.gz'
743
- z_ext.gsub! %r/^\s*\.+/, '.'
744
- "#{ path }#{ z_ext }"
745
- #--}}}
746
- end
747
- export 'zipped_name'
748
- #
749
- # unzip a file - return unzipped name
750
- #
751
- def unzip path, z_pat = nil
752
- #--{{{
753
- z_pat ||= %r/\.(?:z|gz)$/io
754
- Util::spawn "gzip --force --decompress #{ path }" if zipped?(path, z_pat)
755
- #Util::spawn "gzip --force --decompress #{ path }"
756
- uzn = Util::unzipped_name path, z_pat
757
- if block_given?
758
- yield uzn
759
- else
760
- uzn
761
- end
762
- #--}}}
763
- end
764
- alias gunzip unzip
765
- export 'gunzip'
766
- export 'unzip'
767
- #
768
- # return the unzipped name of a path
769
- #
770
- def unzipped_name path, z_pat = nil
771
- #--{{{
772
- z_pat ||= %r/\.(?:z|gz)$/io
773
- path.gsub z_pat, ''
774
- #--}}}
775
- end
776
- export 'unzipped_name'
777
- #
778
- # guess if a file is zipped based on pathname
779
- #
780
- def zipped? path, z_pat = %r/\.(?:z|gz)$/io
781
- #--{{{
782
- path =~ z_pat
783
- #--}}}
784
- end
785
- alias gzipped? zipped?
786
- export 'gzipped?'
787
- export 'zipped?'
788
- #
789
- # convert a string to an integer of any base
790
- #
791
- def strtod(s, opts = {})
792
- #--{{{
793
- base = Util::getopt 'base', opts, 10
794
- case base
795
- when 2
796
- s = "0b#{ s }" unless s =~ %r/^0b\d/
797
- when 8
798
- s = "0#{ s }" unless s =~ %r/^0\d/
799
- when 16
800
- s = "0x#{ s }" unless s =~ %r/^0x\d/
801
- end
802
- Integer s
803
- #--}}}
804
- end
805
- export 'strtod'
806
- #
807
- # convert a string to an integer
808
- #
809
- def atoi(s, opts = {})
810
- #--{{{
811
- strtod("#{ s }".gsub(%r/^0+/,''), 'base' => 10)
812
- #--}}}
813
- end
814
- export 'atoi'
815
- #
816
- # bin a integer into a int range using modulo logic
817
- #
818
- def rangemod n, ir
819
- #--{{{
820
- a, b = Integer(ir.first), Integer(ir.last)
821
- a, b = b, a if a >= b
822
- exclusive = ir.exclude_end?
823
- size = b - a
824
- size += 1 unless exclusive
825
- offset = a - 0
826
- x = (n + offset).modulo size
827
- x += offset
828
- #--}}}
829
- end
830
- #
831
- # bin a integer into a int range using modulo logic
832
- #
833
- def rangemod n, ir
834
- #--{{{
835
- a, b = [ir.first.to_i, ir.last.to_i].sort
836
- b += 1 if ir.exclude_end?
837
- size = b - a
838
- if n < a
839
- v = n - a
840
- d = v.abs
841
- r = d % size
842
- n = b - r
843
- elsif n > b
844
- v = n - b
845
- d = v.abs
846
- r = d % size
847
- n = a + r
848
- end
849
- raise "failed to rangemod #{ n } => #{ ir }" unless
850
- ir.include? n
851
- n
852
- #--}}}
853
- end
854
- export 'rangemod'
855
- #
856
- # explode a
857
- #
858
- def hms seconds
859
- #--{{{
860
- [
861
- Integer(seconds / 3600),
862
- Integer((seconds % 3600) / 60),
863
- Float((seconds % 3600) / 60.0)
864
- ]
865
- #--}}}
866
- end
867
- export 'hms'
868
- #
869
- # expand variables in a string destructively (to the string)
870
- #
871
- def expand! string, vars = {}
872
- #--{{{
873
- loop do
874
- changed = false
875
- vars.each do |var, value|
876
- var.gsub! %r/[^a-zA-Z0-9_]/, ''
877
- [
878
- %r/\$#{ var }\b/,
879
- %r/\@#{ var }\b/,
880
- %r/\${\s*#{ var }\s*}/,
881
- %r/\@{\s*#{ var }\s*}/
882
- ].each do |pat|
883
- changed = string.gsub! pat, "#{ value }"
884
- end
885
- end
886
- break unless changed
887
- end
888
- string
889
- #--}}}
890
- end
891
- export 'expand!'
892
- def expand string, opts = {}
893
- #--{{{
894
- Util::expand! string.dup, opts
895
- #--}}}
896
- end
897
- export 'expand'
898
- #
899
- # determine path of current ruby interpreter (argv[0] in c)
900
- #
901
- def which_ruby
902
- #--{{{
903
- c = ::Config::CONFIG
904
- File::join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
905
- #--}}}
906
- end
907
- export 'which_ruby'
908
- #
909
- # declare multi-dimensional arrays as in md[2,3,4]
910
- #
911
- def md
912
- #--{{{
913
- @__md__ ||=
914
- lambda{|*ds| Array::new(ds.shift||0).map{md[*ds] unless ds.empty?}}
915
- #--}}}
916
- end
917
- export 'md'
918
- #
919
- # find natural left margin of a here-doc and un-indent it
920
- #
921
- def unindent! s
922
- #--{{{
923
- indent = nil
924
- s.each do |line|
925
- next if line =~ %r/^\s*$/
926
- indent = line[%r/^\s*/] and break
927
- end
928
- s.gsub! %r/^#{ indent }/, "" if indent
929
- indent ? s : nil
930
- #--}}}
931
- end
932
- export 'unindent!'
933
- def unindent s
934
- #--{{{
935
- s = "#{ s }"
936
- Util::unindent! s
937
- s
938
- #--}}}
939
- end
940
- export 'unindent'
941
-
942
-
943
-
944
- #--}}}
945
- end # class Util
946
- ALib::export Util
947
-
948
- #
949
- # the logging module extends classes (both at instance and class level) with
950
- # many methods useful for logging. it relies on the builtin Logger class
951
- #
952
- module Logging
953
- #--{{{
954
- #
955
- # a module that adds an accessor to Logging objects in ored to fix a bug where
956
- # not all logging devices are put into sync mode, resulting in improper log
957
- # rolling. this is a hack.
958
- #
959
- module LoggerExt
960
- #--{{{
961
- attr :logdev
962
- #--}}}
963
- end # module LoggerExt
964
- #
965
- # implementations of the methods shared by both classes and objects of classes
966
- # which include Logging
967
- #
968
- module LogMethods
969
- #--{{{
970
- def __logger_mutex
971
- #--{{{
972
- unless defined?(@__logger_mutex) and @__logger_mutex
973
- begin
974
- Thread.critical = true
975
- @__logger_mutex = Sync::new unless defined?(@__logger_mutex) and @__logger_mutex
976
- ensure
977
- Thread.critical = false
978
- end
979
- end
980
- @__logger_mutex
981
- #--}}}
982
- end
983
- def __logger_sync
984
- #--{{{
985
- __logger_mutex.synchronize{ yield }
986
- #--}}}
987
- end
988
- def logger
989
- #--{{{
990
- return @logger if defined?(@logger)
991
- __logger_sync do
992
- unless defined?(@logger)
993
- klass = Class === self ? self : self::class
994
- self.logger = klass::default_logger
995
- end
996
- end
997
- @logger
998
- #--}}}
999
- end
1000
- def logger= log
1001
- #--{{{
1002
- __logger_sync do
1003
- @logger = log
1004
- @logger.extend LoggerExt
1005
- @logger.logdev.dev.sync = true rescue nil
1006
- @logger
1007
- end
1008
- #--}}}
1009
- end
1010
- %w( debug info warn error fatal ).each do |meth|
1011
- module_eval <<-code
1012
- def #{ meth }(*a, &b)
1013
- __logger_sync{ logger.#{ meth }(*a, &b) }
1014
- end
1015
- code
1016
- end
1017
- def log_err e
1018
- #--{{{
1019
- if logger.debug?
1020
- error{ errmsg e }
1021
- else
1022
- error{ emsg e }
1023
- end
1024
- #--}}}
1025
- end
1026
- def emsg e
1027
- #--{{{
1028
- "#{ e.message } - (#{ e.class })"
1029
- #--}}}
1030
- end
1031
- def btrace e
1032
- #--{{{
1033
- e.backtrace.join("\n")
1034
- #--}}}
1035
- end
1036
- def errmsg e
1037
- #--{{{
1038
- emsg(e) << "\n" << btrace(e)
1039
- #--}}}
1040
- end
1041
- #--}}}
1042
- end # module LogMethods
1043
-
1044
- module LogClassMethods
1045
- #--{{{
1046
- def default_logger
1047
- #--{{{
1048
- return @default_logger if defined?(@default_logger)
1049
- __logger_sync do
1050
- unless defined?(@default_logger)
1051
- self.default_logger = Logger.new STDERR
1052
- # @default_logger.warn{ "<#{ self }> using default logger"}
1053
- end
1054
- end
1055
- @default_logger
1056
- #--}}}
1057
- end
1058
- def default_logger= log
1059
- #--{{{
1060
- __logger_sync do
1061
- @default_logger = (Logger === log ? log : Logger::new(log))
1062
- @default_logger.extend LoggerExt
1063
- @default_logger.logdev.dev.sync = true rescue nil
1064
- @default_logger
1065
- end
1066
- #--}}}
1067
- end
1068
- #--}}}
1069
- end
1070
-
1071
- EOL = "\n"
1072
- DIV0 = ("." * 79) << EOL
1073
- DIV1 = ("-" * 79) << EOL
1074
- DIV2 = ("=" * 79) << EOL
1075
- DIV3 = ("#" * 79) << EOL
1076
- SEC0 = ("." * 16) << EOL
1077
- SEC1 = ("-" * 16) << EOL
1078
- SEC2 = ("=" * 16) << EOL
1079
- SEC3 = ("#" * 16) << EOL
1080
-
1081
- class << self
1082
- #--{{{
1083
- def append_features c
1084
- #--{{{
1085
- ret = super
1086
- c.extend LogMethods
1087
- c.extend LogClassMethods
1088
- ret
1089
- #--}}}
1090
- end
1091
- #--}}}
1092
- end
1093
- include LogMethods
1094
- #--}}}
1095
- end # module Logging
1096
- ALib::export Logging
1097
-
1098
- #
1099
- # yaml configfile class
1100
- #
1101
- class ConfigFile < ::Hash
1102
- #--{{{
1103
- DEFAULT_CONIFG = {}
1104
- DEFAULT_SEARCH_PATH = %w(. ~ /usr/local/etc /usr/etc /etc)
1105
- DEFAULT_BASENAME = ".#{ File::basename $0 }.conf"
1106
-
1107
- class << self
1108
- #--{{{
1109
- attr :config, true
1110
- attr :search_path, true
1111
- attr :basename, true
1112
- attr :default_text, true
1113
- def init
1114
- #--{{{
1115
- @config = DEFAULT_CONIFG
1116
- @search_path = DEFAULT_SEARCH_PATH
1117
- @basename = DEFAULT_BASENAME
1118
- #--}}}
1119
- end
1120
- def gen_template port = nil
1121
- #--{{{
1122
- port ||= STDOUT
1123
- buf = @default_text || @config.to_yaml
1124
- if port.respond_to? 'write'
1125
- port.write buf
1126
- port.write "\n"
1127
- else
1128
- open("#{ port }", 'w'){|f| f.puts buf}
1129
- end
1130
- #--}}}
1131
- end
1132
- def default= conf
1133
- #--{{{
1134
- if conf.respond_to?('read')
1135
- @default_text = munge conf.read
1136
- @config = YAML::load @default_text
1137
- else
1138
- case conf
1139
- when Hash
1140
- @config = conf
1141
- when Pathname
1142
- open(conf) do |f|
1143
- @default_text = munge f.read
1144
- @config = YAML::load @default_text
1145
- end
1146
- when String
1147
- @default_text = munge conf
1148
- @config = YAML::load @default_text
1149
- end
1150
- end
1151
- @config
1152
- #--}}}
1153
- end
1154
- alias set_default default=
1155
- def default(*a)
1156
- #--{{{
1157
- if a.empty?
1158
- @config ||= {}
1159
- else
1160
- self.default= a.first
1161
- end
1162
- #--}}}
1163
- end
1164
- def any(basename = @basename, *dirnames)
1165
- #--{{{
1166
- config = nil
1167
- dirnames = @search_path if dirnames.empty?
1168
- dirnames.each do |dirname|
1169
- path = File::join dirname, basename
1170
- path = File::expand_path path
1171
- if test ?e, path
1172
- config = self::new path
1173
- break
1174
- end
1175
- end
1176
- config || self::new('default')
1177
- #--}}}
1178
- end
1179
- def munge buf
1180
- #--{{{
1181
- buf.gsub(%r/\t/o,' ')
1182
- #--}}}
1183
- end
1184
- #--}}}
1185
- end
1186
- self.init
1187
-
1188
- attr :path
1189
- def initialize path = 'default'
1190
- #--{{{
1191
- @path = nil
1192
- yaml = nil
1193
- if path.nil? or path and path =~ /^\s*default/io
1194
- yaml = self.class.default
1195
- @path = 'DEFAULT'
1196
- else path
1197
- yaml = YAML::load(self.class.munge(open(path).read))
1198
- @path = path
1199
- end
1200
- self.update yaml
1201
- #--}}}
1202
- end
1203
- def to_hash
1204
- #--{{{
1205
- {}.update self
1206
- #--}}}
1207
- end
1208
- #--}}}
1209
- end # class ConfigFile
1210
- Configfile = ConfigFile
1211
- ALib::export ConfigFile
1212
- ALib::export Configfile
1213
-
1214
- #
1215
- # file of lines, comments and blank lines are ignored
1216
- #
1217
- class ListFile < ::Array
1218
- #--{{{
1219
- class << self
1220
- #--{{{
1221
- def parse arg, &b
1222
- #--{{{
1223
- arg.respond_to?('gets') ? loadio(arg, &b) : open("#{ path }"){|f| loadio(f, &b)}
1224
- #--}}}
1225
- end
1226
- def loadio io
1227
- #--{{{
1228
- while((line = io.gets))
1229
- line.gsub!(%r/#.*/o,'')
1230
- next if line =~ %r/^[^\S]+$/o
1231
- line.gsub!(%r/^[^\S]+|[^\S]+$/o,'')
1232
- yield line
1233
- end
1234
- #--}}}
1235
- end
1236
- #--}}}
1237
- end
1238
- attr :path
1239
- def initialize arg
1240
- #--{{{
1241
- case arg
1242
- when Pathname, String
1243
- @path = path
1244
- self.class.parse(arg){|line| self << line}
1245
- when IO
1246
- @path = arg.respond_to?('path') ? arg.path : arg.to_s
1247
- self.class.loadio(arg){|line| self << line}
1248
- else
1249
- raise "cannot initialize from <#{ arg.inspect }>"
1250
- end
1251
- #--}}}
1252
- end
1253
- #--}}}
1254
- end # class ListFile
1255
- Listfile = ListFile
1256
- ALib::export ListFile
1257
- ALib::export Listfile
1258
-
1259
- #
1260
- # auto vivifying hash that dumps as yaml nicely
1261
- #
1262
- class AutoHash < ::Hash
1263
- #--{{{
1264
- def initialize(*args)
1265
- #--{{{
1266
- super(*args){|a,k| a[k] = AutoHash::new(*args)}
1267
- #--}}}
1268
- end
1269
- def class
1270
- #--{{{
1271
- Hash
1272
- #--}}}
1273
- end
1274
- #--}}}
1275
- end # class AutoHash
1276
- ALib::export AutoHash
1277
-
1278
- # AUTHOR
1279
- # jan molic /mig/at/1984/dot/cz/
1280
- #
1281
- # DESCRIPTION
1282
- # Hash with preserved order and some array-like extensions
1283
- # Public domain.
1284
- #
1285
- # THANKS
1286
- # Andrew Johnson for his suggestions and fixes of Hash[],
1287
- # merge, to_a, inspect and shift
1288
- class OrderedHash < Hash
1289
- #--{{{
1290
- attr_accessor :order
1291
-
1292
- class << self
1293
- #--{{{
1294
- def [] *args
1295
- #--{{{
1296
- hsh = OrderedHash.new
1297
- if Hash === args[0]
1298
- hsh.replace args[0]
1299
- elsif (args.size % 2) != 0
1300
- raise ArgumentError, "odd number of elements for Hash"
1301
- else
1302
- hsh[args.shift] = args.shift while args.size > 0
1303
- end
1304
- hsh
1305
- #--}}}
1306
- end
1307
- #--}}}
1308
- end
1309
- # def initialize
1310
- ##--{{{
1311
- # @order = []
1312
- ##--}}}
1313
- # end
1314
- def initialize(*a, &b)
1315
- #--{{{
1316
- super
1317
- @order = []
1318
- #--}}}
1319
- end
1320
- def store_only a,b
1321
- #--{{{
1322
- store a,b
1323
- #--}}}
1324
- end
1325
- alias orig_store store
1326
- def store a,b
1327
- #--{{{
1328
- @order.push a unless has_key? a
1329
- super a,b
1330
- #--}}}
1331
- end
1332
- alias []= store
1333
- def == hsh2
1334
- #--{{{
1335
- return false if @order != hsh2.order
1336
- super hsh2
1337
- #--}}}
1338
- end
1339
- def clear
1340
- #--{{{
1341
- @order = []
1342
- super
1343
- #--}}}
1344
- end
1345
- def delete key
1346
- #--{{{
1347
- @order.delete key
1348
- super
1349
- #--}}}
1350
- end
1351
- def each_key
1352
- #--{{{
1353
- @order.each { |k| yield k }
1354
- self
1355
- #--}}}
1356
- end
1357
- def each_value
1358
- #--{{{
1359
- @order.each { |k| yield self[k] }
1360
- self
1361
- #--}}}
1362
- end
1363
- def each
1364
- #--{{{
1365
- @order.each { |k| yield k,self[k] }
1366
- self
1367
- #--}}}
1368
- end
1369
- alias each_pair each
1370
- def delete_if
1371
- #--{{{
1372
- @order.clone.each { |k|
1373
- delete k if yield
1374
- }
1375
- self
1376
- #--}}}
1377
- end
1378
- def values
1379
- #--{{{
1380
- ary = []
1381
- @order.each { |k| ary.push self[k] }
1382
- ary
1383
- #--}}}
1384
- end
1385
- def keys
1386
- #--{{{
1387
- @order
1388
- #--}}}
1389
- end
1390
- def invert
1391
- #--{{{
1392
- hsh2 = Hash.new
1393
- @order.each { |k| hsh2[self[k]] = k }
1394
- hsh2
1395
- #--}}}
1396
- end
1397
- def reject &block
1398
- #--{{{
1399
- self.dup.delete_if &block
1400
- #--}}}
1401
- end
1402
- def reject! &block
1403
- #--{{{
1404
- hsh2 = reject &block
1405
- self == hsh2 ? nil : hsh2
1406
- #--}}}
1407
- end
1408
- def replace hsh2
1409
- #--{{{
1410
- @order = hsh2.keys
1411
- super hsh2
1412
- #--}}}
1413
- end
1414
- def shift
1415
- #--{{{
1416
- key = @order.first
1417
- key ? [key,delete(key)] : super
1418
- #--}}}
1419
- end
1420
- def unshift k,v
1421
- #--{{{
1422
- unless self.include? k
1423
- @order.unshift k
1424
- orig_store(k,v)
1425
- true
1426
- else
1427
- false
1428
- end
1429
- #--}}}
1430
- end
1431
- def push k,v
1432
- #--{{{
1433
- unless self.include? k
1434
- @order.push k
1435
- orig_store(k,v)
1436
- true
1437
- else
1438
- false
1439
- end
1440
- #--}}}
1441
- end
1442
- def pop
1443
- #--{{{
1444
- key = @order.last
1445
- key ? [key,delete(key)] : nil
1446
- #--}}}
1447
- end
1448
- def to_a
1449
- #--{{{
1450
- ary = []
1451
- each { |k,v| ary << [k,v] }
1452
- ary
1453
- #--}}}
1454
- end
1455
- def to_s
1456
- #--{{{
1457
- self.to_a.to_s
1458
- #--}}}
1459
- end
1460
- def inspect
1461
- #--{{{
1462
- ary = []
1463
- each {|k,v| ary << k.inspect + "=>" + v.inspect}
1464
- '{' + ary.join(", ") + '}'
1465
- #--}}}
1466
- end
1467
- def update hsh2
1468
- #--{{{
1469
- hsh2.each { |k,v| self[k] = v }
1470
- self
1471
- #--}}}
1472
- end
1473
- alias :merge! update
1474
- def merge hsh2
1475
- #--{{{
1476
- self.dup update(hsh2)
1477
- #--}}}
1478
- end
1479
- def select
1480
- #--{{{
1481
- ary = []
1482
- each { |k,v| ary << [k,v] if yield k,v }
1483
- ary
1484
- #--}}}
1485
- end
1486
- def class
1487
- #--{{{
1488
- Hash
1489
- #--}}}
1490
- end
1491
- #--}}}
1492
- end # class OrderedHash
1493
- ALib::export OrderedHash
1494
-
1495
- #
1496
- # auto vivifying ordered hash that dumps as yaml nicely
1497
- #
1498
- class AutoOrderedHash < OrderedHash
1499
- #--{{{
1500
- def initialize(*args)
1501
- #--{{{
1502
- super(*args){|a,k| a[k] = AutoHash::new(*args)}
1503
- #--}}}
1504
- end
1505
- def class
1506
- #--{{{
1507
- Hash
1508
- #--}}}
1509
- end
1510
- #--}}}
1511
- end # class AutoOrderedHash
1512
- OrderedAutoHash = AutoOrderedHash
1513
- ALib::export OrderedAutoHash
1514
- ALib::export AutoOrderedHash
1515
-
1516
- # -*- Ruby -*-
1517
- # Copyright (C) 1998, 2001 Motoyuki Kasahara
1518
- #
1519
- # This program is free software; you can redistribute it and/or modify
1520
- # it under the terms of the GNU General Public License as published by
1521
- # the Free Software Foundation; either version 2, or (at your option)
1522
- # any later version.
1523
- #
1524
- # This program is distributed in the hope that it will be useful,
1525
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
1526
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1527
- # GNU General Public License for more details.
1528
- #
1529
- #
1530
- # Traverse a file tree, replacement of `find.rb'.
1531
- #
1532
- class Find2
1533
- #--{{{
1534
- #
1535
- # Constatnts
1536
- #
1537
- FIND1 = 1
1538
- FIND2 = 2
1539
- #
1540
- # Initializer.
1541
- #
1542
- def initialize(mode = FIND1)
1543
- #--{{{
1544
- @mode = mode
1545
- @depth = false
1546
- @follow = false
1547
- @xdev = false
1548
-
1549
- @dirname_stats = Array.new
1550
- @found_files = Array.new
1551
- @target_device = 0
1552
-
1553
- @handle = lambda { |file, stat_result, block|
1554
- case @mode
1555
- when FIND1
1556
- block ? block.call(file) : @found_files.push(file)
1557
- when FIND2
1558
- block ? block.call(file, stat_result) : @found_files.push([file, stat_result])
1559
- end
1560
- }
1561
- #--}}}
1562
- end
1563
- #
1564
- # Methods for accessing instances.
1565
- #
1566
- attr :depth
1567
- attr :follow
1568
- attr :xdev
1569
- #
1570
- # Find the directory `dirname'. (private)
1571
- #
1572
- def find(*arguments, &block)
1573
- #--{{{
1574
- #
1575
- # Parse options if specified.
1576
- #
1577
- #if arguments[0].type == Hash
1578
- #parse_options(arguments.shift)
1579
- #end
1580
-
1581
- # hack
1582
- args = []
1583
- opts = []
1584
- arguments.each do |arg|
1585
- case arg
1586
- when Hash
1587
- opts << arg
1588
- else
1589
- args << arg
1590
- end
1591
- end
1592
- opts.each{|opt| parse_options opt}
1593
- files = args.flatten.compact
1594
-
1595
- #
1596
- # If a block is not given to the `find' method, found files are
1597
- # recorded in this array.
1598
- #
1599
- @dirname_stats.clear
1600
- @found_files.clear
1601
-
1602
- #
1603
- # Loop for each file in `files'.
1604
- #
1605
- files.each do |file|
1606
- catch(:prune) do
1607
- @dirname_stats.clear
1608
-
1609
- #
1610
- # Get `stat' or `lstat' of `file'.
1611
- #
1612
- begin
1613
- if @follow
1614
- begin
1615
- stat_result = File.stat(file)
1616
- rescue Errno::ENOENT, Errno::EACCES
1617
- stat_result = File.lstat(file)
1618
- end
1619
- else
1620
- stat_result = File.lstat(file)
1621
- end
1622
- rescue Errno::ENOENT, Errno::EACCES
1623
- next
1624
- end
1625
-
1626
- #
1627
- # Push `file' to the found stack, or yield with it,
1628
- # if the depth flag is enabled.
1629
- #
1630
- @handle[ file, stat_result, block ] if !@depth
1631
-
1632
- #
1633
- # If `file' is a directory, find files recursively.
1634
- #
1635
- if stat_result.directory?
1636
- @xdev_device = stat_result.dev if @xdev
1637
- @dirname_stats.push(stat_result)
1638
- find_directory(file, block)
1639
- end
1640
-
1641
- #
1642
- # Push `file' to the found stack, or yield with it.
1643
- # if the depth flag is disabled.
1644
- #
1645
- @handle[ file, stat_result, block ] if @depth
1646
-
1647
- end
1648
- end
1649
-
1650
- if block == nil
1651
- return @found_files
1652
- else
1653
- return nil
1654
- end
1655
- #--}}}
1656
- end
1657
- #
1658
- # Find the directory `dirname'. (private)
1659
- #
1660
- def find_directory(dirname, block)
1661
- #--{{{
1662
- #
1663
- # Open the directory `dirname'.
1664
- #
1665
- begin
1666
- dir = Dir.open(dirname)
1667
- rescue
1668
- return
1669
- end
1670
-
1671
- #
1672
- # Read all directory entries except for `.' and `..'.
1673
- #
1674
- entries = Array.new
1675
- loop do
1676
- begin
1677
- entry = dir.read
1678
- rescue
1679
- break
1680
- end
1681
- break if entry == nil
1682
- next if entry == '.' || entry == '..'
1683
- entries.push(entry)
1684
- end
1685
-
1686
- #
1687
- # Close `dir'.
1688
- #
1689
- dir.close
1690
-
1691
- #
1692
- # Loop for each entry in this directory.
1693
- #
1694
- catch(:prune) do
1695
- entries.each do |entry|
1696
- #
1697
- # Set `entry_path' to the full path of `entry'.
1698
- #
1699
- if dirname[-1, 1] == File::Separator
1700
- entry_path = dirname + entry
1701
- else
1702
- entry_path = dirname + File::Separator + entry
1703
- end
1704
-
1705
- #
1706
- # Get `stat' or `lstat' of `entry_path'.
1707
- #
1708
- begin
1709
- if @follow
1710
- begin
1711
- stat_result = File.stat(entry_path)
1712
- rescue Errno::ENOENT, Errno::EACCES
1713
- stat_result = File.lstat(entry_path)
1714
- end
1715
- else
1716
- stat_result = File.lstat(entry_path)
1717
- end
1718
- rescue Errno::ENOENT, Errno::EACCES
1719
- next
1720
- end
1721
-
1722
- #
1723
- # Push `entry_path' to the found stack, or yield with it,
1724
- # if the depth flag is enabled.
1725
- #
1726
-
1727
- @handle[ entry_path, stat_result, block ] if !@depth
1728
-
1729
- #
1730
- # If `entry_path' is a directory, find recursively.
1731
- #
1732
- if stat_result.directory? \
1733
- && (!@xdev || @xdev_device == stat_result.dev) \
1734
- && (!@follow || !visited?(stat_result))
1735
- @dirname_stats.push(stat_result)
1736
- find_directory(entry_path, block)
1737
- @dirname_stats.pop
1738
- end
1739
-
1740
- #
1741
- # Push `entry_path' to the found stack, or yield with it,
1742
- # if the depth flag is disabled.
1743
- #
1744
- @handle[ entry_path, stat_result, block ] if @depth
1745
-
1746
- end
1747
- end
1748
- #--}}}
1749
- end
1750
- private :find_directory
1751
- #
1752
- # Find the directory `dirname'. (class method)
1753
- #
1754
- def Find2.find(*arguments, &block)
1755
- Find2.new.find(*arguments, &block)
1756
- end
1757
- #
1758
- # Find the directory `dirname'. (class method)
1759
- #
1760
- def Find2.find2(*arguments, &block)
1761
- Find2.new(FIND2).find(*arguments, &block)
1762
- end
1763
- #
1764
- # Parse options.
1765
- #
1766
- def parse_options(options)
1767
- #--{{{
1768
- return if options == nil
1769
-
1770
- options.each_pair do |key, value|
1771
- case "#{ key }".strip.downcase
1772
- when 'depth'
1773
- @depth = value
1774
- when 'follow'
1775
- @follow = value
1776
- when 'xdev'
1777
- @xdev = value
1778
- else
1779
- raise ArgumentError, "unknown option - #{key}"
1780
- end
1781
- end
1782
- #--}}}
1783
- end
1784
- private :parse_options
1785
- #
1786
- # Prune the current visited directory.
1787
- #
1788
- def Find2.prune
1789
- #--{{{
1790
- throw :prune
1791
- #--}}}
1792
- end
1793
- #
1794
- # Did we visit the directory with the resouce `stat'? (private)
1795
- #
1796
- def visited?(stat_result)
1797
- #--{{{
1798
- dev = stat_result.dev
1799
- ino = stat_result.ino
1800
- @dirname_stats.each do |i|
1801
- return TRUE if i.dev == dev && i.ino == ino
1802
- end
1803
- return FALSE
1804
- #--}}}
1805
- end
1806
- private :visited?
1807
- #--}}}
1808
- end # class Find2
1809
- Find = Find2
1810
- ALib::export Find
1811
- ALib::export Find2
1812
-
1813
- #
1814
- # Ruby/Bsearch - a binary search library for Ruby.
1815
- #
1816
- # Copyright (C) 2001 Satoru Takabayashi <satoru@namazu.org>
1817
- # All rights reserved.
1818
- # This is free software with ABSOLUTELY NO WARRANTY.
1819
- #
1820
- # You can redistribute it and/or modify it under the terms of
1821
- # the Ruby's licence.
1822
- #
1823
- # Example:
1824
- #
1825
- # % irb -r ./bsearch.rb
1826
- # >> %w(a b c c c d e f).bsearch_first {|x| x <=> "c"}
1827
- # => 2
1828
- # >> %w(a b c c c d e f).bsearch_last {|x| x <=> "c"}
1829
- # => 4
1830
- # >> %w(a b c e f).bsearch_first {|x| x <=> "c"}
1831
- # => 2
1832
- # >> %w(a b e f).bsearch_first {|x| x <=> "c"}
1833
- # => nil
1834
- # >> %w(a b e f).bsearch_last {|x| x <=> "c"}
1835
- # => nil
1836
- # >> %w(a b e f).bsearch_lower_boundary {|x| x <=> "c"}
1837
- # => 2
1838
- # >> %w(a b e f).bsearch_upper_boundary {|x| x <=> "c"}
1839
- # => 2
1840
- # >> %w(a b c c c d e f).bsearch_range {|x| x <=> "c"}
1841
- # => 2...5
1842
- # >> %w(a b c d e f).bsearch_range {|x| x <=> "c"}
1843
- # => 2...3
1844
- # >> %w(a b d e f).bsearch_range {|x| x <=> "c"}
1845
- # => 2...2
1846
-
1847
- module Bsearch
1848
- #--{{{
1849
- VERSION = '1.5'
1850
-
1851
- module BsearchMethods
1852
- #--{{{
1853
- #
1854
- # The binary search algorithm is extracted from Jon Bentley's
1855
- # Programming Pearls 2nd ed. p.93
1856
- #
1857
-
1858
- #
1859
- # Return the lower boundary. (inside)
1860
- #
1861
- # old
1862
- def bsearch_lower_boundary (range = 0 ... self.length, &block)
1863
- #--{{{
1864
- lower = range.first() -1
1865
- upper = if range.exclude_end? then range.last else range.last + 1 end
1866
- while lower + 1 != upper
1867
- mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
1868
- if yield(self[mid]) < 0
1869
- lower = mid
1870
- else
1871
- upper = mid
1872
- end
1873
- end
1874
- return upper
1875
- #--}}}
1876
- end
1877
- # new
1878
- def bsearch_lower_boundary (arg = nil, &block)
1879
- #--{{{
1880
- range = nil
1881
- if arg and not block
1882
- block = lambda{|x| x <=> arg}
1883
- range = 0 ... self.length
1884
- end
1885
- range ||= (arg ? arg : (0...self.length))
1886
-
1887
- lower = range.first() -1
1888
- upper = if range.exclude_end? then range.last else range.last + 1 end
1889
- while lower + 1 != upper
1890
- mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
1891
- if block[ self[mid] ] < 0
1892
- lower = mid
1893
- else
1894
- upper = mid
1895
- end
1896
- end
1897
- return upper
1898
- #--}}}
1899
- end
1900
-
1901
- #
1902
- # This method searches the FIRST occurrence which satisfies a
1903
- # condition given by a block in binary fashion and return the
1904
- # index of the first occurrence. Return nil if not found.
1905
- #
1906
- # old
1907
- def bsearch_first (range = 0 ... self.length, &block)
1908
- #--{{{
1909
- boundary = bsearch_lower_boundary(range, &block)
1910
- if boundary >= self.length || yield(self[boundary]) != 0
1911
- return nil
1912
- else
1913
- return boundary
1914
- end
1915
- #--}}}
1916
- end
1917
- # new
1918
- def bsearch_first (arg = nil, &block)
1919
- #--{{{
1920
- range = nil
1921
- if arg and not block
1922
- block = lambda{|x| x <=> arg}
1923
- range = 0 ... self.length
1924
- end
1925
- range ||= (arg ? arg : (0...self.length))
1926
- boundary = bsearch_lower_boundary(range, &block)
1927
- if boundary >= self.length || block[ self[boundary] ] != 0
1928
- return nil
1929
- else
1930
- return boundary
1931
- end
1932
- #--}}}
1933
- end
1934
-
1935
- # alias bsearch bsearch_first
1936
- def bsearch(*a, &b)
1937
- #--{{{
1938
- unless b
1939
- obj = a.first
1940
- b = lambda{|x| x <=> obj}
1941
- bsearch_first(&b)
1942
- else
1943
- bsearch_first(*a, &b)
1944
- end
1945
- #--}}}
1946
- end
1947
- #
1948
- # Return the upper boundary. (outside)
1949
- #
1950
- # old
1951
- def bsearch_upper_boundary (range = 0 ... self.length, &block)
1952
- #--{{{
1953
- lower = range.first() -1
1954
- upper = if range.exclude_end? then range.last else range.last + 1 end
1955
- while lower + 1 != upper
1956
- mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
1957
- if yield(self[mid]) <= 0
1958
- lower = mid
1959
- else
1960
- upper = mid
1961
- end
1962
- end
1963
- return lower + 1 # outside of the matching range.
1964
- #--}}}
1965
- end
1966
- # new
1967
- def bsearch_upper_boundary (arg = nil, &block)
1968
- #--{{{
1969
- range = nil
1970
- if arg and not block
1971
- block = lambda{|x| x <=> arg}
1972
- range = 0 ... self.length
1973
- end
1974
- range ||= (arg ? arg : (0...self.length))
1975
-
1976
- lower = range.first() -1
1977
- upper = if range.exclude_end? then range.last else range.last + 1 end
1978
- while lower + 1 != upper
1979
- mid = ((lower + upper) / 2).to_i # for working with mathn.rb (Rational)
1980
- if block[ self[mid] ] <= 0
1981
- lower = mid
1982
- else
1983
- upper = mid
1984
- end
1985
- end
1986
- return lower + 1 # outside of the matching range.
1987
- #--}}}
1988
- end
1989
- #
1990
- # This method searches the LAST occurrence which satisfies a
1991
- # condition given by a block in binary fashion and return the
1992
- # index of the last occurrence. Return nil if not found.
1993
- #
1994
- # old
1995
- def bsearch_last (range = 0 ... self.length, &block)
1996
- #--{{{
1997
- # `- 1' for canceling `lower + 1' in bsearch_upper_boundary.
1998
- boundary = bsearch_upper_boundary(range, &block) - 1
1999
-
2000
- if (boundary <= -1 || yield(self[boundary]) != 0)
2001
- return nil
2002
- else
2003
- return boundary
2004
- end
2005
- #--}}}
2006
- end
2007
- # new
2008
- def bsearch_last (arg = nil, &block)
2009
- #--{{{
2010
- range = nil
2011
- if arg and not block
2012
- block = lambda{|x| x <=> arg}
2013
- range = 0 ... self.length
2014
- end
2015
- range ||= (arg ? arg : (0...self.length))
2016
-
2017
- # `- 1' for canceling `lower + 1' in bsearch_upper_boundary.
2018
- boundary = bsearch_upper_boundary(range, &block) - 1
2019
-
2020
- if (boundary <= -1 || block[ self[boundary] ] != 0)
2021
- return nil
2022
- else
2023
- return boundary
2024
- end
2025
- #--}}}
2026
- end
2027
- #
2028
- # Return the search result as a Range object.
2029
- #
2030
- # old
2031
- def bsearch_range (range = 0 ... self.length, &block)
2032
- #--{{{
2033
- lower = bsearch_lower_boundary(range, &block)
2034
- upper = bsearch_upper_boundary(range, &block)
2035
- return lower ... upper
2036
- #--}}}
2037
- end
2038
- # new
2039
- def bsearch_range (arg = nil, &block)
2040
- #--{{{
2041
- range = nil
2042
- if arg and not block
2043
- block = lambda{|x| x <=> arg}
2044
- range = 0 ... self.length
2045
- end
2046
- range ||= (arg ? arg : (0...self.length))
2047
-
2048
- lower = bsearch_lower_boundary(range, &block)
2049
- upper = bsearch_upper_boundary(range, &block)
2050
- return lower ... upper
2051
- #--}}}
2052
- end
2053
- #--}}}
2054
- end
2055
-
2056
- if false
2057
- def Bsearch::append_features klass
2058
- #--{{{
2059
- ::Array.module_eval{ include BsearchMethods }
2060
- super
2061
- #--}}}
2062
- end
2063
- end
2064
- ::Array.module_eval{ include BsearchMethods }
2065
- #--}}}
2066
- end # module Bsearch
2067
- BSearch = Bsearch
2068
- ALib::export BSearch
2069
- ALib::export Bsearch
2070
-
2071
- #
2072
- # template main building block classes
2073
- #
2074
-
2075
- module MainModule
2076
- #--{{{
2077
- module Mixins
2078
- #--{{{
2079
- include ALib
2080
- include ALib::Logging
2081
- #--}}}
2082
- end
2083
- module Constants
2084
- #--{{{
2085
- EXIT_SUCCESS = 0
2086
- EXIT_FAILURE = 1
2087
- #--}}}
2088
- end
2089
- module ClassMethods
2090
- #--{{{
2091
- include Mixins
2092
- include Constants
2093
- def stringlist(*list)
2094
- #--{{{
2095
- list.flatten.compact.map{|item| "#{ item }".strip}
2096
- #--}}}
2097
- end
2098
-
2099
- def instance_attributes(*names)
2100
- #--{{{
2101
- names = stringlist names
2102
- names.each do |name|
2103
- getter = "#{ name }"
2104
- setter = "#{ name }="
2105
- code = <<-code
2106
- def #{ name }(*a)
2107
- unless a.empty?
2108
- self.#{ name }= a.shift
2109
- else
2110
- @#{ name }
2111
- end
2112
- end
2113
- def #{ name }= value
2114
- @#{ name } = value
2115
- end
2116
- alias #{ name }? #{ name }
2117
- code
2118
- module_eval code
2119
- end
2120
- #--}}}
2121
- end
2122
- alias instance_attribute instance_attributes
2123
- alias i_attrs instance_attributes
2124
- alias i_attr instance_attributes
2125
- alias attribute instance_attributes
2126
- alias attributes instance_attributes
2127
-
2128
- def class_attributes(*names)
2129
- #--{{{
2130
- names = stringlist names
2131
- names.each do |name|
2132
- getter = "#{ name }"
2133
- setter = "#{ name }="
2134
- code = <<-code
2135
- class << self
2136
- def #{ name }(*a)
2137
- unless a.empty?
2138
- self.#{ name }= a.shift
2139
- else
2140
- @#{ name }
2141
- end
2142
- end
2143
- def #{ name }= value
2144
- @#{ name } = value
2145
- end
2146
- alias #{ name }? #{ name }
2147
- end
2148
- code
2149
- module_eval code
2150
- end
2151
- #--}}}
2152
- end
2153
- alias class_attribute class_attributes
2154
- alias c_attrs class_attributes
2155
- alias c_attr class_attributes
2156
-
2157
- %w( version author program optspec ).each do |meth|
2158
- #--{{{
2159
- module_eval <<-code
2160
- def #{ meth }(*a)
2161
- unless a.empty?
2162
- self.#{ meth }= a.shift
2163
- else
2164
- @#{ meth }
2165
- end
2166
- end
2167
- def #{ meth }= value
2168
- @#{ meth } = value
2169
- end
2170
- def #{ meth }?
2171
- defined? @#{ meth } and @#{ meth }
2172
- end
2173
- code
2174
- #--}}}
2175
- end
2176
- alias prognam program
2177
- alias prognam= program=
2178
- alias prognam? program?
2179
-
2180
- %w( usage examples ).each do |meth|
2181
- #--{{{
2182
- module_eval <<-code
2183
- def #{ meth }(*a)
2184
- unless a.empty?
2185
- self.#{ meth }= a.shift
2186
- else
2187
- @#{ meth }
2188
- end
2189
- end
2190
- def #{ meth }= msg
2191
- @#{ meth } = unindent_block msg
2192
- end
2193
- def #{ meth }?
2194
- defined? @#{ meth } and @#{ meth }
2195
- end
2196
- code
2197
- #--}}}
2198
- end
2199
-
2200
- def unindent_block buf
2201
- #--{{{
2202
- buf = "#{ buf }"
2203
- lines = buf.to_a
2204
- indent_pat = %r/^\s*[\s|]/
2205
- indent = lines.first[ indent_pat ]
2206
- if indent
2207
- lines.map do |line|
2208
- line[ indent.size..-1 ] || "\n"
2209
- end.join
2210
- else
2211
- buf
2212
- end
2213
- #--}}}
2214
- end
2215
-
2216
- def options(*list)
2217
- #--{{{
2218
- @optspec ||= []
2219
- return @optspec if list.empty?
2220
- list = [list] unless Array === list.first
2221
- list.each{|spec| (@optspec ||= []) << spec}
2222
- #--}}}
2223
- end
2224
- alias option options
2225
-
2226
- def required_arguments(*list)
2227
- #--{{{
2228
- @required_arguments ||= []
2229
- list.flatten.each do |arg|
2230
- return(optional_argument(arg)) if Hash === arg
2231
- unless instance_methods.include? "#{ arg }"
2232
- module_eval <<-code
2233
- def #{ arg }(*__list)
2234
- if __list.empty?
2235
- @#{ arg }
2236
- else
2237
- send('#{ arg }=', *__list)
2238
- end
2239
- end
2240
- def #{ arg }=(__arg, *__list)
2241
- if __list.empty?
2242
- @#{ arg } = __arg
2243
- else
2244
- @#{ arg } = ([__arg] + __list)
2245
- end
2246
- end
2247
- def #{ arg }?
2248
- defined? @#{ arg } and @#{ arg }
2249
- end
2250
- code
2251
- end
2252
- @required_arguments << "#{ arg }"
2253
- end
2254
- @required_arguments
2255
- #--}}}
2256
- end
2257
- alias required_argument required_arguments
2258
- alias arguments required_arguments
2259
- alias argument required_arguments
2260
-
2261
- def optional_arguments(*list)
2262
- #--{{{
2263
- @optional_arguments ||= []
2264
- list.flatten.each do |arg|
2265
- arg, default =
2266
- case arg
2267
- when Hash
2268
- arg.to_a.first
2269
- else
2270
- [arg, nil]
2271
- end
2272
- @do_not_gc ||= []
2273
- @do_not_gc << default unless @do_not_gc.include? default
2274
- unless instance_methods.include? "#{ arg }"
2275
- module_eval <<-code
2276
- def #{ arg }(*__list)
2277
- unless @#{ arg }
2278
- @#{ arg } = ObjectSpace::_id2ref #{ default.object_id }
2279
- end
2280
- if __list.empty?
2281
- @#{ arg }
2282
- else
2283
- send('#{ arg }=', *__list)
2284
- end
2285
- end
2286
- def #{ arg }=(__arg, *__list)
2287
- if __list.empty?
2288
- @#{ arg } = __arg
2289
- else
2290
- @#{ arg } = ([__arg] + __list)
2291
- end
2292
- end
2293
- def #{ arg }?
2294
- defined? @#{ arg } and @#{ arg }
2295
- end
2296
- code
2297
- end
2298
- @optional_arguments << "#{ arg }"
2299
- end
2300
- @optional_arguments
2301
- #--}}}
2302
- end
2303
- alias optional_argument optional_arguments
2304
- def inherited klass
2305
- #--{{{
2306
- ret = super
2307
- begin; klass.class_initialize; rescue NoMethodError; end
2308
- ret
2309
- #--}}}
2310
- end
2311
- #--}}}
2312
- end
2313
- module InstanceMethods
2314
- #--{{{
2315
- include Mixins
2316
- include Constants
2317
- attr :logger
2318
- attr :program
2319
- attr :argv
2320
- attr :env
2321
- attr :cmdline
2322
- attr :console
2323
- attr :options
2324
- attr :listoptions
2325
- attr :op
2326
- attr :logdev
2327
- attr :verbosity
2328
-
2329
- alias console? console
2330
-
2331
- def initialize argv = ARGV, env = ENV
2332
- #--{{{
2333
- @argv = Util::mcp(argv.to_a)
2334
- @env = Util::mcp(env.to_hash)
2335
- @program = File::expand_path $0
2336
- @cmdline = ([@program] + @argv).join ' '
2337
- @console = STDIN.tty?
2338
- #--}}}
2339
- end
2340
- def klass; self.class; end
2341
- def required_arguments
2342
- #--{{{
2343
- klass::required_arguments
2344
- #--}}}
2345
- end
2346
- def optional_arguments
2347
- #--{{{
2348
- klass::optional_arguments
2349
- #--}}}
2350
- end
2351
-
2352
- def run
2353
- #--{{{
2354
- logcatch do
2355
- begin
2356
- pre_run
2357
- pre_parse_options
2358
- parse_options
2359
- post_parse_options
2360
- if(@options.has_key?('help') or (@argv.size == 1 and @argv.first =~ %r/help/i))
2361
- usage STDOUT
2362
- exit EXIT_SUCCESS
2363
- end
2364
- pre_parse_argv
2365
- parse_argv
2366
- post_parse_argv
2367
- init_logging
2368
- pre_main
2369
- status = main
2370
- post_main
2371
- post_run
2372
- exit(status ? EXIT_SUCCESS : EXIT_FAILURE)
2373
- rescue Errno::EPIPE
2374
- STDOUT.tty? ? raise : exit(EXIT_FAILURE)
2375
- end
2376
- end
2377
- #--}}}
2378
- end
2379
- def pre_parse_options; end
2380
- def post_parse_options; end
2381
- def pre_parse_argv; end
2382
- def post_parse_argv; end
2383
- def pre_run; end
2384
- def post_run; end
2385
- def pre_main; end
2386
- def post_main; end
2387
- def logcatch
2388
- #--{{{
2389
- ret = nil
2390
- @logger ||= Logger::new STDERR
2391
- begin
2392
- ret = yield
2393
- rescue Exception => e
2394
- unless SystemExit === e
2395
- fatal{ e }
2396
- exit EXIT_FAILURE
2397
- if false
2398
- if logger.debug?
2399
- fatal{ e }
2400
- exit EXIT_FAILURE
2401
- else
2402
- fatal{ emsg(e) }
2403
- exit EXIT_FAILURE
2404
- end
2405
- end
2406
- else
2407
- exit e.status
2408
- end
2409
- end
2410
- ret
2411
- #--}}}
2412
- end
2413
- def usage port = STDERR
2414
- #--{{{
2415
- port << klass::usage << "\n" if klass::usage
2416
- port << klass::examples << "\n" if klass::examples
2417
-
2418
- if klass::optspec
2419
- port << 'OPTIONS' << "\n"
2420
-
2421
- klass::optspec.each do |os|
2422
- a, b, c = os
2423
- long, short, desc = nil
2424
- [a,b,c].each do |word|
2425
- next unless word
2426
- word.strip!
2427
- case word
2428
- when %r/^--[^-]/o
2429
- long = word
2430
- when %r/^-[^-]/o
2431
- short = word
2432
- else
2433
- desc = word
2434
- end
2435
- end
2436
-
2437
- spec = ((long and short) ? [long, short] : [long])
2438
-
2439
- if spec
2440
- port << Util::columnize(spec.join(', '), :width => 80, :indent => 2)
2441
- port << "\n"
2442
- end
2443
-
2444
- if desc
2445
- port << Util::columnize(desc, :width => 80, :indent => 8)
2446
- port << "\n"
2447
- end
2448
- end
2449
-
2450
- port << "\n"
2451
- end
2452
-
2453
- port
2454
- #--}}}
2455
- end
2456
- def parse_options
2457
- #--{{{
2458
- @op = OptionParser::new
2459
- @options = {}
2460
- @listoptions = Hash::new{|h,k| h[k] = []}
2461
- klass::optspec.each do |spec|
2462
- k = spec.first.gsub(%r/(?:--)|(?:=.*$)|(?:\s+)/o,'')
2463
- @op.def_option(*spec) do |v|
2464
- @options[k] = v
2465
- @listoptions[k] << v
2466
- end
2467
- end
2468
- #begin
2469
- op.parse! @argv
2470
- #rescue OptionParser::InvalidOption => e
2471
- # preverve unknown options
2472
- #e.recover(argv)
2473
- #end
2474
- @options
2475
- #--}}}
2476
- end
2477
- def init_logging opts = @options
2478
- #--{{{
2479
- log = Util::getopt 'log', opts
2480
- log_age = Util::getopt 'log_age', opts
2481
- log_size = Util::getopt 'log_size', opts
2482
- verbosity = Util::getopt 'verbosity', opts
2483
- log_age = Integer log_age rescue nil
2484
- log_size = Integer log_size rescue nil
2485
- $logger = @logger = Logger::new(log || STDERR, log_age, log_size)
2486
- #
2487
- # hack to fix Logger sync bug
2488
- #
2489
- begin
2490
- class << @logger; attr :logdev unless @logger.respond_to?(:logdev); end
2491
- @logdev = @logger.logdev.dev
2492
- @logdev.sync = true
2493
- rescue
2494
- nil
2495
- end
2496
- level = nil
2497
- verbosity ||= 'info'
2498
- verbosity =
2499
- case verbosity
2500
- when /^\s*(?:4|d|debug)\s*$/io
2501
- level = 'Logging::DEBUG'
2502
- 4
2503
- when /^\s*(?:3|i|info)\s*$/io
2504
- level = 'Logging::INFO'
2505
- 3
2506
- when /^\s*(?:2|w|warn)\s*$/io
2507
- level = 'Logging::WARN'
2508
- 2
2509
- when /^\s*(?:1|e|error)\s*$/io
2510
- level = 'Logging::ERROR'
2511
- 1
2512
- when /^\s*(?:0|f|fatal)\s*$/io
2513
- level = 'Logging::FATAL'
2514
- 0
2515
- else
2516
- abort "illegal verbosity setting <#{ verbosity }>"
2517
- end
2518
- @logger.level = 2 - ((verbosity % 5) - 2)
2519
- @logger
2520
- #--}}}
2521
- end
2522
- def parse_argv
2523
- #--{{{
2524
- a, b = [], []
2525
- klass::required_arguments.each do |arg|
2526
- value = @argv.shift
2527
- if value
2528
- send "#{ arg }=", value
2529
- else
2530
- die 'msg' => "required_argument <#{ arg }> not given"
2531
- end
2532
- a << send("#{ arg }")
2533
- end
2534
- klass::optional_arguments.each do |arg|
2535
- value = @argv.shift
2536
- if value
2537
- send "#{ arg }=", value
2538
- end
2539
- b << send("#{ arg }")
2540
- end
2541
- [a, b, @argv]
2542
- #--}}}
2543
- end
2544
- def die opts = {}
2545
- #--{{{
2546
- msg = Util::getopt 'msg', opts, klass.usage
2547
- errno = Util::getopt 'errno', opts, EXIT_FAILURE
2548
- STDERR.puts("#{ msg }")
2549
- exit(Integer(errno))
2550
- #--}}}
2551
- end
2552
- def main
2553
- #--{{{
2554
- raise NotImplementedError, 'you need to define main'
2555
- #--}}}
2556
- end
2557
- #--}}}
2558
- end
2559
- module Abilities
2560
- #--{{{
2561
- def self::append_features other
2562
- #--{{{
2563
- other.extend ClassMethods
2564
- other.module_eval {
2565
- include Mixins
2566
- include Constants
2567
- include InstanceMethods
2568
- }
2569
- #--}}}
2570
- end
2571
- #--}}}
2572
- end
2573
- class SimpleMain
2574
- #--{{{
2575
- include Abilities
2576
- class << self
2577
- #--{{{
2578
- def class_initialize
2579
- #--{{{
2580
- version '0.0.0'
2581
-
2582
- prognam ALib::Util::prognam
2583
-
2584
- usage <<-usage
2585
- NAME
2586
- #{ prognam } v#{ version }
2587
-
2588
- SYNOPSIS
2589
- #{ prognam } [options]+ [file]+
2590
- usage
2591
-
2592
- optspec [
2593
- [
2594
- '--help', '-h',
2595
- 'this message'
2596
- ],
2597
- [
2598
- '--log=path','-l',
2599
- 'set log file - (default stderr)'
2600
- ],
2601
- [
2602
- '--verbosity=verbostiy', '-v',
2603
- '0|fatal < 1|error < 2|warn < 3|info < 4|debug - (default info)'
2604
- ],
2605
- =begin
2606
- [
2607
- '--config=path',
2608
- 'valid path - specify config file (default nil)'
2609
- ],
2610
- [
2611
- '--template=[path]',
2612
- 'valid path - generate a template config file in path (default stdout)'
2613
- ],
2614
- =end
2615
- ]
2616
- #--}}}
2617
- end
2618
- #--}}}
2619
- end
2620
- def pre_parse_argv
2621
- #--{{{
2622
- if(@options.has_key?('help') or (@argv.size == 1 and @argv.first =~ %r/help/i))
2623
- usage STDOUT
2624
- exit EXIT_SUCCESS
2625
- end
2626
- if(@options.has_key?('version') or @argv.first =~ %r/version/i)
2627
- STDOUT.puts self.class.version
2628
- exit EXIT_SUCCESS
2629
- end
2630
- #--}}}
2631
- end
2632
- #--}}}
2633
- end
2634
- class ConfigurableMain
2635
- #--{{{
2636
- include Abilities
2637
-
2638
- class << self
2639
- #--{{{
2640
- def class_initialize
2641
- #--{{{
2642
- version '0.0.0'
2643
-
2644
- prognam ALib::Util::prognam
2645
-
2646
- configfile Class::new(ALib::ConfigFile) #{ default = DATA; DATA.rewind; }
2647
-
2648
- config_default_path "#{ prognam }.conf"
2649
-
2650
- config_search_path %w(. ~ /usr/local/etc /usr/etc /etc)
2651
-
2652
- usage <<-usage
2653
- NAME
2654
- #{ prognam } v#{ version }
2655
-
2656
- SYNOPSIS
2657
- #{ prognam } [options]+ [file]+
2658
-
2659
- CONFIG
2660
- default path -> #{ config_default_path }
2661
- search path -> #{ config_search_path.join ' ' }
2662
- usage
2663
-
2664
- optspec [
2665
- [
2666
- '--help', '-h',
2667
- 'this message'
2668
- ],
2669
- [
2670
- '--log=path','-l',
2671
- 'set log file - (default stderr)'
2672
- ],
2673
- [
2674
- '--verbosity=verbostiy', '-v',
2675
- '0|fatal < 1|error < 2|warn < 3|info < 4|debug - (default info)'
2676
- ],
2677
- [
2678
- '--config=path',
2679
- 'valid path - specify config file (default nil)'
2680
- ],
2681
- [
2682
- '--template=[path]',
2683
- 'valid path - generate a template config file in path (default stdout)'
2684
- ],
2685
- ]
2686
- #--}}}
2687
- end
2688
- #--}}}
2689
- end
2690
-
2691
- class_attributes :config_default_path, :config_search_path, :configfile
2692
- attribute :config
2693
-
2694
- def pre_parse_argv
2695
- #--{{{
2696
- if(@options.has_key?('help') or @argv.first =~ %r/help/i)
2697
- usage STDOUT
2698
- exit EXIT_SUCCESS
2699
- end
2700
- if(@options.has_key?('version') or @argv.first =~ %r/version/i)
2701
- STDOUT.puts self.class.version
2702
- exit EXIT_SUCCESS
2703
- end
2704
- if(@options.has_key?('template') or @argv.first =~ %r/template/i)
2705
- @argv.shift if @argv.first =~ %r/template/i
2706
- arg = @argv.first
2707
- gen_template @options['template'] || @options['config'] || arg
2708
- exit EXIT_SUCCESS
2709
- end
2710
- #--}}}
2711
- end
2712
- def gen_template template
2713
- #--{{{
2714
- klass::configfile::gen_template(template)
2715
- self
2716
- #--}}}
2717
- end
2718
- def post_parse_argv
2719
- #--{{{
2720
- init_config
2721
- #--}}}
2722
- end
2723
- def init_config opts = @options
2724
- #--{{{
2725
- conf = Util::getopt 'config', opts
2726
- @config =
2727
- if conf
2728
- klass::configfile::new(conf)
2729
- else
2730
- klass::configfile::any klass::config_default_path, klass::config_search_path
2731
- end
2732
- @config
2733
- #--}}}
2734
- end
2735
- #--}}}
2736
- end
2737
- #--}}}
2738
- end # module MainModule
2739
-
2740
- class << self
2741
- #--{{{
2742
- def simple_main &b
2743
- #--{{{
2744
- if b
2745
- Class::new(MainModule::SimpleMain, &b)
2746
- else
2747
- MainModule::SimpleMain
2748
- end
2749
- #--}}}
2750
- end
2751
- def configurable_main &b
2752
- #--{{{
2753
- if b
2754
- Class::new(MainModule::ConfigurableMain, &b)
2755
- else
2756
- MainModule::ConfigurableMain
2757
- end
2758
- #--}}}
2759
- end
2760
- #--}}}
2761
- end
2762
-
2763
- SimpleMain = simple_main
2764
- ConfigurableMain = configurable_main
2765
-
2766
- =begin
2767
- class SimpleMain
2768
- #--{{{
2769
- include ALib
2770
- include ALib::Logging
2771
-
2772
- EXIT_SUCCESS = 0
2773
- EXIT_FAILURE = 1
2774
-
2775
- class << self
2776
- #--{{{
2777
- def stringlist(*list)
2778
- #--{{{
2779
- list.flatten.compact.map{|item| "#{ item }".strip}
2780
- #--}}}
2781
- end
2782
- def instance_attribute(*names)
2783
- #--{{{
2784
- names = stringlist names
2785
- names.each do |name|
2786
- getter = "#{ name }"
2787
- setter = "#{ name }="
2788
- code = <<-code
2789
- def #{ name }(*a)
2790
- unless a.empty?
2791
- self.#{ name }= a.shift
2792
- else
2793
- @#{ name }
2794
- end
2795
- end
2796
- def #{ name }= value
2797
- @#{ name } = value
2798
- end
2799
- alias #{ name }? #{ name }
2800
- code
2801
- module_eval code
2802
- end
2803
- #--}}}
2804
- end
2805
- alias instance_attributes instance_attribute
2806
- alias i_attrs instance_attribute
2807
- alias i_attr instance_attribute
2808
- def class_attribute(*names)
2809
- #--{{{
2810
- names = stringlist names
2811
- names.each do |name|
2812
- getter = "#{ name }"
2813
- setter = "#{ name }="
2814
- code = <<-code
2815
- class << self
2816
- def #{ name }(*a)
2817
- unless a.empty?
2818
- self.#{ name }= a.shift
2819
- else
2820
- @#{ name }
2821
- end
2822
- end
2823
- def #{ name }= value
2824
- @#{ name } = value
2825
- end
2826
- alias #{ name }? #{ name }
2827
- end
2828
- code
2829
- module_eval code
2830
- end
2831
- #--}}}
2832
- end
2833
- alias class_attributes class_attribute
2834
- alias c_attrs class_attribute
2835
- alias c_attr class_attribute
2836
- def usage(*a)
2837
- #--{{{
2838
- unless a.empty?
2839
- self.usage = a.shift
2840
- else
2841
- @usage
2842
- end
2843
- #--}}}
2844
- end
2845
- def usage= block
2846
- #--{{{
2847
- @usage = unindent_block block
2848
- #--}}}
2849
- end
2850
- alias usage? usage
2851
- def examples(*a)
2852
- #--{{{
2853
- unless a.empty?
2854
- self.examples = a.shift
2855
- else
2856
- @examples
2857
- end
2858
- #--}}}
2859
- end
2860
- def examples= block
2861
- #--{{{
2862
- @examples = unindent_block block
2863
- #--}}}
2864
- end
2865
- alias examples? examples
2866
- def unindent_block buf
2867
- #--{{{
2868
- buf = "#{ buf }"
2869
- lines = buf.to_a
2870
- indent_pat = %r/^\s*[\s|]/
2871
- indent = lines.first[ indent_pat ]
2872
- if indent
2873
- lines.map do |line|
2874
- line[ indent.size..-1 ] || "\n"
2875
- end.join
2876
- else
2877
- buf
2878
- end
2879
- #--}}}
2880
- end
2881
- def options(*list)
2882
- #--{{{
2883
- list.each{|args| (@optspec ||= []) << args}
2884
- #--}}}
2885
- end
2886
- def option(*args)
2887
- #--{{{
2888
- options args.flatten
2889
- #--}}}
2890
- end
2891
- def required_arguments(*list)
2892
- #--{{{
2893
- @required_arguments ||= []
2894
- list.flatten.each{|arg| @required_arguments << "#{ arg }"}
2895
- @required_arguments
2896
- #--}}}
2897
- end
2898
- alias required_argument required_arguments
2899
- alias arguments required_arguments
2900
- alias argument required_arguments
2901
- def optional_arguments(*list)
2902
- #--{{{
2903
- @optional_arguments ||= []
2904
- list.flatten.each{|arg| @optional_arguments << "#{ arg }"}
2905
- @optional_arguments
2906
- #--}}}
2907
- end
2908
- alias optional_argument optional_arguments
2909
-
2910
- def option(*args)
2911
- #--{{{
2912
- options args.flatten
2913
- #--}}}
2914
- end
2915
- def init
2916
- #--{{{
2917
- version '0.0.0'
2918
- author 'ara.t.howard@noaa.gov'
2919
- prognam ALib::Util::prognam
2920
-
2921
- usage <<-usage
2922
- NAME
2923
- #{ prognam } v#{ version }
2924
-
2925
- SYNOPSIS
2926
- #{ prognam } [options]+ [file]+
2927
-
2928
- DESCRIPTTION
2929
-
2930
- ENVIRONMENT
2931
-
2932
- DIAGNOSTICS
2933
- success -> $? == 0
2934
- failure -> $? != 0
2935
-
2936
- AUTHOR
2937
- #{ author }
2938
-
2939
- BUGS
2940
- > 1
2941
- usage
2942
-
2943
- examples <<-examples
2944
- EXAMPLES
2945
-
2946
- 0) #{ prognam }
2947
- examples
2948
-
2949
- optspec [
2950
- [
2951
- '--help', '-h',
2952
- 'this message'
2953
- ],
2954
- [
2955
- '--log=path','-l',
2956
- 'set log file - (default stderr)'
2957
- ],
2958
- [
2959
- '--verbosity=verbostiy', '-v',
2960
- '0|fatal < 1|error < 2|warn < 3|info < 4|debug - (default info)'
2961
- ],
2962
- [
2963
- '--config=path',
2964
- 'valid path - specify config file (default nil)'
2965
- ],
2966
- [
2967
- '--template=[path]',
2968
- 'valid path - generate a template config file in path (default stdout)'
2969
- ],
2970
- ]
2971
- #--}}}
2972
- end
2973
- def inherited klass
2974
- #--{{{
2975
- ret = super
2976
- klass.init
2977
- ret
2978
- #--}}}
2979
- end
2980
- #--}}}
2981
- end
2982
-
2983
- class_attribute :version
2984
- class_attribute :author
2985
- class_attribute :prognam
2986
- class_attribute :optspec
2987
-
2988
- self::init
2989
-
2990
- attr :logger
2991
- attr :argv
2992
- attr :env
2993
- attr :cmdline
2994
- attr :options
2995
- attr :op
2996
- attr :logdev
2997
- attr :verbosity
2998
-
2999
- def initialize argv = ARGV, env = ENV
3000
- #--{{{
3001
- @argv = Util::mcp(argv.to_a)
3002
- @env = Util::mcp(env.to_hash)
3003
- @cmdline = ([$0] + @argv).join ' '
3004
- #--}}}
3005
- end
3006
- def klass; self.class; end
3007
- def required_arguments
3008
- #--{{{
3009
- klass.required_arguments
3010
- #--}}}
3011
- end
3012
- def optional_arguments
3013
- #--{{{
3014
- klass.optional_arguments
3015
- #--}}}
3016
- end
3017
- def run
3018
- #--{{{
3019
- logcatch do
3020
- parse_options
3021
- begin
3022
- if(@options.has_key?('help') or @argv.first =~ %r/help/i)
3023
- usage STDOUT
3024
- exit EXIT_SUCCESS
3025
- end
3026
- parse_argv
3027
- init_logging
3028
- status = main
3029
- exit(status ? EXIT_SUCCESS : EXIT_FAILURE)
3030
- rescue Errno::EPIPE
3031
- STDOUT.tty? ? raise : exit(EXIT_FAILURE)
3032
- end
3033
- end
3034
- #--}}}
3035
- end
3036
- def logcatch
3037
- #--{{{
3038
- ret = nil
3039
- @logger ||= Logger::new STDERR
3040
- begin
3041
- ret = yield
3042
- rescue => e
3043
- unless SystemExit === e
3044
- if logger.debug?
3045
- fatal{ e }
3046
- exit EXIT_FAILURE
3047
- else
3048
- fatal{ emsg(e) }
3049
- exit EXIT_FAILURE
3050
- end
3051
- else
3052
- exit e.status
3053
- end
3054
- end
3055
- ret
3056
- #--}}}
3057
- end
3058
- def usage port = STDERR
3059
- #--{{{
3060
- port << klass::usage << "\n" if klass::usage
3061
- port << klass::examples << "\n" if klass::examples
3062
-
3063
- if klass::optspec
3064
- port << 'OPTIONS' << "\n"
3065
-
3066
- klass::optspec.each do |os|
3067
- a, b, c = os
3068
- long, short, desc = nil
3069
- [a,b,c].each do |word|
3070
- next unless word
3071
- word.strip!
3072
- case word
3073
- when %r/^--[^-]/o
3074
- long = word
3075
- when %r/^-[^-]/o
3076
- short = word
3077
- else
3078
- desc = word
3079
- end
3080
- end
3081
-
3082
- spec = ((long and short) ? [long, short] : [long])
3083
-
3084
- if spec
3085
- port << Util::columnize(spec.join(', '), :width => 80, :indent => 2)
3086
- port << "\n"
3087
- end
3088
-
3089
- if desc
3090
- port << Util::columnize(desc, :width => 80, :indent => 8)
3091
- port << "\n"
3092
- end
3093
- end
3094
-
3095
- port << "\n"
3096
- end
3097
-
3098
- port
3099
- #--}}}
3100
- end
3101
- def parse_options
3102
- #--{{{
3103
- @op = OptionParser::new
3104
- @options = {}
3105
- @listoptions = Hash::new{|h,k| h[k] = []}
3106
- klass::optspec.each do |spec|
3107
- k = spec.first.gsub(%r/(?:--)|(?:=.*$)|(?:\s+)/o,'')
3108
- @op.def_option(*spec) do |v|
3109
- @options[k] = v
3110
- @listoptions[k] << v
3111
- end
3112
- end
3113
- #begin
3114
- op.parse! @argv
3115
- #rescue OptionParser::InvalidOption => e
3116
- # preverve unknown options
3117
- #e.recover(argv)
3118
- #end
3119
- @options
3120
- #--}}}
3121
- end
3122
- def init_logging
3123
- #--{{{
3124
- log, log_age, log_size, verbosity =
3125
- @options.values_at 'log', 'log_age', 'log_size', 'verbosity'
3126
- log_age = Integer log_age rescue nil
3127
- log_size = Integer log_size rescue nil
3128
- $logger = @logger = Logger::new(log || STDERR, log_age, log_size)
3129
- #
3130
- # hack to fix Logger sync bug
3131
- #
3132
- begin
3133
- class << @logger; attr :logdev unless @logger.respond_to?(:logdev); end
3134
- @logdev = @logger.logdev.dev
3135
- @logdev.sync = true
3136
- rescue
3137
- nil
3138
- end
3139
- level = nil
3140
- verbosity ||= 'info'
3141
- verbosity =
3142
- case verbosity
3143
- when /^\s*(?:4|d|debug)\s*$/io
3144
- level = 'Logging::DEBUG'
3145
- 4
3146
- when /^\s*(?:3|i|info)\s*$/io
3147
- level = 'Logging::INFO'
3148
- 3
3149
- when /^\s*(?:2|w|warn)\s*$/io
3150
- level = 'Logging::WARN'
3151
- 2
3152
- when /^\s*(?:1|e|error)\s*$/io
3153
- level = 'Logging::ERROR'
3154
- 1
3155
- when /^\s*(?:0|f|fatal)\s*$/io
3156
- level = 'Logging::FATAL'
3157
- 0
3158
- else
3159
- abort "illegal verbosity setting <#{ verbosity }>"
3160
- end
3161
- @logger.level = 2 - ((verbosity % 5) - 2)
3162
- @logger
3163
- #--}}}
3164
- end
3165
- def parse_argv
3166
- #--{{{
3167
- klass.required_arguments.each do |arg|
3168
- value = @argv.shift
3169
- if value
3170
- klass.module_eval <<-code
3171
- def #{ arg }(*__list)
3172
- if __list.empty?
3173
- @#{ arg }
3174
- else
3175
- send('#{ arg }=', *__list)
3176
- end
3177
- end
3178
- def #{ arg }=(__arg, *__list)
3179
- if __list.empty?
3180
- @#{ arg } = __arg
3181
- else
3182
- @#{ arg } = ([__arg] + __list)
3183
- end
3184
- end
3185
- code
3186
- send "#{ arg }=", value
3187
- else
3188
- die 'msg' => "required_argument <#{ arg }> not given"
3189
- end
3190
- end
3191
-
3192
- klass.optional_arguments.each do |arg|
3193
- value = @argv.shift
3194
- break unless value
3195
- if value
3196
- klass.module_eval <<-code
3197
- def #{ arg }(*__list)
3198
- if __list.empty?
3199
- @#{ arg }
3200
- else
3201
- send('#{ arg }=', *__list)
3202
- end
3203
- end
3204
- def #{ arg }=(__arg, *__list)
3205
- if __list.empty?
3206
- @#{ arg } = __arg
3207
- else
3208
- @#{ arg } = ([__arg] + __list)
3209
- end
3210
- end
3211
- code
3212
- send "#{ arg }=", value
3213
- end
3214
- end
3215
-
3216
- @argv
3217
- #--}}}
3218
- end
3219
- def die opts = {}
3220
- #--{{{
3221
- msg = Util::getopt 'msg', opts, klass.usage
3222
- errno = Util::getopt 'errno', opts, EXIT_FAILURE
3223
- STDERR.puts("#{ msg }")
3224
- exit(Integer(errno))
3225
- #--}}}
3226
- end
3227
- def main
3228
- #--{{{
3229
- #--}}}
3230
- end
3231
- #--}}}
3232
- end
3233
- class ConfigurableMain
3234
- #--{{{
3235
- include ALib
3236
- include ALib::Logging
3237
-
3238
- EXIT_SUCCESS = 0
3239
- EXIT_FAILURE = 1
3240
-
3241
- class << self
3242
- #--{{{
3243
- def stringlist(*list)
3244
- #--{{{
3245
- list.flatten.compact.map{|item| "#{ item }".strip}
3246
- #--}}}
3247
- end
3248
- def instance_attribute(*names)
3249
- #--{{{
3250
- names = stringlist names
3251
- names.each do |name|
3252
- getter = "#{ name }"
3253
- setter = "#{ name }="
3254
- code = <<-code
3255
- def #{ name }(*a)
3256
- unless a.empty?
3257
- self.#{ name }= a.shift
3258
- else
3259
- @#{ name }
3260
- end
3261
- end
3262
- def #{ name }= value
3263
- @#{ name } = value
3264
- end
3265
- alias #{ name }? #{ name }
3266
- code
3267
- module_eval code
3268
- end
3269
- #--}}}
3270
- end
3271
- alias instance_attributes instance_attribute
3272
- alias i_attrs instance_attribute
3273
- alias i_attr instance_attribute
3274
- def class_attribute(*names)
3275
- #--{{{
3276
- names = stringlist names
3277
- names.each do |name|
3278
- getter = "#{ name }"
3279
- setter = "#{ name }="
3280
- code = <<-code
3281
- class << self
3282
- def #{ name }(*a)
3283
- unless a.empty?
3284
- self.#{ name }= a.shift
3285
- else
3286
- @#{ name }
3287
- end
3288
- end
3289
- def #{ name }= value
3290
- @#{ name } = value
3291
- end
3292
- alias #{ name }? #{ name }
3293
- end
3294
- code
3295
- module_eval code
3296
- end
3297
- #--}}}
3298
- end
3299
- alias class_attributes class_attribute
3300
- alias c_attrs class_attribute
3301
- alias c_attr class_attribute
3302
- def usage(*a)
3303
- #--{{{
3304
- unless a.empty?
3305
- self.usage = a.shift
3306
- else
3307
- @usage
3308
- end
3309
- #--}}}
3310
- end
3311
- def usage= block
3312
- #--{{{
3313
- @usage = unindent_block block
3314
- #--}}}
3315
- end
3316
- alias usage? usage
3317
- def examples(*a)
3318
- #--{{{
3319
- unless a.empty?
3320
- self.examples = a.shift
3321
- else
3322
- @examples
3323
- end
3324
- #--}}}
3325
- end
3326
- def examples= block
3327
- #--{{{
3328
- @examples = unindent_block block
3329
- #--}}}
3330
- end
3331
- alias examples? examples
3332
- def unindent_block buf
3333
- #--{{{
3334
- buf = "#{ buf }"
3335
- lines = buf.to_a
3336
- indent_pat = %r/^\s*[\s|]/
3337
- indent = lines.first[ indent_pat ]
3338
- if indent
3339
- lines.map do |line|
3340
- line[ indent.size..-1 ] || "\n"
3341
- end.join
3342
- else
3343
- buf
3344
- end
3345
- #--}}}
3346
- end
3347
- def options(*list)
3348
- #--{{{
3349
- list.each{|args| (@optspec ||= []) << args}
3350
- #--}}}
3351
- end
3352
- def option(*args)
3353
- #--{{{
3354
- options args.flatten
3355
- #--}}}
3356
- end
3357
- def required_arguments(*list)
3358
- #--{{{
3359
- @required_arguments ||= []
3360
- list.flatten.each{|arg| @required_arguments << "#{ arg }"}
3361
- @required_arguments
3362
- #--}}}
3363
- end
3364
- alias required_argument required_arguments
3365
- alias arguments required_arguments
3366
- alias argument required_arguments
3367
- def optional_arguments(*list)
3368
- #--{{{
3369
- @optional_arguments ||= []
3370
- list.flatten.each{|arg| @optional_arguments << "#{ arg }"}
3371
- @optional_arguments
3372
- #--}}}
3373
- end
3374
- alias optional_argument optional_arguments
3375
- def init
3376
- #--{{{
3377
- version '0.0.0'
3378
- author 'ara.t.howard@noaa.gov'
3379
- prognam ALib::Util::prognam
3380
- configfile Class::new(ALib::ConfigFile) #{ default = DATA; DATA.rewind; }
3381
- config_default_path "#{ prognam }.conf"
3382
- config_search_path %w(. ~ /usr/local/etc /usr/etc /etc)
3383
-
3384
- usage <<-usage
3385
- NAME
3386
- #{ prognam } v#{ version }
3387
-
3388
- SYNOPSIS
3389
- #{ prognam } [options]+ [file]+
3390
-
3391
- DESCRIPTTION
3392
-
3393
- ENVIRONMENT
3394
-
3395
- CONFIG
3396
- default path -> #{ config_default_path }
3397
- search path -> #{ config_search_path.join ' ' }
3398
-
3399
- DIAGNOSTICS
3400
- success -> $? == 0
3401
- failure -> $? != 0
3402
-
3403
- AUTHOR
3404
- #{ author }
3405
-
3406
- BUGS
3407
- > 1
3408
- usage
3409
-
3410
- examples <<-examples
3411
- EXAMPLES
3412
-
3413
- 0) #{ prognam }
3414
- examples
3415
-
3416
- optspec [
3417
- [
3418
- '--help', '-h',
3419
- 'this message'
3420
- ],
3421
- [
3422
- '--log=path','-l',
3423
- 'set log file - (default stderr)'
3424
- ],
3425
- [
3426
- '--verbosity=verbostiy', '-v',
3427
- '0|fatal < 1|error < 2|warn < 3|info < 4|debug - (default info)'
3428
- ],
3429
- [
3430
- '--config=path',
3431
- 'valid path - specify config file (default nil)'
3432
- ],
3433
- [
3434
- '--template=[path]',
3435
- 'valid path - generate a template config file in path (default stdout)'
3436
- ],
3437
- ]
3438
- #--}}}
3439
- end
3440
- def inherited klass
3441
- #--{{{
3442
- ret = super
3443
- klass.init
3444
- ret
3445
- #--}}}
3446
- end
3447
- #--}}}
3448
- end
3449
-
3450
- class_attribute :version
3451
- class_attribute :author
3452
- class_attribute :prognam
3453
- class_attribute :config_default_path
3454
- class_attribute :config_search_path
3455
- class_attribute :optspec
3456
- class_attribute :configfile
3457
-
3458
- self::init
3459
-
3460
- attr :logger
3461
- attr :argv
3462
- attr :env
3463
- attr :cmdline
3464
- attr :options
3465
- attr :op
3466
- attr :logdev
3467
- attr :verbosity
3468
- attr :config
3469
-
3470
- def initialize argv = ARGV, env = ENV
3471
- #--{{{
3472
- @argv = Util::mcp(argv.to_a)
3473
- @env = Util::mcp(env.to_hash)
3474
- @cmdline = ([$0] + @argv).join ' '
3475
- #--}}}
3476
- end
3477
- def klass; self.class; end
3478
- def required_arguments
3479
- #--{{{
3480
- klass.required_arguments
3481
- #--}}}
3482
- end
3483
- def optional_arguments
3484
- #--{{{
3485
- klass.optional_arguments
3486
- #--}}}
3487
- end
3488
- def run
3489
- #--{{{
3490
- logcatch do
3491
- parse_options
3492
- begin
3493
- if(@options.has_key?('help') or @argv.first =~ %r/help/i)
3494
- usage STDOUT
3495
- exit EXIT_SUCCESS
3496
- end
3497
- if(@options.has_key?('template') or @argv.first =~ %r/template/i)
3498
- @argv.shift if @argv.first =~ %r/template/i
3499
- arg = @argv.first
3500
- gen_template @options['template'] || @options['config'] || arg
3501
- exit EXIT_SUCCESS
3502
- end
3503
- parse_argv
3504
- init_logging
3505
- init_config
3506
- status = main
3507
- exit(status ? EXIT_SUCCESS : EXIT_FAILURE)
3508
- rescue Errno::EPIPE
3509
- STDOUT.tty? ? raise : exit(EXIT_FAILURE)
3510
- end
3511
- end
3512
- #--}}}
3513
- end
3514
- def logcatch
3515
- #--{{{
3516
- ret = nil
3517
- @logger ||= Logger::new STDERR
3518
- begin
3519
- ret = yield
3520
- rescue => e
3521
- unless SystemExit === e
3522
- if logger.debug?
3523
- fatal{ e }
3524
- exit EXIT_FAILURE
3525
- else
3526
- fatal{ emsg(e) }
3527
- exit EXIT_FAILURE
3528
- end
3529
- else
3530
- exit e.status
3531
- end
3532
- end
3533
- ret
3534
- #--}}}
3535
- end
3536
- def usage port = STDERR
3537
- #--{{{
3538
- port << klass::usage << "\n" if klass::usage
3539
- port << klass::examples << "\n" if klass::examples
3540
-
3541
- if klass::optspec
3542
- port << 'OPTIONS' << "\n"
3543
-
3544
- klass::optspec.each do |os|
3545
- a, b, c = os
3546
- long, short, desc = nil
3547
- [a,b,c].each do |word|
3548
- next unless word
3549
- word.strip!
3550
- case word
3551
- when %r/^--[^-]/o
3552
- long = word
3553
- when %r/^-[^-]/o
3554
- short = word
3555
- else
3556
- desc = word
3557
- end
3558
- end
3559
-
3560
- spec = ((long and short) ? [long, short] : [long])
3561
-
3562
- if spec
3563
- port << Util::columnize(spec.join(', '), :width => 80, :indent => 2)
3564
- port << "\n"
3565
- end
3566
-
3567
- if desc
3568
- port << Util::columnize(desc, :width => 80, :indent => 8)
3569
- port << "\n"
3570
- end
3571
- end
3572
-
3573
- port << "\n"
3574
- end
3575
-
3576
- port
3577
- #--}}}
3578
- end
3579
- def parse_options
3580
- #--{{{
3581
- @op = OptionParser::new
3582
- @options = {}
3583
- @listoptions = Hash::new{|h,k| h[k] = []}
3584
- klass::optspec.each do |spec|
3585
- k = spec.first.gsub(%r/(?:--)|(?:=.*$)|(?:\s+)/o,'')
3586
- @op.def_option(*spec) do |v|
3587
- @options[k] = v
3588
- @listoptions[k] << v
3589
- end
3590
- end
3591
- #begin
3592
- op.parse! @argv
3593
- #rescue OptionParser::InvalidOption => e
3594
- # preverve unknown options
3595
- #e.recover(argv)
3596
- #end
3597
- @options
3598
- #--}}}
3599
- end
3600
- def init_logging
3601
- #--{{{
3602
- log, log_age, log_size, verbosity =
3603
- @options.values_at 'log', 'log_age', 'log_size', 'verbosity'
3604
- log_age = Integer log_age rescue nil
3605
- log_size = Integer log_size rescue nil
3606
- $logger = @logger = Logger::new(log || STDERR, log_age, log_size)
3607
- #
3608
- # hack to fix Logger sync bug
3609
- #
3610
- begin
3611
- class << @logger; attr :logdev unless @logger.respond_to?(:logdev); end
3612
- @logdev = @logger.logdev.dev
3613
- @logdev.sync = true
3614
- rescue
3615
- nil
3616
- end
3617
- level = nil
3618
- verbosity ||= 'info'
3619
- verbosity =
3620
- case verbosity
3621
- when /^\s*(?:4|d|debug)\s*$/io
3622
- level = 'Logging::DEBUG'
3623
- 4
3624
- when /^\s*(?:3|i|info)\s*$/io
3625
- level = 'Logging::INFO'
3626
- 3
3627
- when /^\s*(?:2|w|warn)\s*$/io
3628
- level = 'Logging::WARN'
3629
- 2
3630
- when /^\s*(?:1|e|error)\s*$/io
3631
- level = 'Logging::ERROR'
3632
- 1
3633
- when /^\s*(?:0|f|fatal)\s*$/io
3634
- level = 'Logging::FATAL'
3635
- 0
3636
- else
3637
- abort "illegal verbosity setting <#{ verbosity }>"
3638
- end
3639
- @logger.level = 2 - ((verbosity % 5) - 2)
3640
- @logger
3641
- #--}}}
3642
- end
3643
- def init_config
3644
- #--{{{
3645
- @config =
3646
- if @options['config']
3647
- klass::configfile::new(@options['config'])
3648
- else
3649
- klass::configfile::any klass::config_default_path, klass::config_search_path
3650
- end
3651
- @config
3652
- #--}}}
3653
- end
3654
- def gen_template template
3655
- #--{{{
3656
- klass::configfile::gen_template(template)
3657
- self
3658
- #--}}}
3659
- end
3660
- def parse_argv
3661
- #--{{{
3662
- klass.required_arguments.each do |arg|
3663
- value = @argv.shift
3664
- if value
3665
- klass.module_eval <<-code
3666
- def #{ arg }(*__list)
3667
- if __list.empty?
3668
- @#{ arg }
3669
- else
3670
- send('#{ arg }=', *__list)
3671
- end
3672
- end
3673
- def #{ arg }=(__arg, *__list)
3674
- if __list.empty?
3675
- @#{ arg } = __arg
3676
- else
3677
- @#{ arg } = ([__arg] + __list)
3678
- end
3679
- end
3680
- code
3681
- send "#{ arg }=", value
3682
- else
3683
- die 'msg' => "required_argument <#{ arg }> not given"
3684
- end
3685
- end
3686
-
3687
- klass.optional_arguments.each do |arg|
3688
- value = @argv.shift
3689
- break unless value
3690
- if value
3691
- klass.module_eval <<-code
3692
- def #{ arg }(*__list)
3693
- if __list.empty?
3694
- @#{ arg }
3695
- else
3696
- send('#{ arg }=', *__list)
3697
- end
3698
- end
3699
- def #{ arg }=(__arg, *__list)
3700
- if __list.empty?
3701
- @#{ arg } = __arg
3702
- else
3703
- @#{ arg } = ([__arg] + __list)
3704
- end
3705
- end
3706
- code
3707
- send "#{ arg }=", value
3708
- end
3709
- end
3710
-
3711
- @argv
3712
- #--}}}
3713
- end
3714
- def main
3715
- #--{{{
3716
- warn{ "foobar" }
3717
- p @listoptions
3718
- return EXIT_SUCCESS
3719
- #--}}}
3720
- end
3721
- def die errno = EXIT_FAILURE
3722
- #--{{{
3723
- STDERR.puts klass.usage
3724
- exit EXIT_FAILURE
3725
- #--}}}
3726
- end
3727
- #--}}}
3728
- end
3729
- =end
3730
-
3731
-
3732
- #
3733
- # on-demand extensions to standard classes - (incomplete now)
3734
- #
3735
- module ModuleExtensions
3736
- #--{{{
3737
- def reader_attributes(*names)
3738
- #--{{{
3739
- @reader_attributes ||= []
3740
- unless names.empty?
3741
- names.flatten.each do |name|
3742
- @reader_attributes << "#{ name }"
3743
- getter = "#{ name }"
3744
- unless instance_methods.include? getter
3745
- code = <<-code
3746
- def #{ name }(*a)
3747
- unless a.empty?
3748
- self.#{ name }= a.shift
3749
- else
3750
- @#{ name }
3751
- end
3752
- end
3753
- code
3754
- module_eval code
3755
- end
3756
-
3757
- setter = "#{ name }="
3758
- unless instance_methods.include? setter
3759
- code = <<-code
3760
- def #{ name }= value
3761
- @#{ name } = value
3762
- end
3763
- private '#{ name }='.intern
3764
- code
3765
- module_eval code
3766
- end
3767
-
3768
- query = "#{ name }?"
3769
- unless instance_methods.include? query
3770
- code = <<-code
3771
- alias #{ name }? #{ name }
3772
- code
3773
- module_eval code
3774
- end
3775
- end
3776
- end
3777
- @reader_attributes
3778
- #--}}}
3779
- end
3780
- alias reader_attribute reader_attributes
3781
- def writer_attributes(*names)
3782
- #--{{{
3783
- @writer_attributes ||= []
3784
- unless names.empty?
3785
- names.flatten.each do |name|
3786
- @writer_attributes << "#{ name }="
3787
- getter = "#{ name }"
3788
- unless instance_methods.include? getter
3789
- code = <<-code
3790
- def #{ name }(*a)
3791
- unless a.empty?
3792
- self.#{ name }= a.shift
3793
- else
3794
- @#{ name }
3795
- end
3796
- end
3797
- private '#{ name }'.intern
3798
- code
3799
- module_eval code
3800
- end
3801
-
3802
- setter = "#{ name }="
3803
- unless instance_methods.include? setter
3804
- code = <<-code
3805
- def #{ name }= value
3806
- @#{ name } = value
3807
- end
3808
- code
3809
- module_eval code
3810
- end
3811
-
3812
- query = "#{ name }?"
3813
- unless instance_methods.include? query
3814
- code = <<-code
3815
- alias #{ name }? #{ name }
3816
- private '#{ name }?'.intern
3817
- code
3818
- module_eval code
3819
- end
3820
- end
3821
- end
3822
- @writer_attributes
3823
- #--}}}
3824
- end
3825
- alias writer_attribute writer_attributes
3826
- def attributes(*names)
3827
- #--{{{
3828
- reader_attributes(*names) + writer_attributes(*names)
3829
- #--}}}
3830
- end
3831
- alias attribute attributes
3832
- def class_reader_attributes(*names)
3833
- #--{{{
3834
- class << self; self; end.instance_eval{ reader_attributes(*names) }
3835
- #--}}}
3836
- end
3837
- alias class_reader_attribute class_reader_attributes
3838
- def class_writer_attributes(*names)
3839
- #--{{{
3840
- class << self; self; end.instance_eval{ writer_attributes(*names) }
3841
- #--}}}
3842
- end
3843
- alias class_writer_attribute class_writer_attributes
3844
- def class_attributes(*names)
3845
- #--{{{
3846
- class << self; self; end.instance_eval{ attributes(*names) }
3847
- #--}}}
3848
- end
3849
- alias class_attribute class_attributes
3850
- class << self
3851
- def self.append_features c
3852
- #--{{{
3853
- Module.extend self
3854
- #--}}}
3855
- end
3856
- end
3857
- #--}}}
3858
- end # module ModuleExtensions
3859
- module ClassExtensions;
3860
- end # module ClassExtensions
3861
- module ObjectExtensions
3862
- end # module ObjectExtensions
3863
- module StandardExtensions
3864
- include ModuleExtensions
3865
- include ClassExtensions
3866
- include ObjectExtensions
3867
- end # StandardExtensions
3868
-
3869
- #--}}}
3870
- end
3871
-
3872
- Alib = ALib