alib 0.4.0 → 0.5.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 +12 -1
- data/{alib-0.4.0.gem → alib-0.5.0.gem} +0 -0
- data/lib/{alib-0.4.0.rb → alib-0.5.0.rb} +17 -40
- data/lib/alib-0.5.0/attributes-3.2.0.rb +54 -0
- data/lib/alib-0.5.0/attributes.rb +54 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/autohash.rb +0 -0
- data/lib/alib-0.5.0/binding_of_caller.rb +70 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/bsearch.rb +0 -0
- data/lib/alib-0.5.0/classmethods.rb +39 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/configfile.rb +0 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/find2.rb +0 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/listfile.rb +0 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/logging.rb +71 -7
- data/lib/{alib-0.4.0 → alib-0.5.0}/main.rb +416 -14
- data/lib/alib-0.5.0/main.rb.bak +1029 -0
- data/lib/alib-0.5.0/open4-0.9.1.rb +379 -0
- data/lib/alib-0.5.0/open4.rb +379 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/orderedautohash.rb +0 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/orderedhash.rb +0 -0
- data/lib/alib-0.5.0/prototype-0.3.0.rb +200 -0
- data/lib/alib-0.5.0/prototype.rb +200 -0
- data/lib/alib-0.5.0/stdext.rb +174 -0
- data/lib/{alib-0.4.0 → alib-0.5.0}/util.rb +452 -51
- data/lib/alib.rb +17 -40
- metadata +45 -32
- data/b.rb +0 -1
- data/build +0 -0
- data/install +0 -143
- data/lib/alib-0.4.0/open4.rb +0 -175
@@ -0,0 +1,1029 @@
|
|
1
|
+
#
|
2
|
+
# template main building block classes
|
3
|
+
#
|
4
|
+
|
5
|
+
|
6
|
+
module ALib
|
7
|
+
|
8
|
+
class AbstractMain
|
9
|
+
#--{{{
|
10
|
+
include ALib
|
11
|
+
include ALib::Logging
|
12
|
+
|
13
|
+
module Constants
|
14
|
+
EXIT_SUCCESS = 0
|
15
|
+
EXIT_PSEUDO_SUCCESS = 42
|
16
|
+
EXIT_OK = 42
|
17
|
+
EXIT_FAILURE = 1
|
18
|
+
end
|
19
|
+
include Constants
|
20
|
+
|
21
|
+
def self.exit_success() EXIT_SUCCESS end
|
22
|
+
def exit_success() EXIT_SUCCESS end
|
23
|
+
def self.status_success() EXIT_SUCCESS end
|
24
|
+
def status_success() EXIT_SUCCESS end
|
25
|
+
|
26
|
+
def self.exit_pseudo_success() EXIT_PSEUDO_SUCCESS end
|
27
|
+
def exit_pseudo_success() EXIT_PSEUDO_SUCCESS end
|
28
|
+
def self.status_pseudo_success() EXIT_PSEUDO_SUCCESS end
|
29
|
+
def status_pseudo_success() EXIT_PSEUDO_SUCCESS end
|
30
|
+
|
31
|
+
def self.exit_ok() EXIT_OK end
|
32
|
+
def exit_ok() EXIT_OK end
|
33
|
+
def self.status_ok() EXIT_OK end
|
34
|
+
def status_ok() EXIT_OK end
|
35
|
+
|
36
|
+
def self.exit_failure() EXIT_FAILURE end
|
37
|
+
def exit_failure() EXIT_FAILURE end
|
38
|
+
def self.status_failure() EXIT_FAILURE end
|
39
|
+
def status_failure() EXIT_FAILURE end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
#--{{{
|
43
|
+
def stringlist(*list)
|
44
|
+
#--{{{
|
45
|
+
list.flatten.compact.map{|item| "#{ item }".strip}
|
46
|
+
#--}}}
|
47
|
+
end
|
48
|
+
def instance_attributes(*names)
|
49
|
+
#--{{{
|
50
|
+
names = stringlist names
|
51
|
+
names.each do |name|
|
52
|
+
getter = "#{ name }"
|
53
|
+
setter = "#{ name }="
|
54
|
+
code = <<-code
|
55
|
+
def #{ name }(*a)
|
56
|
+
unless a.empty?
|
57
|
+
self.#{ name }= a.shift
|
58
|
+
else
|
59
|
+
@#{ name }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
def #{ name }= value
|
63
|
+
@#{ name } = value
|
64
|
+
end
|
65
|
+
alias #{ name }? #{ name }
|
66
|
+
code
|
67
|
+
module_eval code
|
68
|
+
end
|
69
|
+
#--}}}
|
70
|
+
end
|
71
|
+
alias instance_attribute instance_attributes
|
72
|
+
alias i_attrs instance_attributes
|
73
|
+
alias i_attr instance_attributes
|
74
|
+
alias attribute instance_attributes
|
75
|
+
alias attributes instance_attributes
|
76
|
+
|
77
|
+
def class_attributes(*names)
|
78
|
+
#--{{{
|
79
|
+
names = stringlist names
|
80
|
+
names.each do |name|
|
81
|
+
getter = "#{ name }"
|
82
|
+
setter = "#{ name }="
|
83
|
+
code = <<-code
|
84
|
+
class << self
|
85
|
+
def #{ name }(*a)
|
86
|
+
unless a.empty?
|
87
|
+
self.#{ name }= a.shift
|
88
|
+
else
|
89
|
+
@#{ name }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
def #{ name }= value
|
93
|
+
@#{ name } = value
|
94
|
+
end
|
95
|
+
alias #{ name }? #{ name }
|
96
|
+
end
|
97
|
+
code
|
98
|
+
module_eval code
|
99
|
+
end
|
100
|
+
#--}}}
|
101
|
+
end
|
102
|
+
alias class_attribute class_attributes
|
103
|
+
alias c_attrs class_attributes
|
104
|
+
alias c_attr class_attributes
|
105
|
+
|
106
|
+
%w( version author program optspec name examples synopsis ).each do |meth|
|
107
|
+
#--{{{
|
108
|
+
module_eval <<-code
|
109
|
+
def #{ meth }(*a)
|
110
|
+
unless a.empty?
|
111
|
+
self.#{ meth }= a.shift
|
112
|
+
else
|
113
|
+
@#{ meth }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
def #{ meth }= value
|
117
|
+
@#{ meth } = value
|
118
|
+
end
|
119
|
+
def #{ meth }?
|
120
|
+
defined? @#{ meth } and @#{ meth }
|
121
|
+
end
|
122
|
+
code
|
123
|
+
#--}}}
|
124
|
+
end
|
125
|
+
alias prognam program
|
126
|
+
alias progname program
|
127
|
+
alias prognam= program=
|
128
|
+
alias prognam? program?
|
129
|
+
|
130
|
+
=begin
|
131
|
+
%w( usage examples ).each do |meth|
|
132
|
+
#--{{{
|
133
|
+
module_eval <<-code
|
134
|
+
def #{ meth }(*a)
|
135
|
+
unless a.empty?
|
136
|
+
self.#{ meth }= a.shift
|
137
|
+
else
|
138
|
+
@#{ meth }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
def #{ meth }= msg
|
142
|
+
@#{ meth } = unindent_block msg.to_s
|
143
|
+
end
|
144
|
+
def #{ meth }?
|
145
|
+
defined? @#{ meth } and @#{ meth }
|
146
|
+
end
|
147
|
+
code
|
148
|
+
#--}}}
|
149
|
+
end
|
150
|
+
=end
|
151
|
+
|
152
|
+
def usage arg = nil
|
153
|
+
#--{{{
|
154
|
+
if arg
|
155
|
+
@usage = arg.to_s
|
156
|
+
else
|
157
|
+
if defined? @usage
|
158
|
+
@usage
|
159
|
+
else
|
160
|
+
s = ""
|
161
|
+
|
162
|
+
unless name.to_s.empty?
|
163
|
+
#s << "\n"
|
164
|
+
s << "NAME\n"
|
165
|
+
s << indent_block("#{ name }\n", 2)
|
166
|
+
end
|
167
|
+
|
168
|
+
unless synopsis.to_s.empty?
|
169
|
+
s << "\n"
|
170
|
+
s << "SYNOPSIS\n"
|
171
|
+
s << indent_block("#{ synopsis }\n", 2)
|
172
|
+
end
|
173
|
+
|
174
|
+
unless examples.to_s.empty?
|
175
|
+
s << "\n"
|
176
|
+
s << "EXAMPLES\n"
|
177
|
+
s << indent_block("#{ examples }\n", 2)
|
178
|
+
end
|
179
|
+
|
180
|
+
s
|
181
|
+
end
|
182
|
+
end
|
183
|
+
#--}}}
|
184
|
+
end
|
185
|
+
|
186
|
+
=begin
|
187
|
+
usage <<-usage
|
188
|
+
NAME
|
189
|
+
#{ program } v#{ version }
|
190
|
+
|
191
|
+
SYNOPSIS
|
192
|
+
#{ program } [options]* [file]*
|
193
|
+
usage
|
194
|
+
=end
|
195
|
+
|
196
|
+
|
197
|
+
def unindent_block buf
|
198
|
+
#--{{{
|
199
|
+
buf = "#{ buf }"
|
200
|
+
lines = buf.to_a
|
201
|
+
indent_pat = %r/^\s*[\s|]/
|
202
|
+
indent = lines.first[ indent_pat ] rescue nil
|
203
|
+
if indent
|
204
|
+
lines.map do |line|
|
205
|
+
line[ indent.size..-1 ] || "\n"
|
206
|
+
end.join
|
207
|
+
else
|
208
|
+
buf
|
209
|
+
end
|
210
|
+
#--}}}
|
211
|
+
end
|
212
|
+
|
213
|
+
def indent_block buf, n = 2
|
214
|
+
#--{{{
|
215
|
+
space = ' ' * n.to_i
|
216
|
+
unindent_block(buf).gsub %r/^/, space
|
217
|
+
#--}}}
|
218
|
+
end
|
219
|
+
|
220
|
+
def options(*list)
|
221
|
+
#--{{{
|
222
|
+
@optspec ||= []
|
223
|
+
return @optspec if list.empty?
|
224
|
+
list = [list] unless Array === list.first
|
225
|
+
list.each{|spec| (@optspec ||= []) << spec}
|
226
|
+
#--}}}
|
227
|
+
end
|
228
|
+
alias option options
|
229
|
+
|
230
|
+
def required_arguments(*list)
|
231
|
+
#--{{{
|
232
|
+
@required_arguments ||= []
|
233
|
+
list.flatten.each do |arg|
|
234
|
+
return(optional_argument(arg)) if Hash === arg
|
235
|
+
unless instance_methods.include? "#{ arg }"
|
236
|
+
module_eval <<-code
|
237
|
+
def #{ arg }(*__list)
|
238
|
+
if __list.empty?
|
239
|
+
@#{ arg }
|
240
|
+
else
|
241
|
+
send('#{ arg }=', *__list)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
def #{ arg }=(__arg, *__list)
|
245
|
+
if __list.empty?
|
246
|
+
@#{ arg } = __arg
|
247
|
+
else
|
248
|
+
@#{ arg } = ([__arg] + __list)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
def #{ arg }?
|
252
|
+
defined? @#{ arg } and @#{ arg }
|
253
|
+
end
|
254
|
+
code
|
255
|
+
end
|
256
|
+
@required_arguments << "#{ arg }"
|
257
|
+
end
|
258
|
+
@required_arguments
|
259
|
+
#--}}}
|
260
|
+
end
|
261
|
+
alias required_argument required_arguments
|
262
|
+
alias arguments required_arguments
|
263
|
+
alias argument required_arguments
|
264
|
+
|
265
|
+
def optional_arguments(*list)
|
266
|
+
#--{{{
|
267
|
+
@optional_arguments ||= []
|
268
|
+
list.flatten.each do |arg|
|
269
|
+
arg, default =
|
270
|
+
case arg
|
271
|
+
when Hash
|
272
|
+
arg.to_a.first
|
273
|
+
else
|
274
|
+
[arg, nil]
|
275
|
+
end
|
276
|
+
@do_not_gc ||= []
|
277
|
+
@do_not_gc << default unless @do_not_gc.include? default
|
278
|
+
unless instance_methods.include? "#{ arg }"
|
279
|
+
module_eval <<-code
|
280
|
+
def #{ arg }(*__list)
|
281
|
+
unless @#{ arg }
|
282
|
+
@#{ arg } = ObjectSpace::_id2ref #{ default.object_id }
|
283
|
+
end
|
284
|
+
if __list.empty?
|
285
|
+
@#{ arg }
|
286
|
+
else
|
287
|
+
send('#{ arg }=', *__list)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
def #{ arg }=(__arg, *__list)
|
291
|
+
if __list.empty?
|
292
|
+
@#{ arg } = __arg
|
293
|
+
else
|
294
|
+
@#{ arg } = ([__arg] + __list)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
def #{ arg }?
|
298
|
+
defined? @#{ arg } and @#{ arg }
|
299
|
+
end
|
300
|
+
code
|
301
|
+
end
|
302
|
+
@optional_arguments << "#{ arg }"
|
303
|
+
end
|
304
|
+
@optional_arguments
|
305
|
+
#--}}}
|
306
|
+
end
|
307
|
+
alias optional_argument optional_arguments
|
308
|
+
|
309
|
+
def class_initialize
|
310
|
+
#--{{{
|
311
|
+
version '0.0.0'
|
312
|
+
|
313
|
+
author 'ara.t.howard@noaa.gov'
|
314
|
+
|
315
|
+
program File.basename($0)
|
316
|
+
|
317
|
+
name "#{ program } v#{ version }"
|
318
|
+
|
319
|
+
optspec [
|
320
|
+
[ '--help', '-h', 'this message' ],
|
321
|
+
[ '--log=path','-l', 'set log file - (default stderr)' ],
|
322
|
+
[ '--verbosity=verbostiy', '-v', '0|fatal < 1|error < 2|warn < 3|info < 4|debug - (default info)' ],
|
323
|
+
]
|
324
|
+
|
325
|
+
=begin
|
326
|
+
usage <<-usage
|
327
|
+
NAME
|
328
|
+
#{ program } v#{ version }
|
329
|
+
|
330
|
+
SYNOPSIS
|
331
|
+
#{ program } [options]* [file]*
|
332
|
+
usage
|
333
|
+
=end
|
334
|
+
|
335
|
+
examples ''
|
336
|
+
#--}}}
|
337
|
+
end
|
338
|
+
|
339
|
+
def inherited klass, &b
|
340
|
+
#--{{{
|
341
|
+
ret = super(klass, &b)
|
342
|
+
klass.class_initialize
|
343
|
+
ret
|
344
|
+
#--}}}
|
345
|
+
end
|
346
|
+
|
347
|
+
def run(*a, &b)
|
348
|
+
#--{{{
|
349
|
+
new(*a, &b).run
|
350
|
+
#--}}}
|
351
|
+
end
|
352
|
+
|
353
|
+
def defaults head = nil, *tail
|
354
|
+
#--{{{
|
355
|
+
@defaults ||= {}
|
356
|
+
return @defaults if head.nil?
|
357
|
+
return @defaults.update(head) if head.is_a?(Hash)
|
358
|
+
return @defaults.values_at(*head) if head.is_a?(Array)
|
359
|
+
return @defaults[head.to_s] if tail.empty?
|
360
|
+
keys = [head, tail].flatten.map{|k| k.to_s}
|
361
|
+
return @defaults.values_at(*keys)
|
362
|
+
#--}}}
|
363
|
+
end
|
364
|
+
alias_method "default", "defaults"
|
365
|
+
#--}}}
|
366
|
+
end
|
367
|
+
|
368
|
+
#class_attribute
|
369
|
+
|
370
|
+
class_initialize
|
371
|
+
|
372
|
+
attr :logger
|
373
|
+
attr :program
|
374
|
+
attr :argv
|
375
|
+
attr :env
|
376
|
+
attr :cmdline
|
377
|
+
attr :console
|
378
|
+
attr :options
|
379
|
+
attr :listoptions
|
380
|
+
attr :op
|
381
|
+
attr :logdev
|
382
|
+
attr :verbosity
|
383
|
+
alias console? console
|
384
|
+
|
385
|
+
def exit_status e = nil
|
386
|
+
(e ? (@exit_success = e) : (defined?(@exit_success) and @exit_success))
|
387
|
+
end
|
388
|
+
alias_method "exit_status?", "exit_status"
|
389
|
+
|
390
|
+
def initialize argv = ARGV, env = ENV
|
391
|
+
#--{{{
|
392
|
+
@argv = Util::mcp(argv.to_a)
|
393
|
+
@env = Util::mcp(env.to_hash)
|
394
|
+
@program = File::expand_path $0
|
395
|
+
@cmdline = ([@program] + @argv).join ' '
|
396
|
+
@console = STDIN.tty?
|
397
|
+
#--}}}
|
398
|
+
end
|
399
|
+
def klass; self.class; end
|
400
|
+
def required_arguments
|
401
|
+
#--{{{
|
402
|
+
klass::required_arguments
|
403
|
+
#--}}}
|
404
|
+
end
|
405
|
+
def optional_arguments
|
406
|
+
#--{{{
|
407
|
+
klass::optional_arguments
|
408
|
+
#--}}}
|
409
|
+
end
|
410
|
+
def run
|
411
|
+
#--{{{
|
412
|
+
logcatch do
|
413
|
+
begin
|
414
|
+
pre_run
|
415
|
+
pre_parse_options
|
416
|
+
parse_options
|
417
|
+
post_parse_options
|
418
|
+
pre_parse_argv
|
419
|
+
parse_argv
|
420
|
+
post_parse_argv
|
421
|
+
pre_init_logging
|
422
|
+
init_logging
|
423
|
+
post_init_logging
|
424
|
+
pre_main
|
425
|
+
status = main
|
426
|
+
post_main
|
427
|
+
post_run
|
428
|
+
exit(exit_status ? exit_status : (status ? EXIT_SUCCESS : EXIT_FAILURE))
|
429
|
+
rescue Errno::EPIPE
|
430
|
+
STDOUT.tty? ? raise : exit(EXIT_FAILURE)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
#--}}}
|
434
|
+
end
|
435
|
+
def pre_parse_options; end
|
436
|
+
def post_parse_options; end
|
437
|
+
def pre_init_logging; end
|
438
|
+
def post_init_logging; end
|
439
|
+
def pre_parse_argv
|
440
|
+
#--{{{
|
441
|
+
if(@options.has_key?('help') or (@argv.size == 1 and @argv.first =~ %r/help/i))
|
442
|
+
usage STDOUT
|
443
|
+
exit EXIT_SUCCESS
|
444
|
+
end
|
445
|
+
if(@options.has_key?('version') or @argv.first =~ %r/version/i)
|
446
|
+
STDOUT.puts self.class.version
|
447
|
+
exit EXIT_SUCCESS
|
448
|
+
end
|
449
|
+
#--}}}
|
450
|
+
end
|
451
|
+
def post_parse_argv; end
|
452
|
+
def pre_run; end
|
453
|
+
def post_run; end
|
454
|
+
def pre_main; end
|
455
|
+
def post_main; end
|
456
|
+
def logcatch
|
457
|
+
#--{{{
|
458
|
+
ret = nil
|
459
|
+
# @logger ||= Logger::new STDERR
|
460
|
+
logger!
|
461
|
+
begin
|
462
|
+
ret = yield
|
463
|
+
rescue Exception => e
|
464
|
+
unless SystemExit === e
|
465
|
+
fatal{ e }
|
466
|
+
exit EXIT_FAILURE
|
467
|
+
if false
|
468
|
+
if logger.debug?
|
469
|
+
fatal{ e }
|
470
|
+
exit EXIT_FAILURE
|
471
|
+
else
|
472
|
+
fatal{ emsg(e) }
|
473
|
+
exit EXIT_FAILURE
|
474
|
+
end
|
475
|
+
end
|
476
|
+
else
|
477
|
+
exit e.status
|
478
|
+
end
|
479
|
+
end
|
480
|
+
ret
|
481
|
+
#--}}}
|
482
|
+
end
|
483
|
+
def usage port = STDERR
|
484
|
+
#--{{{
|
485
|
+
port << klass::usage << "\n" if(klass::usage and not klass::usage.empty?)
|
486
|
+
port << klass::examples << "\n" if(klass::examples and not klass::examples.empty?)
|
487
|
+
|
488
|
+
if klass::optspec
|
489
|
+
port << 'OPTIONS' << "\n"
|
490
|
+
|
491
|
+
klass::optspec.each do |os|
|
492
|
+
a, b, c = os
|
493
|
+
long, short, desc = nil
|
494
|
+
[a,b,c].each do |word|
|
495
|
+
next unless word
|
496
|
+
word.strip!
|
497
|
+
case word
|
498
|
+
when %r/^--[^-]/o
|
499
|
+
long = word
|
500
|
+
when %r/^-[^-]/o
|
501
|
+
short = word
|
502
|
+
else
|
503
|
+
desc = word
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
spec = ((long and short) ? [long, short] : [long])
|
508
|
+
|
509
|
+
if spec
|
510
|
+
port << Util::columnize(spec.join(', '), :width => 80, :indent => 2)
|
511
|
+
port << "\n"
|
512
|
+
end
|
513
|
+
|
514
|
+
if desc
|
515
|
+
port << Util::columnize(desc, :width => 80, :indent => 8)
|
516
|
+
port << "\n"
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
port << "\n"
|
521
|
+
end
|
522
|
+
|
523
|
+
port
|
524
|
+
#--}}}
|
525
|
+
end
|
526
|
+
def parse_options
|
527
|
+
#--{{{
|
528
|
+
@op = OptionParser::new
|
529
|
+
@options = {}
|
530
|
+
@listoptions = Hash::new{|h,k| h[k] = []}
|
531
|
+
klass::optspec.each do |spec|
|
532
|
+
k = spec.first.gsub(%r/(?:--)|(?:=.*$)|(?:\s+)/o,'')
|
533
|
+
@op.def_option(*spec) do |v|
|
534
|
+
@options[k] = v
|
535
|
+
@listoptions[k] << v
|
536
|
+
end
|
537
|
+
end
|
538
|
+
begin
|
539
|
+
op.parse! @argv
|
540
|
+
rescue OptionParser::InvalidOption => e
|
541
|
+
# preverve unknown options
|
542
|
+
#e.recover(argv)
|
543
|
+
invalid_option e
|
544
|
+
end
|
545
|
+
@options
|
546
|
+
#--}}}
|
547
|
+
end
|
548
|
+
def invalid_option e
|
549
|
+
#--{{{
|
550
|
+
# e.recover argv
|
551
|
+
fatal{ e.to_s }
|
552
|
+
exit EXIT_FAILURE
|
553
|
+
#--}}}
|
554
|
+
end
|
555
|
+
def init_logging opts = @options
|
556
|
+
#--{{{
|
557
|
+
log = Util::getopt 'log', opts
|
558
|
+
log_age = Util::getopt 'log_age', opts
|
559
|
+
log_size = Util::getopt 'log_size', opts
|
560
|
+
verbosity = Util::getopt 'verbosity', opts
|
561
|
+
log_age = Integer log_age rescue nil
|
562
|
+
log_size = Integer log_size rescue nil
|
563
|
+
$logger = self.logger = Logger::new(log || STDERR, log_age, log_size)
|
564
|
+
#
|
565
|
+
# hack to fix Logger sync bug
|
566
|
+
#
|
567
|
+
begin
|
568
|
+
class << @logger; attr :logdev unless @logger.respond_to?(:logdev); end
|
569
|
+
@logdev = @logger.logdev.dev
|
570
|
+
@logdev.sync = true
|
571
|
+
rescue
|
572
|
+
nil
|
573
|
+
end
|
574
|
+
level = nil
|
575
|
+
verbosity ||= 'info'
|
576
|
+
verbosity =
|
577
|
+
case verbosity
|
578
|
+
when /^\s*(?:4|d|debug)\s*$/io
|
579
|
+
level = 'Logging::DEBUG'
|
580
|
+
4
|
581
|
+
when /^\s*(?:3|i|info)\s*$/io
|
582
|
+
level = 'Logging::INFO'
|
583
|
+
3
|
584
|
+
when /^\s*(?:2|w|warn)\s*$/io
|
585
|
+
level = 'Logging::WARN'
|
586
|
+
2
|
587
|
+
when /^\s*(?:1|e|error)\s*$/io
|
588
|
+
level = 'Logging::ERROR'
|
589
|
+
1
|
590
|
+
when /^\s*(?:0|f|fatal)\s*$/io
|
591
|
+
level = 'Logging::FATAL'
|
592
|
+
0
|
593
|
+
else
|
594
|
+
abort "illegal verbosity setting <#{ verbosity }>"
|
595
|
+
end
|
596
|
+
logger.level = 2 - ((verbosity % 5) - 2)
|
597
|
+
logger
|
598
|
+
#--}}}
|
599
|
+
end
|
600
|
+
def parse_argv
|
601
|
+
#--{{{
|
602
|
+
a, b = [], []
|
603
|
+
klass::required_arguments.each do |arg|
|
604
|
+
value = @argv.shift
|
605
|
+
if value
|
606
|
+
send "#{ arg }=", value
|
607
|
+
else
|
608
|
+
die 'msg' => "required_argument <#{ arg }> not given"
|
609
|
+
end
|
610
|
+
a << send("#{ arg }")
|
611
|
+
end
|
612
|
+
klass::optional_arguments.each do |arg|
|
613
|
+
value = @argv.shift
|
614
|
+
if value
|
615
|
+
send "#{ arg }=", value
|
616
|
+
end
|
617
|
+
b << send("#{ arg }")
|
618
|
+
end
|
619
|
+
[a, b, @argv]
|
620
|
+
#--}}}
|
621
|
+
end
|
622
|
+
def die opts = {}
|
623
|
+
#--{{{
|
624
|
+
msg = Util::getopt 'msg', opts, klass.usage
|
625
|
+
errno = Util::getopt 'errno', opts, EXIT_FAILURE
|
626
|
+
STDERR.puts("#{ msg }")
|
627
|
+
exit(Integer(errno))
|
628
|
+
#--}}}
|
629
|
+
end
|
630
|
+
def main
|
631
|
+
#--{{{
|
632
|
+
raise NotImplementedError, 'main'
|
633
|
+
#--}}}
|
634
|
+
end
|
635
|
+
def options? *keys
|
636
|
+
#--{{{
|
637
|
+
list = keys.map{|key| @options.has_key? key}
|
638
|
+
list.size > 0 and list.all?
|
639
|
+
#--}}}
|
640
|
+
end
|
641
|
+
alias_method "option?", "options?"
|
642
|
+
def options *keys
|
643
|
+
#--{{{
|
644
|
+
if keys.empty?
|
645
|
+
@options
|
646
|
+
else
|
647
|
+
keys.map{|key| @options[key]}
|
648
|
+
end
|
649
|
+
#--}}}
|
650
|
+
end
|
651
|
+
def option key
|
652
|
+
#--{{{
|
653
|
+
options(key).first
|
654
|
+
#--}}}
|
655
|
+
end
|
656
|
+
def defaults *a, &b
|
657
|
+
#--{{{
|
658
|
+
self.class.defaults *a, &b
|
659
|
+
#--}}}
|
660
|
+
end
|
661
|
+
alias_method "default", "defaults"
|
662
|
+
|
663
|
+
def argv_plus_stdin
|
664
|
+
#--{{{
|
665
|
+
stdin = argv.delete '-'
|
666
|
+
STDIN.each{|line| argv << line} if stdin
|
667
|
+
argv.map!{|arg| arg.strip}
|
668
|
+
argv
|
669
|
+
#--}}}
|
670
|
+
end
|
671
|
+
|
672
|
+
#
|
673
|
+
# casting methods
|
674
|
+
#
|
675
|
+
module Casting
|
676
|
+
#--{{{
|
677
|
+
def int_list *list
|
678
|
+
#--{{{
|
679
|
+
list.flatten.compact.map{|i| Util.atoi i}
|
680
|
+
#--}}}
|
681
|
+
end
|
682
|
+
def float_list *list
|
683
|
+
#--{{{
|
684
|
+
list.flatten.compact.map{|f| Float f}
|
685
|
+
#--}}}
|
686
|
+
end
|
687
|
+
def string_list *list
|
688
|
+
#--{{{
|
689
|
+
list.flatten.compact.map{|s| String s}
|
690
|
+
#--}}}
|
691
|
+
end
|
692
|
+
def string_cast arg
|
693
|
+
arg.to_s
|
694
|
+
end
|
695
|
+
def int_cast arg
|
696
|
+
Integer arg.to_s
|
697
|
+
end
|
698
|
+
def float_cast arg
|
699
|
+
Float arg
|
700
|
+
end
|
701
|
+
def bool_cast arg
|
702
|
+
arg ? true : false
|
703
|
+
end
|
704
|
+
def bool_cast arg
|
705
|
+
case arg
|
706
|
+
when Numeric
|
707
|
+
not arg.zero?
|
708
|
+
when String
|
709
|
+
case arg
|
710
|
+
when %r/^(1|t|true)$/i
|
711
|
+
true
|
712
|
+
when %r/^(0|f|false)$/i
|
713
|
+
false
|
714
|
+
else
|
715
|
+
raise ArgumentError, arg.inspect
|
716
|
+
end
|
717
|
+
else
|
718
|
+
arg ? true : false
|
719
|
+
end
|
720
|
+
end
|
721
|
+
def re_cast arg
|
722
|
+
Regexp === arg ? arg : %r/#{ arg }/
|
723
|
+
end
|
724
|
+
def pathname_cast arg, opts = {}
|
725
|
+
expand = opts['expand'] || opts[:expand]
|
726
|
+
pn = (Pathname === arg ? arg : Pathname.new(arg.to_s))
|
727
|
+
expand ? pn.expand_path : pn
|
728
|
+
end
|
729
|
+
#--}}}
|
730
|
+
end
|
731
|
+
include Casting
|
732
|
+
|
733
|
+
#
|
734
|
+
# param dsl and class
|
735
|
+
#
|
736
|
+
class Param < ::String
|
737
|
+
#--{{{
|
738
|
+
include Casting
|
739
|
+
|
740
|
+
def self.pattr name
|
741
|
+
#--{{{
|
742
|
+
module_eval <<-code
|
743
|
+
def #{ name } *_a, &b
|
744
|
+
_a.push lambda{ instance_eval &b } if b
|
745
|
+
_a.size == 0 ? (defined? @#{ name } and @#{ name }) : (@#{ name }=_a.shift)
|
746
|
+
end
|
747
|
+
def #{ name }?
|
748
|
+
defined?(@#{ name }) and @#{ name }
|
749
|
+
end
|
750
|
+
def #{ name }= val
|
751
|
+
#{ name }( val )
|
752
|
+
end
|
753
|
+
code
|
754
|
+
#--}}}
|
755
|
+
end
|
756
|
+
|
757
|
+
%w(
|
758
|
+
this
|
759
|
+
rhs
|
760
|
+
required_argument
|
761
|
+
optional_argument
|
762
|
+
long
|
763
|
+
short
|
764
|
+
description
|
765
|
+
default
|
766
|
+
munge
|
767
|
+
cast
|
768
|
+
).each{|a| pattr a}
|
769
|
+
|
770
|
+
alias_method 'desc', 'description'
|
771
|
+
alias_method 'synopsis', 'description'
|
772
|
+
|
773
|
+
{
|
774
|
+
'requires_argument' => 'required_argument',
|
775
|
+
'argument_required' => 'required_argument',
|
776
|
+
'arg_required' => 'required_argument',
|
777
|
+
'req_arg' => 'required_argument',
|
778
|
+
'opt_arg' => 'optional_argument',
|
779
|
+
'argument_optional' => 'optional_argument',
|
780
|
+
'arg_optional' => 'optional_argument',
|
781
|
+
}.each{|dst,src| define_method(dst){ send src, true }}
|
782
|
+
|
783
|
+
def initialize name, this = nil, &block
|
784
|
+
#--{{{
|
785
|
+
if name.is_a?(Array)
|
786
|
+
a, b, ignored = name
|
787
|
+
a, b = a.to_s, b.to_s
|
788
|
+
name = a.size > b.size ? a : b
|
789
|
+
st = a.size > b.size ? b : a
|
790
|
+
short st
|
791
|
+
end
|
792
|
+
|
793
|
+
name = name.to_s
|
794
|
+
@this = this
|
795
|
+
|
796
|
+
re = %r/\s*=\s*([^=]+)\s*$/
|
797
|
+
m, @rhs = re.match(name).to_a
|
798
|
+
name.gsub! re, '' if @rhs
|
799
|
+
name.gsub! %r/^\s*--/, ''
|
800
|
+
|
801
|
+
super(name.to_s.gsub(%r/^\s*--/,''))
|
802
|
+
instance_eval &block if block
|
803
|
+
#--}}}
|
804
|
+
end
|
805
|
+
def long
|
806
|
+
#--{{{
|
807
|
+
@long ||= "--#{ self }"
|
808
|
+
#--}}}
|
809
|
+
end
|
810
|
+
def to_a
|
811
|
+
#--{{{
|
812
|
+
[ long, short, description ].compact
|
813
|
+
#--}}}
|
814
|
+
end
|
815
|
+
def to_option
|
816
|
+
#--{{{
|
817
|
+
optspec = []
|
818
|
+
|
819
|
+
if long
|
820
|
+
s = "#{ long }"
|
821
|
+
if required_argument
|
822
|
+
s << "=#{ self }"
|
823
|
+
elsif optional_argument
|
824
|
+
s << "=[#{ self }]"
|
825
|
+
elsif rhs
|
826
|
+
s << "=#{ rhs }" unless s[%r/=/]
|
827
|
+
end
|
828
|
+
optspec << s
|
829
|
+
end
|
830
|
+
|
831
|
+
if short
|
832
|
+
s = "#{ short }".strip.gsub(%r/^-*/,'-')
|
833
|
+
optspec << s
|
834
|
+
end
|
835
|
+
|
836
|
+
if description
|
837
|
+
s = "#{ description }"
|
838
|
+
optspec << s
|
839
|
+
end
|
840
|
+
|
841
|
+
optspec
|
842
|
+
#--}}}
|
843
|
+
end
|
844
|
+
def argument what = :required
|
845
|
+
#--{{{
|
846
|
+
case what.to_s
|
847
|
+
when /opt/i
|
848
|
+
send "optional_argument", true
|
849
|
+
when /req/i
|
850
|
+
send "required_argument", true
|
851
|
+
else
|
852
|
+
raise "what <#{ what }>"
|
853
|
+
end
|
854
|
+
#--}}}
|
855
|
+
end
|
856
|
+
alias_method 'arg', 'argument'
|
857
|
+
def cast &b
|
858
|
+
#--{{{
|
859
|
+
b and @cast = b
|
860
|
+
cast? ? @cast : nil
|
861
|
+
#--}}}
|
862
|
+
end
|
863
|
+
def cast?
|
864
|
+
#--{{{
|
865
|
+
defined? @cast
|
866
|
+
#--}}}
|
867
|
+
end
|
868
|
+
def param name # call up!
|
869
|
+
#--{{{
|
870
|
+
@this.param name
|
871
|
+
#--}}}
|
872
|
+
end
|
873
|
+
def value this = self
|
874
|
+
#--{{{
|
875
|
+
if defined? @default
|
876
|
+
@default.respond_to?('call') ? @default.call : @default
|
877
|
+
else
|
878
|
+
nil
|
879
|
+
end
|
880
|
+
#--}}}
|
881
|
+
end
|
882
|
+
#--}}}
|
883
|
+
end
|
884
|
+
#
|
885
|
+
# meta-hooks for param dsl
|
886
|
+
#
|
887
|
+
class << self
|
888
|
+
#--{{{
|
889
|
+
def params
|
890
|
+
#--{{{
|
891
|
+
@params ||= {}
|
892
|
+
#--}}}
|
893
|
+
end
|
894
|
+
alias_method "parms", "params"
|
895
|
+
def param name, this = self, &block
|
896
|
+
#--{{{
|
897
|
+
parm =
|
898
|
+
if block or name.is_a?(Array)
|
899
|
+
param = Param.new name, this, &block
|
900
|
+
option *param.to_option
|
901
|
+
default param => param.default
|
902
|
+
params[ param.to_s ] = param
|
903
|
+
else
|
904
|
+
name = name.to_s
|
905
|
+
defined = params[ name ]
|
906
|
+
if defined
|
907
|
+
defined
|
908
|
+
else
|
909
|
+
param = Param.new name, this, &block
|
910
|
+
option *param.to_option
|
911
|
+
default param => param.default
|
912
|
+
params[ param.to_s ] = param
|
913
|
+
end
|
914
|
+
end
|
915
|
+
parm.value
|
916
|
+
#--}}}
|
917
|
+
end
|
918
|
+
alias_method "parm", "param"
|
919
|
+
def get_param name
|
920
|
+
params[ name.to_s ]
|
921
|
+
end
|
922
|
+
#--}}}
|
923
|
+
end
|
924
|
+
def params
|
925
|
+
#--{{{
|
926
|
+
self.class.params
|
927
|
+
#--}}}
|
928
|
+
end
|
929
|
+
alias_method "parms", "params"
|
930
|
+
def param? name
|
931
|
+
#--{{{
|
932
|
+
key = name.to_s
|
933
|
+
options.has_key? key
|
934
|
+
#--}}}
|
935
|
+
end
|
936
|
+
def param name, *a
|
937
|
+
#--{{{
|
938
|
+
key = name.to_s
|
939
|
+
pm = params[key] or raise "no such param <#{ key }>!"
|
940
|
+
|
941
|
+
value =
|
942
|
+
if options.has_key? key
|
943
|
+
options[key] || default(key)
|
944
|
+
else
|
945
|
+
a.empty? ? default(key) : a.shift
|
946
|
+
end
|
947
|
+
|
948
|
+
#value = value.call if value.respond_to?('call')
|
949
|
+
value = instance_eval &value if Proc === value
|
950
|
+
|
951
|
+
#value = pm.cast[value] if(option?(key) and pm.cast?)
|
952
|
+
value = pm.cast[value] if(value and pm.cast?)
|
953
|
+
|
954
|
+
value
|
955
|
+
#--}}}
|
956
|
+
end
|
957
|
+
alias_method "parm", "param"
|
958
|
+
|
959
|
+
|
960
|
+
def self.main &block
|
961
|
+
define_method :main, &block
|
962
|
+
end
|
963
|
+
#--}}}
|
964
|
+
end # class AbstractMain
|
965
|
+
|
966
|
+
class SimpleMain < AbstractMain
|
967
|
+
end
|
968
|
+
|
969
|
+
class ConfigurableMain < AbstractMain
|
970
|
+
#--{{{
|
971
|
+
def self.class_initialize
|
972
|
+
#--{{{
|
973
|
+
super
|
974
|
+
class_attribute :config_default_path
|
975
|
+
class_attribute :config_search_path
|
976
|
+
class_attribute :configfile
|
977
|
+
|
978
|
+
config_default_path "#{ prognam }.conf"
|
979
|
+
|
980
|
+
config_search_path %w(. ~ /usr/local/etc /usr/etc /etc)
|
981
|
+
|
982
|
+
configfile Class::new(ALib::ConfigFile) #{ default = DATA; DATA.rewind; }
|
983
|
+
|
984
|
+
optspec << [ '--config=path', 'valid path - specify config file (default nil)' ]
|
985
|
+
optspec << [ '--template=[path]', 'valid path - generate a template config file in path (default stdout)' ]
|
986
|
+
#--}}}
|
987
|
+
end
|
988
|
+
|
989
|
+
attribute :config
|
990
|
+
|
991
|
+
def pre_parse_argv
|
992
|
+
#--{{{
|
993
|
+
super
|
994
|
+
if(@options.has_key?('template') or @argv.first =~ %r/template/i)
|
995
|
+
@argv.shift if @argv.first =~ %r/template/i
|
996
|
+
arg = @argv.first
|
997
|
+
gen_template @options['template'] || @options['config'] || arg
|
998
|
+
exit EXIT_SUCCESS
|
999
|
+
end
|
1000
|
+
#--}}}
|
1001
|
+
end
|
1002
|
+
def gen_template template
|
1003
|
+
#--{{{
|
1004
|
+
klass::configfile::gen_template(template)
|
1005
|
+
self
|
1006
|
+
#--}}}
|
1007
|
+
end
|
1008
|
+
def post_parse_argv
|
1009
|
+
#--{{{
|
1010
|
+
init_config
|
1011
|
+
#--}}}
|
1012
|
+
end
|
1013
|
+
def init_config opts = @options
|
1014
|
+
#--{{{
|
1015
|
+
conf = Util::getopt 'config', opts
|
1016
|
+
@config =
|
1017
|
+
if conf
|
1018
|
+
klass::configfile::new(conf)
|
1019
|
+
else
|
1020
|
+
klass::configfile::any klass::config_default_path, klass::config_search_path
|
1021
|
+
end
|
1022
|
+
@config
|
1023
|
+
#--}}}
|
1024
|
+
end
|
1025
|
+
#--}}}
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
end
|
1029
|
+
|