alib 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3872 +1,104 @@
1
1
  #
2
2
  # the ALib module is a namespace for things i've found useful
3
3
  #
4
- module ALib
4
+ module ALib
5
5
  #--{{{
6
- VERSION = '0.3.1'
6
+ VERSION = '0.4.0'
7
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'
8
+ def self.version() VERSION end
20
9
 
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
10
+ require 'pathname'
11
+ require 'socket'
12
+ require 'tmpdir'
13
+ require 'rbconfig'
14
+ require 'logger'
15
+ require 'yaml'
16
+ require 'fileutils'
17
+ require 'tempfile'
18
+ require 'optparse'
19
+ require 'sync'
20
+ require 'time'
21
+ require 'fcntl'
22
+ require 'uri'
23
+ require 'net/http'
2225
24
 
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
25
 
2582
- prognam ALib::Util::prognam
26
+ # TODO - bundle open4!!
2583
27
 
2584
- usage <<-usage
2585
- NAME
2586
- #{ prognam } v#{ version }
28
+ LIBDIR = 'alib-%s/' % VERSION
2587
29
 
2588
- SYNOPSIS
2589
- #{ prognam } [options]+ [file]+
2590
- usage
30
+ AUTOLOAD = {
2591
31
 
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
32
+ 'Util' => 'util',
2637
33
 
2638
- class << self
2639
- #--{{{
2640
- def class_initialize
2641
- #--{{{
2642
- version '0.0.0'
34
+ 'Logging' => 'logging',
2643
35
 
2644
- prognam ALib::Util::prognam
36
+ 'ConfigFile' => 'configfile',
37
+ 'Configfile' => 'configfile',
2645
38
 
2646
- configfile Class::new(ALib::ConfigFile) #{ default = DATA; DATA.rewind; }
39
+ 'ListFile' => 'listfile',
40
+ 'Listfile' => 'listfile',
2647
41
 
2648
- config_default_path "#{ prognam }.conf"
42
+ 'AutoHash' => 'autohash',
2649
43
 
2650
- config_search_path %w(. ~ /usr/local/etc /usr/etc /etc)
44
+ 'OrderedHash' => 'orderedhash',
2651
45
 
2652
- usage <<-usage
2653
- NAME
2654
- #{ prognam } v#{ version }
46
+ 'OrderedAutoHash' => 'orderedautohash',
47
+ 'AutoOrderedHash' => 'orderedautohash',
2655
48
 
2656
- SYNOPSIS
2657
- #{ prognam } [options]+ [file]+
49
+ 'Find' => 'find2',
50
+ 'Find2' => 'find2',
2658
51
 
2659
- CONFIG
2660
- default path -> #{ config_default_path }
2661
- search path -> #{ config_search_path.join ' ' }
2662
- usage
52
+ 'Bsearch' => 'bsearch',
2663
53
 
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
54
+ 'AbstractMain' => 'main',
55
+ 'SimpleMain' => 'main',
56
+ 'ConfigurableMain' => 'main',
2690
57
 
2691
- class_attributes :config_default_path, :config_search_path, :configfile
2692
- attribute :config
58
+ }
2693
59
 
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
60
+ AUTOLOAD.each{|const, basename| autoload const.to_s, LIBDIR + basename.to_s}
2739
61
 
62
+ METACLASS =
2740
63
  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
- #--}}}
64
+ self
2761
65
  end
2762
66
 
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
67
+ AUTOLOAD.each{ |const, m| METACLASS.module_eval{ define_method(m){ ALib.send 'const_get', const}}}
3191
68
 
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
69
+ begin
70
+ require 'open4'
71
+ rescue LoadError
72
+ require LIBDIR + 'open4'
73
+ end
3215
74
 
3216
- @argv
3217
- #--}}}
3218
- end
3219
- def die opts = {}
75
+ class << self
3220
76
  #--{{{
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
77
+ def load basename
3228
78
  #--{{{
3229
- #--}}}
3230
- end
79
+ require LIBDIR + basename.to_s
3231
80
  #--}}}
3232
81
  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
82
+ def simple_main &b
3441
83
  #--{{{
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
84
+ b ? Class::new(ALib::SimpleMain, &b) : ALib::SimpleMain
3727
85
  #--}}}
3728
86
  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)
87
+ alias_method 'main', 'simple_main'
88
+ alias_method 'smain', 'simple_main'
89
+ def configurable_main &b
3782
90
  #--{{{
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) }
91
+ b ? Class::new(ALib::ConfigurableMain, &b) : ALib::ConfigurableMain
3841
92
  #--}}}
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) }
93
+ end
94
+ alias_method 'cmain', 'configurable_main'
3847
95
  #--}}}
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
96
+ end
3857
97
  #--}}}
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
98
+ end
3868
99
 
3869
- #--}}}
3870
- end
100
+ Alib = ALib
3871
101
 
3872
- Alib = ALib
102
+ class Object
103
+ def alib() Alib end
104
+ end