main 0.0.1 → 0.0.2
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/README +220 -3
- data/README.tmpl +219 -3
- data/lib/main.rb +17 -10
- data/lib/main/arrayfields.rb +347 -0
- data/lib/main/attributes.rb +54 -0
- data/lib/main/base.rb +112 -44
- data/lib/main/factories.rb +6 -5
- data/lib/main/parameter.rb +2 -1
- data/lib/main/proxy.rb +54 -0
- data/test/main.rb +116 -1
- metadata +5 -4
- data/a.rb +0 -33
- data/main-0.0.1.gem +0 -0
data/lib/main.rb
CHANGED
@@ -1,24 +1,31 @@
|
|
1
1
|
module Main
|
2
|
-
VERSION = '0.0.
|
2
|
+
VERSION = '0.0.2'
|
3
|
+
def version() VERSION end
|
3
4
|
|
4
5
|
LIBDIR = File.join(File.dirname(File.expand_path(__FILE__)), self.name.downcase, '')
|
5
6
|
|
7
|
+
EXIT_SUCCESS = 0
|
8
|
+
EXIT_FAILURE = 1
|
9
|
+
EXIT_WARN = 42
|
10
|
+
#
|
11
|
+
# built-in
|
12
|
+
#
|
6
13
|
require 'logger'
|
7
14
|
require 'enumerator'
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
#
|
16
|
+
# inlcuded from other codeforpeople.com projects
|
17
|
+
#
|
18
|
+
require LIBDIR + 'attributes'
|
19
|
+
require LIBDIR + 'arrayfields'
|
20
|
+
#
|
21
|
+
# main libs
|
22
|
+
#
|
17
23
|
require LIBDIR + 'util'
|
18
24
|
require LIBDIR + 'usage'
|
19
25
|
require LIBDIR + 'cast'
|
20
26
|
require LIBDIR + 'parameter'
|
21
27
|
require LIBDIR + 'getoptlong'
|
28
|
+
require LIBDIR + 'proxy'
|
22
29
|
require LIBDIR + 'base'
|
23
30
|
require LIBDIR + 'factories'
|
24
31
|
end
|
@@ -0,0 +1,347 @@
|
|
1
|
+
#
|
2
|
+
# The ArrayFields module implements methods which allow an Array to be indexed
|
3
|
+
# by String or Symbol. It is not required to manually use this module to extend
|
4
|
+
# Array's - they are auto-extended when Array#fields= is called
|
5
|
+
#
|
6
|
+
module ArrayFields
|
7
|
+
#{{{
|
8
|
+
VERSION = '3.6.0'
|
9
|
+
#
|
10
|
+
# multiton cache of fields - wraps fields and fieldpos map to save memory
|
11
|
+
#
|
12
|
+
class FieldSet
|
13
|
+
#{{{
|
14
|
+
class << self
|
15
|
+
#{{{
|
16
|
+
def new fields
|
17
|
+
#{{{
|
18
|
+
@sets ||= {}
|
19
|
+
obj = @sets[fields]
|
20
|
+
unless obj
|
21
|
+
obj = super
|
22
|
+
@sets[fields] = obj
|
23
|
+
end
|
24
|
+
obj
|
25
|
+
#}}}
|
26
|
+
end
|
27
|
+
#}}}
|
28
|
+
end
|
29
|
+
attr :fields
|
30
|
+
attr :fieldpos
|
31
|
+
def initialize fields
|
32
|
+
#{{{
|
33
|
+
raise ArgumentError, "<#{ fields.inspect }> not inject-able" unless
|
34
|
+
fields.respond_to? :inject
|
35
|
+
|
36
|
+
@fieldpos =
|
37
|
+
fields.inject({}) do |h, f|
|
38
|
+
unless String === f or Symbol === f
|
39
|
+
raise ArgumentError, "<#{ f.inspect }> neither String nor Symbol"
|
40
|
+
end
|
41
|
+
h[f] = h.size
|
42
|
+
h
|
43
|
+
end
|
44
|
+
|
45
|
+
@fields = fields
|
46
|
+
#}}}
|
47
|
+
end
|
48
|
+
def pos f
|
49
|
+
#{{{
|
50
|
+
return @fieldpos[f] if @fieldpos.has_key? f
|
51
|
+
f = f.to_s
|
52
|
+
return @fieldpos[f] if @fieldpos.has_key? f
|
53
|
+
f = f.intern
|
54
|
+
return @fieldpos[f] if @fieldpos.has_key? f
|
55
|
+
nil
|
56
|
+
#}}}
|
57
|
+
end
|
58
|
+
#}}}
|
59
|
+
end
|
60
|
+
#
|
61
|
+
# methods redefined to work with fields as well as numeric indexes
|
62
|
+
#
|
63
|
+
def [](idx, *args)
|
64
|
+
#{{{
|
65
|
+
if @fieldset and (String === idx or Symbol === idx)
|
66
|
+
pos = @fieldset.pos idx
|
67
|
+
return nil unless pos
|
68
|
+
super(pos, *args)
|
69
|
+
else
|
70
|
+
super
|
71
|
+
end
|
72
|
+
#}}}
|
73
|
+
end
|
74
|
+
alias slice []
|
75
|
+
def []=(idx, *args)
|
76
|
+
#{{{
|
77
|
+
if @fieldset and (String === idx or Symbol === idx)
|
78
|
+
pos = @fieldset.pos idx
|
79
|
+
unless pos
|
80
|
+
@fieldset.fields << idx
|
81
|
+
@fieldset.fieldpos[idx] = pos = size
|
82
|
+
end
|
83
|
+
super(pos, *args)
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
#}}}
|
88
|
+
end
|
89
|
+
def at idx
|
90
|
+
#{{{
|
91
|
+
if @fieldset and (String === idx or Symbol === idx)
|
92
|
+
pos = @fieldset.pos idx
|
93
|
+
return nil unless pos
|
94
|
+
super pos
|
95
|
+
else
|
96
|
+
super
|
97
|
+
end
|
98
|
+
#}}}
|
99
|
+
end
|
100
|
+
def delete_at idx
|
101
|
+
#{{{
|
102
|
+
if @fieldset and (String === idx or Symbol === idx)
|
103
|
+
pos = @fieldset.pos idx
|
104
|
+
return nil unless pos
|
105
|
+
super pos
|
106
|
+
else
|
107
|
+
super
|
108
|
+
end
|
109
|
+
#}}}
|
110
|
+
end
|
111
|
+
def fill(obj, *args)
|
112
|
+
#{{{
|
113
|
+
idx = args.first
|
114
|
+
if idx and @fieldset and (String === idx or Symbol === idx)
|
115
|
+
idx = args.shift
|
116
|
+
pos = @fieldset.pos idx
|
117
|
+
super(obj, pos, *args)
|
118
|
+
else
|
119
|
+
super
|
120
|
+
end
|
121
|
+
#}}}
|
122
|
+
end
|
123
|
+
def values_at(*idxs)
|
124
|
+
#{{{
|
125
|
+
idxs.flatten!
|
126
|
+
if @fieldset
|
127
|
+
idxs.map!{|i| (String === i or Symbol === i) ? @fieldset.pos(i) : i}
|
128
|
+
end
|
129
|
+
super(*idxs)
|
130
|
+
#}}}
|
131
|
+
end
|
132
|
+
alias indices values_at
|
133
|
+
alias indexes values_at
|
134
|
+
def slice!(*args)
|
135
|
+
#{{{
|
136
|
+
ret = self[*args]
|
137
|
+
self[*args] = nil
|
138
|
+
ret
|
139
|
+
#}}}
|
140
|
+
end
|
141
|
+
def each_with_field
|
142
|
+
#{{{
|
143
|
+
each_with_index do |elem, i|
|
144
|
+
yield elem, @fieldset.fields[i]
|
145
|
+
end
|
146
|
+
#}}}
|
147
|
+
end
|
148
|
+
#
|
149
|
+
# methods which give a hash-like interface
|
150
|
+
#
|
151
|
+
def each_pair
|
152
|
+
#{{{
|
153
|
+
each_with_index do |elem, i|
|
154
|
+
yield @fieldset.fields[i], elem
|
155
|
+
end
|
156
|
+
#}}}
|
157
|
+
end
|
158
|
+
def each_key
|
159
|
+
#{{{
|
160
|
+
@fieldset.each{|field| yield field}
|
161
|
+
#}}}
|
162
|
+
end
|
163
|
+
def each_value(*args, &block)
|
164
|
+
#{{{
|
165
|
+
each(*args, &block)
|
166
|
+
#}}}
|
167
|
+
end
|
168
|
+
def fetch key
|
169
|
+
#{{{
|
170
|
+
self[key] or raise IndexError, 'key not found'
|
171
|
+
#}}}
|
172
|
+
end
|
173
|
+
def has_key? key
|
174
|
+
#{{{
|
175
|
+
@fieldset.fields.include? key
|
176
|
+
#}}}
|
177
|
+
end
|
178
|
+
alias member? has_key?
|
179
|
+
alias key? has_key?
|
180
|
+
def has_value? value
|
181
|
+
#{{{
|
182
|
+
if respond_to? 'include?'
|
183
|
+
self.include? value
|
184
|
+
else
|
185
|
+
a = []
|
186
|
+
each{|val| a << val}
|
187
|
+
a.include? value
|
188
|
+
end
|
189
|
+
#}}}
|
190
|
+
end
|
191
|
+
alias value? has_value?
|
192
|
+
def keys
|
193
|
+
#{{{
|
194
|
+
fields
|
195
|
+
#}}}
|
196
|
+
end
|
197
|
+
def store key, value
|
198
|
+
#{{{
|
199
|
+
self[key] = value
|
200
|
+
#}}}
|
201
|
+
end
|
202
|
+
def values
|
203
|
+
#{{{
|
204
|
+
if respond_to? 'to_ary'
|
205
|
+
self.to_ary
|
206
|
+
else
|
207
|
+
a = []
|
208
|
+
each{|val| a << val}
|
209
|
+
a
|
210
|
+
end
|
211
|
+
#}}}
|
212
|
+
end
|
213
|
+
def to_hash
|
214
|
+
#{{{
|
215
|
+
if respond_to? 'to_ary'
|
216
|
+
h = {}
|
217
|
+
@fieldset.fields.zip(to_ary){|f,e| h[f] = e}
|
218
|
+
h
|
219
|
+
else
|
220
|
+
a = []
|
221
|
+
each{|val| a << val}
|
222
|
+
h = {}
|
223
|
+
@fieldset.fields.zip(a){|f,e| h[f] = e}
|
224
|
+
h
|
225
|
+
end
|
226
|
+
#}}}
|
227
|
+
end
|
228
|
+
alias to_h to_hash
|
229
|
+
def update other
|
230
|
+
#--{{{
|
231
|
+
other.each{|k,v| self[k] = v}
|
232
|
+
to_hash
|
233
|
+
#--}}}
|
234
|
+
end
|
235
|
+
def replace other
|
236
|
+
#--{{{
|
237
|
+
Hash === other ? update(other) : super
|
238
|
+
#--}}}
|
239
|
+
end
|
240
|
+
def invert
|
241
|
+
#--{{{
|
242
|
+
to_hash.invert
|
243
|
+
#--}}}
|
244
|
+
end
|
245
|
+
#}}}
|
246
|
+
end
|
247
|
+
#
|
248
|
+
# Fieldable encapsulates methods in common for classes which may have their
|
249
|
+
# fields set
|
250
|
+
#
|
251
|
+
module Fieldable
|
252
|
+
#{{{
|
253
|
+
#
|
254
|
+
# sets fields an dynamically extends this Array instance with methods for
|
255
|
+
# keyword access
|
256
|
+
#
|
257
|
+
def fields= fields
|
258
|
+
#{{{
|
259
|
+
extend ArrayFields unless defined? @fieldset
|
260
|
+
|
261
|
+
@fieldset =
|
262
|
+
if ArrayFields::FieldSet === fields
|
263
|
+
fields
|
264
|
+
else
|
265
|
+
ArrayFields::FieldSet.new fields
|
266
|
+
end
|
267
|
+
#}}}
|
268
|
+
end
|
269
|
+
#
|
270
|
+
# access to fieldset
|
271
|
+
#
|
272
|
+
attr_reader :fieldset
|
273
|
+
#
|
274
|
+
# access to field list
|
275
|
+
#
|
276
|
+
def fields
|
277
|
+
#{{{
|
278
|
+
@fieldset and @fieldset.fields
|
279
|
+
#}}}
|
280
|
+
end
|
281
|
+
#}}}
|
282
|
+
end
|
283
|
+
#
|
284
|
+
# The Array class is extened with a methods to allow keyword access
|
285
|
+
#
|
286
|
+
class Array
|
287
|
+
#{{{
|
288
|
+
include Fieldable
|
289
|
+
#}}}
|
290
|
+
end
|
291
|
+
#
|
292
|
+
# proxy class that allows an array to be wrapped in a way that still allows #
|
293
|
+
# keyword access. also facilitate usage of ArrayFields with arraylike objects.
|
294
|
+
# thnx to Sean O'Dell for the suggestion.
|
295
|
+
#
|
296
|
+
# sample usage
|
297
|
+
#
|
298
|
+
# fa = FieldedArray.new %w(zero one two), [0,1,2]
|
299
|
+
# p fa['zero'] #=> 0
|
300
|
+
#
|
301
|
+
#
|
302
|
+
class FieldedArray
|
303
|
+
#{{{
|
304
|
+
include Fieldable
|
305
|
+
class << self
|
306
|
+
|
307
|
+
def [](*pairs)
|
308
|
+
#{{{
|
309
|
+
pairs.flatten!
|
310
|
+
raise ArgumentError, "argument must be key/val paris" unless
|
311
|
+
(pairs.size % 2 == 0 and pairs.size >= 2)
|
312
|
+
fields, elements = [], []
|
313
|
+
#pairs.each do |f,e|
|
314
|
+
while((f = pairs.shift) and (e = pairs.shift))
|
315
|
+
raise ArgumentError, "field must be String or Symbol" unless
|
316
|
+
(String === f or Symbol === f)
|
317
|
+
fields << f and elements << e
|
318
|
+
end
|
319
|
+
new fields, elements
|
320
|
+
#}}}
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
def initialize fields, array
|
325
|
+
#{{{
|
326
|
+
@a = array
|
327
|
+
self.fields = fields
|
328
|
+
#}}}
|
329
|
+
end
|
330
|
+
def method_missing(meth, *args, &block)
|
331
|
+
#{{{
|
332
|
+
@a.send(meth, *args, &block)
|
333
|
+
#}}}
|
334
|
+
end
|
335
|
+
delegates =
|
336
|
+
#{{{
|
337
|
+
%w(
|
338
|
+
to_s
|
339
|
+
to_str
|
340
|
+
inspect
|
341
|
+
)
|
342
|
+
#}}}
|
343
|
+
delegates.each do |meth|
|
344
|
+
class_eval "def #{ meth }(*a,&b); @a.#{ meth }(*a,&b);end"
|
345
|
+
end
|
346
|
+
#}}}
|
347
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Attributes
|
2
|
+
VERSION = '3.2.0'
|
3
|
+
|
4
|
+
def version() VERSION end
|
5
|
+
|
6
|
+
def attributes *a, &b
|
7
|
+
unless a.empty?
|
8
|
+
hashes, names = a.partition{|x| Hash === x}
|
9
|
+
|
10
|
+
names_and_defaults = {}
|
11
|
+
hashes.each{|h| names_and_defaults.update h}
|
12
|
+
names.flatten.compact.each{|name| names_and_defaults.update name => nil}
|
13
|
+
|
14
|
+
names_and_defaults.each do |name, default|
|
15
|
+
init = b || lambda { default }
|
16
|
+
ivar, getter, setter, query = "@#{ name }", "#{ name }", "#{ name }=", "#{ name }?"
|
17
|
+
|
18
|
+
define_method(setter) do |value|
|
19
|
+
instance_variable_set ivar, value
|
20
|
+
end
|
21
|
+
|
22
|
+
define_method(getter) do |*value|
|
23
|
+
unless value.empty?
|
24
|
+
send setter, value.shift
|
25
|
+
else
|
26
|
+
defined = instance_eval "defined? #{ ivar }"
|
27
|
+
send setter, instance_eval(&init) unless defined
|
28
|
+
instance_variable_get ivar
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method query, getter
|
33
|
+
|
34
|
+
(attributes << name).uniq!
|
35
|
+
attributes
|
36
|
+
end
|
37
|
+
else
|
38
|
+
@attributes ||= []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def attribute(*a, &b) attributes *a, &b end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Object
|
46
|
+
def attributes *a, &b
|
47
|
+
sc = class << self; self; end
|
48
|
+
sc.attributes *a, &b
|
49
|
+
end
|
50
|
+
|
51
|
+
def attribute(*a, &b) attributes *a, &b end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Module; include Attributes; end
|
data/lib/main/base.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
module Main
|
2
2
|
class Base
|
3
|
-
EXIT_SUCCESS = 0
|
4
|
-
EXIT_FAILURE = 1
|
5
|
-
EXIT_OK = 42
|
6
|
-
|
7
3
|
class << self
|
8
4
|
attribute( 'program' ){ File.basename $0 }
|
9
5
|
attribute( 'name' ){ File.basename $0 }
|
@@ -11,20 +7,17 @@ module Main
|
|
11
7
|
attribute( 'description' )
|
12
8
|
attribute( 'author' )
|
13
9
|
attribute( 'version' )
|
14
|
-
attribute( '
|
10
|
+
attribute( 'stdin' ){ $stdin }
|
11
|
+
attribute( 'stdout' ){ $stdout }
|
12
|
+
attribute( 'stderr' ){ $stderr }
|
13
|
+
attribute( 'logger' ){ stderr }
|
14
|
+
attribute( 'logger_level' ){ Logger::INFO }
|
15
15
|
attribute( 'exit_status' ){ EXIT_SUCCESS }
|
16
16
|
attribute( 'exit_success' ){ EXIT_SUCCESS }
|
17
17
|
attribute( 'exit_failure' ){ EXIT_FAILURE }
|
18
|
-
attribute( '
|
18
|
+
attribute( 'exit_warn' ){ EXIT_WARN }
|
19
19
|
attribute( 'usage' ){ Usage.default_usage self }
|
20
20
|
|
21
|
-
def new *a, &b
|
22
|
-
obj = allocate
|
23
|
-
obj.__initialize__
|
24
|
-
obj.instance_eval{ initialize *a, &b }
|
25
|
-
obj
|
26
|
-
end
|
27
|
-
|
28
21
|
def parameters
|
29
22
|
@parameters ||= Parameter::List[]
|
30
23
|
end
|
@@ -67,10 +60,14 @@ module Main
|
|
67
60
|
attribute 'env'
|
68
61
|
attribute 'params'
|
69
62
|
attribute 'logger'
|
63
|
+
attribute 'stdin'
|
64
|
+
attribute 'stdout'
|
65
|
+
attribute 'stderr'
|
70
66
|
|
71
67
|
%w(
|
72
68
|
program name synopsis description author version
|
73
|
-
exit_status exit_success exit_failure
|
69
|
+
exit_status exit_success exit_failure exit_warn
|
70
|
+
logger_level
|
74
71
|
usage
|
75
72
|
).each{|a| attribute(a){ self.class.send a}}
|
76
73
|
|
@@ -80,7 +77,7 @@ module Main
|
|
80
77
|
alias_method "#{ dst }?", "params?"
|
81
78
|
end
|
82
79
|
|
83
|
-
%w( exit_success! exit_failure!
|
80
|
+
%w( exit_success! exit_failure! exit_warn! ).each do |code|
|
84
81
|
module_eval <<-code
|
85
82
|
def #{ code } *a, &b
|
86
83
|
exit #{ code.chop }
|
@@ -96,55 +93,126 @@ module Main
|
|
96
93
|
code
|
97
94
|
end
|
98
95
|
|
99
|
-
def
|
100
|
-
|
96
|
+
def pre_initialize() :hook end
|
97
|
+
def initialize argv = ARGV, env = ENV, opts = {}
|
98
|
+
@argv, @env, @opts = argv, env, opts
|
99
|
+
setup_finalizers
|
100
|
+
setup_io_restoration
|
101
|
+
setup_io_redirection
|
102
|
+
setup_logging
|
103
|
+
end
|
104
|
+
def post_initialize() :hook end
|
105
|
+
|
106
|
+
def setup_finalizers
|
107
|
+
@finalizers = finalizers = []
|
108
|
+
ObjectSpace.define_finalizer(self) do
|
109
|
+
while((f = finalizers.pop)); f.call; end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def finalize
|
114
|
+
while((f = @finalizers.pop)); f.call; end
|
115
|
+
end
|
101
116
|
|
102
|
-
|
117
|
+
def setup_io_redirection
|
118
|
+
self.stdin = @opts['stdin'] || @opts[:stdin] || self.class.stdin
|
119
|
+
self.stdout = @opts['stdout'] || @opts[:stdout] || self.class.stdout
|
120
|
+
self.stderr = @opts['stderr'] || @opts[:stderr] || self.class.stderr
|
121
|
+
end
|
103
122
|
|
104
|
-
|
123
|
+
def setup_logging
|
124
|
+
log = self.class.logger || stderr
|
125
|
+
self.logger = log
|
126
|
+
end
|
127
|
+
def logger= log
|
128
|
+
unless(defined?(@logger) and @logger == log)
|
105
129
|
case log
|
106
130
|
when Logger
|
107
|
-
log
|
131
|
+
@logger = log
|
108
132
|
when IO, StringIO
|
109
|
-
Logger.new log
|
133
|
+
@logger = Logger.new log
|
134
|
+
@logger.level = logger_level
|
110
135
|
else
|
111
|
-
Logger.new *log
|
136
|
+
@logger = Logger.new *log
|
137
|
+
@logger.level = logger_level
|
112
138
|
end
|
139
|
+
end
|
140
|
+
end
|
113
141
|
|
114
|
-
|
142
|
+
def setup_io_restoration
|
143
|
+
[STDIN, STDOUT, STDERR].each do |io|
|
144
|
+
dup = io.dup and @finalizers.push lambda{ io.reopen dup }
|
145
|
+
end
|
115
146
|
end
|
116
147
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
148
|
+
def stdin= io
|
149
|
+
unless(defined?(@stdin) and (@stdin == io))
|
150
|
+
@stdin =
|
151
|
+
if io.respond_to? 'read'
|
152
|
+
io
|
153
|
+
else
|
154
|
+
fd = open io.to_s, 'r+'
|
155
|
+
@finalizers.push lambda{ fd.close }
|
156
|
+
fd
|
157
|
+
end
|
158
|
+
begin
|
159
|
+
STDIN.reopen @stdin
|
160
|
+
rescue
|
161
|
+
$stdin = @stdin
|
162
|
+
::Object.const_set 'STDIN', @stdin
|
163
|
+
#p STDIN
|
164
|
+
#p STDIN.read
|
165
|
+
end
|
166
|
+
#p 'STDIN' => STDIN
|
167
|
+
#p '@stdin' => @stdin
|
168
|
+
#p '$stdin' => $stdin
|
123
169
|
end
|
124
170
|
end
|
125
171
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
|
172
|
+
def stdout= io
|
173
|
+
unless(defined?(@stdout) and (@stdout == io))
|
174
|
+
@stdout =
|
175
|
+
if io.respond_to? 'write'
|
176
|
+
io
|
177
|
+
else
|
178
|
+
fd = open io.to_s, 'w+'
|
179
|
+
@finalizers.push lambda{ fd.close }
|
180
|
+
fd
|
181
|
+
end
|
182
|
+
STDOUT.reopen @stdout rescue($stdout = @stdout)
|
130
183
|
end
|
184
|
+
end
|
131
185
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
186
|
+
def stderr= io
|
187
|
+
unless(defined?(@stderr) and (@stderr == io))
|
188
|
+
@stderr =
|
189
|
+
if io.respond_to? 'write'
|
190
|
+
io
|
191
|
+
else
|
192
|
+
fd = open io.to_s, 'w+'
|
193
|
+
@finalizers.push lambda{ fd.close }
|
194
|
+
fd
|
195
|
+
end
|
196
|
+
STDERR.reopen @stderr rescue($stderr = @stderr)
|
141
197
|
end
|
142
|
-
status = Integer(exit_status) rescue(exit_status ? 0 : 1)
|
143
|
-
exit status
|
144
198
|
end
|
199
|
+
|
200
|
+
def pre_parse_parameters() :hook end
|
201
|
+
def parse_parameters
|
202
|
+
pre_parse_parameters
|
203
|
+
|
204
|
+
self.class.parameters.parse @argv, @env
|
205
|
+
@params = Parameter::Table.new
|
206
|
+
self.class.parameters.each{|p| @params[p.name.to_s] = p}
|
207
|
+
|
208
|
+
post_parse_parameters
|
209
|
+
end
|
210
|
+
def post_parse_parameters() :hook end
|
145
211
|
|
212
|
+
def pre_run() end
|
146
213
|
def run
|
147
214
|
raise NotImplementedError, 'run not defined'
|
148
215
|
end
|
216
|
+
def post_run() end
|
149
217
|
end
|
150
218
|
end
|