ThiagoLelis-backgroundjob 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/main.rb CHANGED
@@ -1,60 +1,60 @@
1
- module Main
2
- #
3
- # top level constants
4
- #
5
- Main::VERSION = '2.8.2' unless
6
- defined? Main::VERSION
7
- def self.version() Main::VERSION end
8
-
9
- Main::LIBDIR = File.join(File.dirname(File.expand_path(__FILE__)), self.name.downcase, '') unless
10
- defined? Main::LIBDIR
11
- def self.libdir() Main::LIBDIR end
12
-
13
- Main::EXIT_SUCCESS = 0 unless defined? Main::EXIT_SUCCESS
14
- Main::EXIT_FAILURE = 1 unless defined? Main::EXIT_FAILURE
15
- Main::EXIT_WARN = 42 unless defined? Main::EXIT_WARN
16
- #
17
- # built-in
18
- #
19
- require 'logger'
20
- require 'enumerator'
21
- require 'set'
22
- #
23
- # use gems to pick up dependancies
24
- #
25
- begin
26
- require 'rubygems'
27
- rescue LoadError
28
- 42
29
- end
30
-
31
- require 'fattr'
32
- begin
33
- version = Fattr.version
34
- raise unless version[%r/^1\./]
35
- rescue
36
- abort "main requires fattrs >= 1.0.3 - gem install fattr"
37
- end
38
-
39
- require 'arrayfields'
40
- begin
41
- version = Arrayfields.version
42
- raise unless version[%r/^4\./]
43
- rescue
44
- abort "main requires arrayfields >= 4.5.0 - gem install arrayfields"
45
- end
46
- #
47
- # main's own libs
48
- #
49
- require libdir + 'stdext'
50
- require libdir + 'softspoken'
51
- require libdir + 'util'
52
- require libdir + 'logger'
53
- require libdir + 'usage'
54
- require libdir + 'cast'
55
- require libdir + 'parameter'
56
- require libdir + 'getoptlong'
57
- require libdir + 'mode'
58
- require libdir + 'base'
59
- require libdir + 'factories'
60
- end
1
+ module Main
2
+ #
3
+ # top level constants
4
+ #
5
+ Main::VERSION = '2.8.2' unless
6
+ defined? Main::VERSION
7
+ def self.version() Main::VERSION end
8
+
9
+ Main::LIBDIR = File.join(File.dirname(File.expand_path(__FILE__)), self.name.downcase, '') unless
10
+ defined? Main::LIBDIR
11
+ def self.libdir() Main::LIBDIR end
12
+
13
+ Main::EXIT_SUCCESS = 0 unless defined? Main::EXIT_SUCCESS
14
+ Main::EXIT_FAILURE = 1 unless defined? Main::EXIT_FAILURE
15
+ Main::EXIT_WARN = 42 unless defined? Main::EXIT_WARN
16
+ #
17
+ # built-in
18
+ #
19
+ require 'logger'
20
+ require 'enumerator'
21
+ require 'set'
22
+ #
23
+ # use gems to pick up dependancies
24
+ #
25
+ begin
26
+ require 'rubygems'
27
+ rescue LoadError
28
+ 42
29
+ end
30
+
31
+ require 'fattr'
32
+ begin
33
+ version = Fattr.version
34
+ raise unless version[%r/^1\./]
35
+ rescue
36
+ abort "main requires fattrs >= 1.0.3 - gem install fattr"
37
+ end
38
+
39
+ require 'arrayfields'
40
+ begin
41
+ version = Arrayfields.version
42
+ raise unless version[%r/^4\./]
43
+ rescue
44
+ abort "main requires arrayfields >= 4.5.0 - gem install arrayfields"
45
+ end
46
+ #
47
+ # main's own libs
48
+ #
49
+ require libdir + 'stdext'
50
+ require libdir + 'softspoken'
51
+ require libdir + 'util'
52
+ require libdir + 'logger'
53
+ require libdir + 'usage'
54
+ require libdir + 'cast'
55
+ require libdir + 'parameter'
56
+ require libdir + 'getoptlong'
57
+ require libdir + 'mode'
58
+ require libdir + 'base'
59
+ require libdir + 'factories'
60
+ end
data/lib/main/base.rb CHANGED
@@ -1,515 +1,515 @@
1
- module Main
2
- class Base
3
- class << self
4
- def wrap_run!
5
- const_set :RUN, instance_method(:run)
6
-
7
- class_eval do
8
- def run *a, &b
9
- argv.push "--#{ argv.shift }" if argv.first == 'help'
10
- return mode_run! if mode_given?
11
-
12
- status =
13
- catch :exit do
14
- begin
15
-
16
- parse_parameters
17
-
18
- if params['help'] and params['help'].given?
19
- print usage.to_s
20
- exit
21
- end
22
-
23
- pre_run
24
- before_run
25
- self.class.const_get(:RUN).bind(self).call(*a, &b)
26
- after_run
27
- post_run
28
-
29
- finalize
30
- rescue Exception => e
31
- handle_exception e
32
- end
33
- nil
34
- end
35
-
36
- handle_throw status
37
- end
38
- end
39
- end
40
-
41
- def method_added m
42
- return if @in_method_added
43
- super if defined? super
44
- @in_method_added = true
45
- begin
46
- wrap_run! if m.to_s == 'run'
47
- ensure
48
- @in_method_added = false
49
- end
50
- end
51
-
52
- def self.inheritable_fattr name, &block
53
- block ||= lambda{}
54
- fattr( name ){
55
- catch :value do
56
- if parent?
57
- value = parent.send name
58
- value =
59
- begin
60
- Util.mcp value
61
- rescue
62
- value.clone rescue value.dup
63
- end
64
- throw :value, value
65
- end
66
- instance_eval &block
67
- end
68
- }
69
- end
70
-
71
- # fattrs
72
- fattr( 'name' ){ File.basename $0 }
73
- fattr( 'synopsis' ){ Usage.default_synopsis(self) }
74
- fattr( 'description' )
75
- fattr( 'usage' ){ Usage.default_usage self }
76
- fattr( 'modes' ){ Mode.list }
77
- fattr( 'mode_definitions' ){ Array.new }
78
- fattr( 'mode_name' ){ 'main' }
79
- fattr( 'parent' ){ nil }
80
- fattr( 'children' ){ Set.new }
81
-
82
- fattr( 'program' ){ File.basename $0 }
83
- fattr( 'author' )
84
- fattr( 'version' )
85
- fattr( 'stdin' ){ $stdin }
86
- fattr( 'stdout' ){ $stdout }
87
- fattr( 'stderr' ){ $stderr }
88
- fattr( 'logger' ){ stderr }
89
- fattr( 'logger_level' ){ Logger::INFO }
90
- fattr( 'exit_status' ){ EXIT_SUCCESS }
91
- fattr( 'exit_success' ){ EXIT_SUCCESS }
92
- fattr( 'exit_failure' ){ EXIT_FAILURE }
93
- fattr( 'exit_warn' ){ EXIT_WARN }
94
- inheritable_fattr( 'parameters' ){ Parameter::List[] }
95
- inheritable_fattr( 'can_has_hash' ){ Hash.new }
96
- inheritable_fattr( 'mixin_table' ){ Hash.new }
97
-
98
- # override a few fattrs
99
- def mode_name=(value)
100
- @mode_name = Mode.new value
101
- end
102
-
103
- def usage *argv, &block
104
- usage! unless defined? @usage
105
- return @usage if argv.empty? and block.nil?
106
- key, value, *ignored = argv
107
- value = block.call if block
108
- @usage[key.to_s] = value.to_s
109
- end
110
-
111
- def create parent = Base, *a, &b
112
- Class.new parent do |child|
113
- child.parent = parent unless parent == Base
114
- parent.children.add child
115
- child.context do
116
- child.class_eval &b if b
117
- child.default_options!
118
- #child.wrap_run! unless child.const_defined?(:RUN)
119
- mode_definitions.each do |name, block|
120
- klass =
121
- create context do
122
- mode_name name.to_s
123
- module_eval &block if block
124
- end
125
- modes.add klass
126
- end
127
- end
128
- end
129
- end
130
-
131
- def context &block
132
- @@context ||= []
133
- unless block
134
- @@context.last
135
- else
136
- begin
137
- @@context.push self
138
- block.call @@context.last
139
- ensure
140
- @@context.pop
141
- end
142
- end
143
- end
144
-
145
- module ::Main
146
- singleton_class{
147
- def current
148
- ::Main::Base.context
149
- end
150
- }
151
- end
152
-
153
- def fully_qualified_mode
154
- list = []
155
- ancestors.each do |ancestor|
156
- break unless ancestor < Base
157
- list << ancestor.mode_name
158
- end
159
- list.reverse[1..-1]
160
- end
161
-
162
- def run(&b) define_method(:run, &b) end
163
-
164
- def new(*a, &b)
165
- allocate.instance_eval do
166
- pre_initialize
167
- before_initialize
168
- main_initialize *a, &b
169
- initialize
170
- after_initialize
171
- post_initialize
172
- self
173
- end
174
- end
175
- end
176
-
177
- module DSL
178
- def parameter *a, &b
179
- (parameters << Parameter.create(:parameter, *a, &b)).last
180
- end
181
-
182
- def option *a, &b
183
- (parameters << Parameter.create(:option, *a, &b)).last
184
- end
185
- alias_method 'opt', 'option'
186
- alias_method 'switch', 'option'
187
-
188
- def default_options!
189
- option 'help', 'h' unless parameters.has_option?('help', 'h')
190
- end
191
-
192
- def argument *a, &b
193
- (parameters << Parameter.create(:argument, *a, &b)).last
194
- end
195
- alias_method 'arg', 'argument'
196
-
197
- def keyword *a, &b
198
- (parameters << Parameter.create(:keyword, *a, &b)).last
199
- end
200
- alias_method 'kw', 'keyword'
201
-
202
- def environment *a, &b
203
- (parameters << Parameter.create(:environment, *a, &b)).last
204
- end
205
- alias_method 'env', 'environment'
206
-
207
- =begin
208
- def mode name, &b
209
- klass =
210
- create context do
211
- mode_name name.to_s
212
- module_eval &b if b
213
- end
214
- modes.add klass
215
- end
216
- =end
217
-
218
- def mode name, &b
219
- mode_definitions << [name, b]
220
- end
221
-
222
- def can_has ptype, *a, &b
223
- key = a.map{|s| s.to_s}.sort_by{|s| -s.size }.first
224
- can_has_hash.update key => [ptype, a, b]
225
- key
226
- end
227
-
228
- def has key, *keys
229
- keys = [key, *keys].flatten.compact.map{|k| k.to_s}
230
- keys.map do |key|
231
- ptype, a, b = can_has_hash[key]
232
- abort "yo - can *not* has #{ key.inspect }!?" unless(ptype and a and b)
233
- send ptype, *a, &b
234
- key
235
- end
236
- end
237
-
238
- def mixin name, *names, &block
239
- names = [name, *names].flatten.compact.map{|name| name.to_s}
240
- if block
241
- names.each do |name|
242
- mixin_table[name] = block
243
- end
244
- else
245
- names.each do |name|
246
- module_eval &mixin_table[name]
247
- end
248
- end
249
- end
250
-
251
- ## TODO - for some reason these hork the usage!
252
-
253
- %w[ examples samples api ].each do |chunkname|
254
- module_eval <<-code
255
- def #{ chunkname } *a, &b
256
- txt = b ? b.call : a.join("\\n")
257
- usage['#{ chunkname }'] = txt
258
- end
259
- code
260
- end
261
- alias_method 'example', 'examples'
262
- alias_method 'sample', 'samples'
263
- end
264
- extend DSL
265
-
266
- fattr 'argv'
267
- fattr 'env'
268
- fattr 'params'
269
- fattr 'logger'
270
- fattr 'stdin'
271
- fattr 'stdout'
272
- fattr 'stderr'
273
-
274
- %w(
275
- program name synopsis description author version
276
- exit_status exit_success exit_failure exit_warn
277
- logger_level
278
- usage
279
- ).each{|a| fattr(a){ self.class.send a}}
280
-
281
- %w( parameters param ).each do |dst|
282
- alias_method "#{ dst }", "params"
283
- alias_method "#{ dst }=", "params="
284
- alias_method "#{ dst }?", "params?"
285
- end
286
-
287
- %w( debug info warn fatal error ).each do |m|
288
- module_eval <<-code
289
- def #{ m } *a, &b
290
- logger.#{ m } *a, &b
291
- end
292
- code
293
- end
294
-
295
- =begin
296
- =end
297
- def pre_initialize() :hook end
298
- def before_initialize() :hook end
299
- def main_initialize argv = ARGV, env = ENV, opts = {}
300
- @argv, @env, @opts = argv, env, opts
301
- setup_finalizers
302
- setup_io_restoration
303
- setup_io_redirection
304
- setup_logging
305
- end
306
- def initialize() :hook end
307
- def after_initialize() :hook end
308
- def post_initialize() :hook end
309
-
310
- def setup_finalizers
311
- @finalizers = finalizers = []
312
- ObjectSpace.define_finalizer(self) do
313
- while((f = finalizers.pop)); f.call; end
314
- end
315
- end
316
-
317
- def finalize
318
- while((f = @finalizers.pop)); f.call; end
319
- end
320
-
321
- def setup_io_redirection
322
- self.stdin = @opts['stdin'] || @opts[:stdin] || self.class.stdin
323
- self.stdout = @opts['stdout'] || @opts[:stdout] || self.class.stdout
324
- self.stderr = @opts['stderr'] || @opts[:stderr] || self.class.stderr
325
- end
326
-
327
- def setup_logging
328
- log = self.class.logger || stderr
329
- self.logger = log
330
- end
331
- def logger= log
332
- unless(defined?(@logger) and @logger == log)
333
- case log
334
- when ::Logger, Logger
335
- @logger = log
336
- when IO, StringIO
337
- @logger = Logger.new log
338
- @logger.level = logger_level
339
- else
340
- @logger = Logger.new *log
341
- @logger.level = logger_level
342
- end
343
- end
344
- @logger
345
- end
346
-
347
- def setup_io_restoration
348
- [STDIN, STDOUT, STDERR].each do |io|
349
- dup = io.dup and @finalizers.push lambda{ io.reopen dup }
350
- end
351
- end
352
-
353
- def stdin= io
354
- unless(defined?(@stdin) and (@stdin == io))
355
- @stdin =
356
- if io.respond_to? 'read'
357
- io
358
- else
359
- fd = open io.to_s, 'r+'
360
- @finalizers.push lambda{ fd.close }
361
- fd
362
- end
363
- begin
364
- STDIN.reopen @stdin
365
- rescue
366
- $stdin = @stdin
367
- ::Object.const_set 'STDIN', @stdin
368
- end
369
- end
370
- end
371
-
372
- def stdout= io
373
- unless(defined?(@stdout) and (@stdout == io))
374
- @stdout =
375
- if io.respond_to? 'write'
376
- io
377
- else
378
- fd = open io.to_s, 'w+'
379
- @finalizers.push lambda{ fd.close }
380
- fd
381
- end
382
- STDOUT.reopen @stdout rescue($stdout = @stdout)
383
- end
384
- end
385
-
386
- def stderr= io
387
- unless(defined?(@stderr) and (@stderr == io))
388
- @stderr =
389
- if io.respond_to? 'write'
390
- io
391
- else
392
- fd = open io.to_s, 'w+'
393
- @finalizers.push lambda{ fd.close }
394
- fd
395
- end
396
- STDERR.reopen @stderr rescue($stderr = @stderr)
397
- end
398
- end
399
-
400
- def pre_parse_parameters() :hook end
401
- def before_parse_parameters() :hook end
402
- def parse_parameters
403
- pre_parse_parameters
404
-
405
- self.class.parameters.parse @argv, @env
406
- @params = Parameter::Table.new
407
- self.class.parameters.each{|p| @params[p.name.to_s] = p}
408
-
409
- post_parse_parameters
410
- end
411
- def after_parse_parameters() :hook end
412
- def post_parse_parameters() :hook end
413
-
414
- def pre_run() :hook end
415
- def before_run() :hook end
416
- def run
417
- raise NotImplementedError, 'run not defined'
418
- end
419
- def after_run() :hook end
420
- def post_run() :hook end
421
-
422
- def mode_given?
423
- begin
424
- modes.size > 0 and
425
- argv.size > 0 and
426
- modes.find_by_mode(argv.first)
427
- rescue Mode::Ambiguous
428
- true
429
- end
430
- end
431
- def mode_run!
432
- mode = modes.find_by_mode argv.shift
433
- klass = modes[mode] or abort "bad mode <#{ mode }>"
434
- main = klass.new @argv, @env, @opts
435
- main.mode = mode
436
- main.run
437
- end
438
- def modes
439
- self.class.modes
440
- end
441
- fattr 'mode'
442
-
443
- def help! status = 0
444
- print usage.to_s
445
- exit(status)
446
- end
447
-
448
- def abort message = 'exit'
449
- raise SystemExit.new(message)
450
- end
451
-
452
- def handle_exception e
453
- if e.respond_to?(:error_handler_before)
454
- fcall(e, :error_handler_before, self)
455
- end
456
-
457
- if e.respond_to?(:error_handler_instead)
458
- fcall(e, :error_handler_instead, self)
459
- else
460
- if e.respond_to? :status
461
- exit_status(( e.status ))
462
- end
463
-
464
- if Softspoken === e or SystemExit === e
465
- quiet = ((SystemExit === e and e.message.respond_to?('abort')) or # see main/stdext.rb
466
- (SystemExit === e and e.message == 'exit'))
467
- stderr.puts e.message unless quiet
468
- else
469
- fatal{ e }
470
- end
471
- end
472
-
473
- if e.respond_to?(:error_handler_after)
474
- fcall(e, :error_handler_after, self)
475
- end
476
-
477
- exit_status(( exit_failure )) if exit_status == exit_success
478
- exit_status(( Integer(exit_status) rescue(exit_status ? 0 : 1) ))
479
- exit exit_status
480
- end
481
-
482
- def fcall obj, m, *argv, &block
483
- m = obj.method m
484
- arity = m.arity
485
- if arity >= 0
486
- argv = argv[0, arity]
487
- else
488
- arity = arity.abs - 1
489
- argv = argv[0, arity] + argv[arity .. -1]
490
- end
491
- m.call *argv, &block
492
- end
493
-
494
- def handle_throw status
495
- exit(( Integer(status) rescue 0 ))
496
- end
497
-
498
- %w[ before instead after ].each do |which|
499
- module_eval <<-code
500
- def error_handler_#{ which } *argv, &block
501
- block.call *argv
502
- end
503
- code
504
- end
505
-
506
- def instance_eval_block *argv, &block
507
- sc =
508
- class << self
509
- self
510
- end
511
- sc.module_eval{ define_method '__instance_eval_block', &block }
512
- fcall self, '__instance_eval_block', *argv, &block
513
- end
514
- end
515
- end
1
+ module Main
2
+ class Base
3
+ class << self
4
+ def wrap_run!
5
+ const_set :RUN, instance_method(:run)
6
+
7
+ class_eval do
8
+ def run *a, &b
9
+ argv.push "--#{ argv.shift }" if argv.first == 'help'
10
+ return mode_run! if mode_given?
11
+
12
+ status =
13
+ catch :exit do
14
+ begin
15
+
16
+ parse_parameters
17
+
18
+ if params['help'] and params['help'].given?
19
+ print usage.to_s
20
+ exit
21
+ end
22
+
23
+ pre_run
24
+ before_run
25
+ self.class.const_get(:RUN).bind(self).call(*a, &b)
26
+ after_run
27
+ post_run
28
+
29
+ finalize
30
+ rescue Exception => e
31
+ handle_exception e
32
+ end
33
+ nil
34
+ end
35
+
36
+ handle_throw status
37
+ end
38
+ end
39
+ end
40
+
41
+ def method_added m
42
+ return if @in_method_added
43
+ super if defined? super
44
+ @in_method_added = true
45
+ begin
46
+ wrap_run! if m.to_s == 'run'
47
+ ensure
48
+ @in_method_added = false
49
+ end
50
+ end
51
+
52
+ def self.inheritable_fattr name, &block
53
+ block ||= lambda{}
54
+ fattr( name ){
55
+ catch :value do
56
+ if parent?
57
+ value = parent.send name
58
+ value =
59
+ begin
60
+ Util.mcp value
61
+ rescue
62
+ value.clone rescue value.dup
63
+ end
64
+ throw :value, value
65
+ end
66
+ instance_eval &block
67
+ end
68
+ }
69
+ end
70
+
71
+ # fattrs
72
+ fattr( 'name' ){ File.basename $0 }
73
+ fattr( 'synopsis' ){ Usage.default_synopsis(self) }
74
+ fattr( 'description' )
75
+ fattr( 'usage' ){ Usage.default_usage self }
76
+ fattr( 'modes' ){ Mode.list }
77
+ fattr( 'mode_definitions' ){ Array.new }
78
+ fattr( 'mode_name' ){ 'main' }
79
+ fattr( 'parent' ){ nil }
80
+ fattr( 'children' ){ Set.new }
81
+
82
+ fattr( 'program' ){ File.basename $0 }
83
+ fattr( 'author' )
84
+ fattr( 'version' )
85
+ fattr( 'stdin' ){ $stdin }
86
+ fattr( 'stdout' ){ $stdout }
87
+ fattr( 'stderr' ){ $stderr }
88
+ fattr( 'logger' ){ stderr }
89
+ fattr( 'logger_level' ){ Logger::INFO }
90
+ fattr( 'exit_status' ){ EXIT_SUCCESS }
91
+ fattr( 'exit_success' ){ EXIT_SUCCESS }
92
+ fattr( 'exit_failure' ){ EXIT_FAILURE }
93
+ fattr( 'exit_warn' ){ EXIT_WARN }
94
+ inheritable_fattr( 'parameters' ){ Parameter::List[] }
95
+ inheritable_fattr( 'can_has_hash' ){ Hash.new }
96
+ inheritable_fattr( 'mixin_table' ){ Hash.new }
97
+
98
+ # override a few fattrs
99
+ def mode_name=(value)
100
+ @mode_name = Mode.new value
101
+ end
102
+
103
+ def usage *argv, &block
104
+ usage! unless defined? @usage
105
+ return @usage if argv.empty? and block.nil?
106
+ key, value, *ignored = argv
107
+ value = block.call if block
108
+ @usage[key.to_s] = value.to_s
109
+ end
110
+
111
+ def create parent = Base, *a, &b
112
+ Class.new parent do |child|
113
+ child.parent = parent unless parent == Base
114
+ parent.children.add child
115
+ child.context do
116
+ child.class_eval &b if b
117
+ child.default_options!
118
+ #child.wrap_run! unless child.const_defined?(:RUN)
119
+ mode_definitions.each do |name, block|
120
+ klass =
121
+ create context do
122
+ mode_name name.to_s
123
+ module_eval &block if block
124
+ end
125
+ modes.add klass
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ def context &block
132
+ @@context ||= []
133
+ unless block
134
+ @@context.last
135
+ else
136
+ begin
137
+ @@context.push self
138
+ block.call @@context.last
139
+ ensure
140
+ @@context.pop
141
+ end
142
+ end
143
+ end
144
+
145
+ module ::Main
146
+ singleton_class{
147
+ def current
148
+ ::Main::Base.context
149
+ end
150
+ }
151
+ end
152
+
153
+ def fully_qualified_mode
154
+ list = []
155
+ ancestors.each do |ancestor|
156
+ break unless ancestor < Base
157
+ list << ancestor.mode_name
158
+ end
159
+ list.reverse[1..-1]
160
+ end
161
+
162
+ def run(&b) define_method(:run, &b) end
163
+
164
+ def new(*a, &b)
165
+ allocate.instance_eval do
166
+ pre_initialize
167
+ before_initialize
168
+ main_initialize *a, &b
169
+ initialize
170
+ after_initialize
171
+ post_initialize
172
+ self
173
+ end
174
+ end
175
+ end
176
+
177
+ module DSL
178
+ def parameter *a, &b
179
+ (parameters << Parameter.create(:parameter, *a, &b)).last
180
+ end
181
+
182
+ def option *a, &b
183
+ (parameters << Parameter.create(:option, *a, &b)).last
184
+ end
185
+ alias_method 'opt', 'option'
186
+ alias_method 'switch', 'option'
187
+
188
+ def default_options!
189
+ option 'help', 'h' unless parameters.has_option?('help', 'h')
190
+ end
191
+
192
+ def argument *a, &b
193
+ (parameters << Parameter.create(:argument, *a, &b)).last
194
+ end
195
+ alias_method 'arg', 'argument'
196
+
197
+ def keyword *a, &b
198
+ (parameters << Parameter.create(:keyword, *a, &b)).last
199
+ end
200
+ alias_method 'kw', 'keyword'
201
+
202
+ def environment *a, &b
203
+ (parameters << Parameter.create(:environment, *a, &b)).last
204
+ end
205
+ alias_method 'env', 'environment'
206
+
207
+ =begin
208
+ def mode name, &b
209
+ klass =
210
+ create context do
211
+ mode_name name.to_s
212
+ module_eval &b if b
213
+ end
214
+ modes.add klass
215
+ end
216
+ =end
217
+
218
+ def mode name, &b
219
+ mode_definitions << [name, b]
220
+ end
221
+
222
+ def can_has ptype, *a, &b
223
+ key = a.map{|s| s.to_s}.sort_by{|s| -s.size }.first
224
+ can_has_hash.update key => [ptype, a, b]
225
+ key
226
+ end
227
+
228
+ def has key, *keys
229
+ keys = [key, *keys].flatten.compact.map{|k| k.to_s}
230
+ keys.map do |key|
231
+ ptype, a, b = can_has_hash[key]
232
+ abort "yo - can *not* has #{ key.inspect }!?" unless(ptype and a and b)
233
+ send ptype, *a, &b
234
+ key
235
+ end
236
+ end
237
+
238
+ def mixin name, *names, &block
239
+ names = [name, *names].flatten.compact.map{|name| name.to_s}
240
+ if block
241
+ names.each do |name|
242
+ mixin_table[name] = block
243
+ end
244
+ else
245
+ names.each do |name|
246
+ module_eval &mixin_table[name]
247
+ end
248
+ end
249
+ end
250
+
251
+ ## TODO - for some reason these hork the usage!
252
+
253
+ %w[ examples samples api ].each do |chunkname|
254
+ module_eval <<-code
255
+ def #{ chunkname } *a, &b
256
+ txt = b ? b.call : a.join("\\n")
257
+ usage['#{ chunkname }'] = txt
258
+ end
259
+ code
260
+ end
261
+ alias_method 'example', 'examples'
262
+ alias_method 'sample', 'samples'
263
+ end
264
+ extend DSL
265
+
266
+ fattr 'argv'
267
+ fattr 'env'
268
+ fattr 'params'
269
+ fattr 'logger'
270
+ fattr 'stdin'
271
+ fattr 'stdout'
272
+ fattr 'stderr'
273
+
274
+ %w(
275
+ program name synopsis description author version
276
+ exit_status exit_success exit_failure exit_warn
277
+ logger_level
278
+ usage
279
+ ).each{|a| fattr(a){ self.class.send a}}
280
+
281
+ %w( parameters param ).each do |dst|
282
+ alias_method "#{ dst }", "params"
283
+ alias_method "#{ dst }=", "params="
284
+ alias_method "#{ dst }?", "params?"
285
+ end
286
+
287
+ %w( debug info warn fatal error ).each do |m|
288
+ module_eval <<-code
289
+ def #{ m } *a, &b
290
+ logger.#{ m } *a, &b
291
+ end
292
+ code
293
+ end
294
+
295
+ =begin
296
+ =end
297
+ def pre_initialize() :hook end
298
+ def before_initialize() :hook end
299
+ def main_initialize argv = ARGV, env = ENV, opts = {}
300
+ @argv, @env, @opts = argv, env, opts
301
+ setup_finalizers
302
+ setup_io_restoration
303
+ setup_io_redirection
304
+ setup_logging
305
+ end
306
+ def initialize() :hook end
307
+ def after_initialize() :hook end
308
+ def post_initialize() :hook end
309
+
310
+ def setup_finalizers
311
+ @finalizers = finalizers = []
312
+ ObjectSpace.define_finalizer(self) do
313
+ while((f = finalizers.pop)); f.call; end
314
+ end
315
+ end
316
+
317
+ def finalize
318
+ while((f = @finalizers.pop)); f.call; end
319
+ end
320
+
321
+ def setup_io_redirection
322
+ self.stdin = @opts['stdin'] || @opts[:stdin] || self.class.stdin
323
+ self.stdout = @opts['stdout'] || @opts[:stdout] || self.class.stdout
324
+ self.stderr = @opts['stderr'] || @opts[:stderr] || self.class.stderr
325
+ end
326
+
327
+ def setup_logging
328
+ log = self.class.logger || stderr
329
+ self.logger = log
330
+ end
331
+ def logger= log
332
+ unless(defined?(@logger) and @logger == log)
333
+ case log
334
+ when ::Logger, Logger
335
+ @logger = log
336
+ when IO, StringIO
337
+ @logger = Logger.new log
338
+ @logger.level = logger_level
339
+ else
340
+ @logger = Logger.new *log
341
+ @logger.level = logger_level
342
+ end
343
+ end
344
+ @logger
345
+ end
346
+
347
+ def setup_io_restoration
348
+ [STDIN, STDOUT, STDERR].each do |io|
349
+ dup = io.dup and @finalizers.push lambda{ io.reopen dup }
350
+ end
351
+ end
352
+
353
+ def stdin= io
354
+ unless(defined?(@stdin) and (@stdin == io))
355
+ @stdin =
356
+ if io.respond_to? 'read'
357
+ io
358
+ else
359
+ fd = open io.to_s, 'r+'
360
+ @finalizers.push lambda{ fd.close }
361
+ fd
362
+ end
363
+ begin
364
+ STDIN.reopen @stdin
365
+ rescue
366
+ $stdin = @stdin
367
+ ::Object.const_set 'STDIN', @stdin
368
+ end
369
+ end
370
+ end
371
+
372
+ def stdout= io
373
+ unless(defined?(@stdout) and (@stdout == io))
374
+ @stdout =
375
+ if io.respond_to? 'write'
376
+ io
377
+ else
378
+ fd = open io.to_s, 'w+'
379
+ @finalizers.push lambda{ fd.close }
380
+ fd
381
+ end
382
+ STDOUT.reopen @stdout rescue($stdout = @stdout)
383
+ end
384
+ end
385
+
386
+ def stderr= io
387
+ unless(defined?(@stderr) and (@stderr == io))
388
+ @stderr =
389
+ if io.respond_to? 'write'
390
+ io
391
+ else
392
+ fd = open io.to_s, 'w+'
393
+ @finalizers.push lambda{ fd.close }
394
+ fd
395
+ end
396
+ STDERR.reopen @stderr rescue($stderr = @stderr)
397
+ end
398
+ end
399
+
400
+ def pre_parse_parameters() :hook end
401
+ def before_parse_parameters() :hook end
402
+ def parse_parameters
403
+ pre_parse_parameters
404
+
405
+ self.class.parameters.parse @argv, @env
406
+ @params = Parameter::Table.new
407
+ self.class.parameters.each{|p| @params[p.name.to_s] = p}
408
+
409
+ post_parse_parameters
410
+ end
411
+ def after_parse_parameters() :hook end
412
+ def post_parse_parameters() :hook end
413
+
414
+ def pre_run() :hook end
415
+ def before_run() :hook end
416
+ def run
417
+ raise NotImplementedError, 'run not defined'
418
+ end
419
+ def after_run() :hook end
420
+ def post_run() :hook end
421
+
422
+ def mode_given?
423
+ begin
424
+ modes.size > 0 and
425
+ argv.size > 0 and
426
+ modes.find_by_mode(argv.first)
427
+ rescue Mode::Ambiguous
428
+ true
429
+ end
430
+ end
431
+ def mode_run!
432
+ mode = modes.find_by_mode argv.shift
433
+ klass = modes[mode] or abort "bad mode <#{ mode }>"
434
+ main = klass.new @argv, @env, @opts
435
+ main.mode = mode
436
+ main.run
437
+ end
438
+ def modes
439
+ self.class.modes
440
+ end
441
+ fattr 'mode'
442
+
443
+ def help! status = 0
444
+ print usage.to_s
445
+ exit(status)
446
+ end
447
+
448
+ def abort message = 'exit'
449
+ raise SystemExit.new(message)
450
+ end
451
+
452
+ def handle_exception e
453
+ if e.respond_to?(:error_handler_before)
454
+ fcall(e, :error_handler_before, self)
455
+ end
456
+
457
+ if e.respond_to?(:error_handler_instead)
458
+ fcall(e, :error_handler_instead, self)
459
+ else
460
+ if e.respond_to? :status
461
+ exit_status(( e.status ))
462
+ end
463
+
464
+ if Softspoken === e or SystemExit === e
465
+ quiet = ((SystemExit === e and e.message.respond_to?('abort')) or # see main/stdext.rb
466
+ (SystemExit === e and e.message == 'exit'))
467
+ stderr.puts e.message unless quiet
468
+ else
469
+ fatal{ e }
470
+ end
471
+ end
472
+
473
+ if e.respond_to?(:error_handler_after)
474
+ fcall(e, :error_handler_after, self)
475
+ end
476
+
477
+ exit_status(( exit_failure )) if exit_status == exit_success
478
+ exit_status(( Integer(exit_status) rescue(exit_status ? 0 : 1) ))
479
+ exit exit_status
480
+ end
481
+
482
+ def fcall obj, m, *argv, &block
483
+ m = obj.method m
484
+ arity = m.arity
485
+ if arity >= 0
486
+ argv = argv[0, arity]
487
+ else
488
+ arity = arity.abs - 1
489
+ argv = argv[0, arity] + argv[arity .. -1]
490
+ end
491
+ m.call *argv, &block
492
+ end
493
+
494
+ def handle_throw status
495
+ exit(( Integer(status) rescue 0 ))
496
+ end
497
+
498
+ %w[ before instead after ].each do |which|
499
+ module_eval <<-code
500
+ def error_handler_#{ which } *argv, &block
501
+ block.call *argv
502
+ end
503
+ code
504
+ end
505
+
506
+ def instance_eval_block *argv, &block
507
+ sc =
508
+ class << self
509
+ self
510
+ end
511
+ sc.module_eval{ define_method '__instance_eval_block', &block }
512
+ fcall self, '__instance_eval_block', *argv, &block
513
+ end
514
+ end
515
+ end