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