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.
@@ -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
+