Class: Main::Base

Inherits:
Object show all
Extended by:
DSL
Defined in:
lib/main/base.rb

Defined Under Namespace

Modules: DSL

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DSL

argument, default_options!, environment, keyword, mode, option, parameter

Constructor Details

#initialize(argv = ARGV, env = ENV, opts = {}) ⇒ Base

Returns a new instance of Base.



203
204
205
206
207
208
209
# File 'lib/main/base.rb', line 203

def initialize argv = ARGV, env = ENV, opts = {}
  @argv, @env, @opts = argv, env, opts
  setup_finalizers
  setup_io_restoration
  setup_io_redirection
  setup_logging
end

Class Method Details

.context(&block) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/main/base.rb', line 106

def context &block 
  @@context ||= []
  unless block 
    @@context.last
  else
    begin
      @@context.push self 
      block.call @@context.last
    ensure
      @@context.pop
    end
  end
end

.create(parent = Base, *a, &b) ⇒ Object



95
96
97
98
99
100
101
102
103
104
# File 'lib/main/base.rb', line 95

def create parent = Base, *a, &b
  Class.new parent do |child|
    child.parent = parent unless parent == Base
    parent.children.add child
    child.context do
      child.class_eval &b if b
      child.default_options!
    end
  end
end

.fully_qualified_modeObject



120
121
122
123
124
125
126
127
# File 'lib/main/base.rb', line 120

def fully_qualified_mode
  list = []
  ancestors.each do |ancestor|
    break unless ancestor < Base
    list << ancestor.mode_name
  end
  list.reverse[1..-1]
end

.inheritable_attribute(name, &block) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/main/base.rb', line 52

def self.inheritable_attribute name, &block
  block ||= lambda{}
  attribute( name ){ 
    catch :value do
      if parent?
        value = parent.send name 
        value =
          begin
            Util.mcp value
          rescue
            value.clone rescue value.dup
          end
        throw :value, value 
      end
      instance_eval &block
    end
  } 
end

.method_added(m) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/main/base.rb', line 41

def method_added m
  return if @in_method_added
  super if defined? super
  @in_method_added = true
  begin
    wrap_run! if m.to_s == 'run'
  ensure
    @in_method_added = false 
  end
end

.mode_name=(value) ⇒ Object



77
# File 'lib/main/base.rb', line 77

def mode_name=(value) @mode_name = Mode.new value end

.run(&b) ⇒ Object



129
# File 'lib/main/base.rb', line 129

def run(&b) define_method(:run, &b) end

.wrap_run!Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/main/base.rb', line 4

def wrap_run!
  const_set :RUN, instance_method(:run)

  class_eval do
    def run *a, &b
      status =
        catch :exit do
          begin
            argv.push "--#{ argv.shift }" if argv.first == 'help'

            return mode_run! if mode_given?

            parse_parameters

            if params['help'] and params['help'].given?
              print usage.to_s
              exit
            end

            pre_run

            self.class.const_get(:RUN).bind(self).call(*a, &b)

            post_run

            finalize
          rescue Exception => e
            handle_exception e
          end
          nil
        end

      handle_throw status
    end
  end
end

Instance Method Details

#fcall(obj, m, *argv, &block) ⇒ Object



374
375
376
377
378
379
380
381
382
383
384
# File 'lib/main/base.rb', line 374

def fcall obj, m, *argv, &block
  m = obj.method m
  arity = m.arity
  if arity >= 0
    argv = argv[0, arity]
  else
    arity = arity.abs - 1
    argv = argv[0, arity] + argv[arity .. -1]
  end
  m.call *argv, &block
end

#finalizeObject



219
220
221
# File 'lib/main/base.rb', line 219

def finalize
  while((f = @finalizers.pop)); f.call; end
end

#handle_exception(e) ⇒ Object



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/main/base.rb', line 346

def handle_exception e
  if e.respond_to?(:error_handler_before)
    fcall(e, :error_handler_before, self)
  end

  if e.respond_to?(:error_handler_instead)
    fcall(e, :error_handler_instead, self)
  else
    if e.respond_to? :status
      exit_status(( e.status ))
    end

    if Softspoken === e or SystemExit === e
      stderr.puts e.message unless(SystemExit === e and e.message.to_s == 'exit')
    else
      fatal{ e }
    end
  end

  if e.respond_to?(:error_handler_after)
    fcall(e, :error_handler_after, self)
  end

  exit_status(( exit_failure )) if exit_status == exit_success
  exit_status(( Integer(exit_status) rescue(exit_status ? 0 : 1) ))
  exit exit_status
end

#handle_throw(status) ⇒ Object



386
387
388
# File 'lib/main/base.rb', line 386

def handle_throw status
  exit(( Integer(status) rescue 0 ))
end

#help!(status = 0) ⇒ Object



341
342
343
344
# File 'lib/main/base.rb', line 341

def help! status = 0
  print usage.to_s
  exit(status)
end

#instance_eval_block(*argv, &block) ⇒ Object



398
399
400
401
402
403
404
405
# File 'lib/main/base.rb', line 398

def instance_eval_block *argv, &block
  sc =
    class << self
      self
    end
  sc.module_eval{ define_method '__instance_eval_block', &block }
  fcall self, '__instance_eval_block', *argv, &block
end

#logger=(log) ⇒ Object



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/main/base.rb', line 233

def logger= log
  unless(defined?(@logger) and @logger == log)
    case log 
      when Logger
        @logger = log
      when IO, StringIO
        @logger = Logger.new log 
        @logger.level = logger_level 
      else
        @logger = Logger.new *log
        @logger.level = logger_level 
    end
  end
  @logger
end

#mode_given?Boolean

Returns:

  • (Boolean)


320
321
322
323
324
325
326
327
328
# File 'lib/main/base.rb', line 320

def mode_given?
  begin
    modes.size > 0 and
    argv.size > 0 and
    modes.find_by_mode(argv.first)
  rescue Mode::Ambiguous
    true
  end
end

#mode_run!Object



329
330
331
332
333
334
335
# File 'lib/main/base.rb', line 329

def mode_run!
  mode = modes.find_by_mode argv.shift
  klass = modes[mode] or abort "bad mode <#{ mode }>"
  main = klass.new @argv, @env, @opts
  main.mode = mode
  main.run
end

#modesObject



336
337
338
# File 'lib/main/base.rb', line 336

def modes
  self.class.modes
end

#parse_parametersObject



303
304
305
306
307
308
309
310
311
# File 'lib/main/base.rb', line 303

def parse_parameters
  pre_parse_parameters

  self.class.parameters.parse @argv, @env
  @params = Parameter::Table.new
  self.class.parameters.each{|p| @params[p.name.to_s] = p}

  post_parse_parameters
end

#post_initializeObject



210
# File 'lib/main/base.rb', line 210

def post_initialize() :hook end

#post_parse_parametersObject



312
# File 'lib/main/base.rb', line 312

def post_parse_parameters() :hook end

#post_runObject



318
# File 'lib/main/base.rb', line 318

def post_run() :hook end

#pre_initializeObject



202
# File 'lib/main/base.rb', line 202

def pre_initialize() :hook end

#pre_parse_parametersObject



302
# File 'lib/main/base.rb', line 302

def pre_parse_parameters() :hook end

#pre_runObject



314
# File 'lib/main/base.rb', line 314

def pre_run() :hook end

#runObject

Raises:

  • (NotImplementedError)


315
316
317
# File 'lib/main/base.rb', line 315

def run
  raise NotImplementedError, 'run not defined'
end

#setup_finalizersObject



212
213
214
215
216
217
# File 'lib/main/base.rb', line 212

def setup_finalizers
  @finalizers = finalizers = []
  ObjectSpace.define_finalizer(self) do
    while((f = finalizers.pop)); f.call; end
  end
end

#setup_io_redirectionObject



223
224
225
226
227
# File 'lib/main/base.rb', line 223

def setup_io_redirection
  self.stdin = @opts['stdin'] || @opts[:stdin] || self.class.stdin
  self.stdout = @opts['stdout'] || @opts[:stdout] || self.class.stdout
  self.stderr = @opts['stderr'] || @opts[:stderr] || self.class.stderr
end

#setup_io_restorationObject



249
250
251
252
253
# File 'lib/main/base.rb', line 249

def setup_io_restoration
  [STDIN, STDOUT, STDERR].each do |io|
    dup = io.dup and @finalizers.push lambda{ io.reopen dup }
  end
end

#setup_loggingObject



229
230
231
232
# File 'lib/main/base.rb', line 229

def setup_logging
  log = self.class.logger || stderr
  self.logger = log
end

#stderr=(io) ⇒ Object



288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/main/base.rb', line 288

def stderr= io
  unless(defined?(@stderr) and (@stderr == io))
    @stderr =
      if io.respond_to? 'write'
        io
      else
        fd = open io.to_s, 'w+'
        @finalizers.push lambda{ fd.close }
        fd
      end
    STDERR.reopen @stderr rescue($stderr = @stderr)
  end
end

#stdin=(io) ⇒ Object



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/main/base.rb', line 255

def stdin= io
  unless(defined?(@stdin) and (@stdin == io))
    @stdin =
      if io.respond_to? 'read'
        io
      else
        fd = open io.to_s, 'r+'
        @finalizers.push lambda{ fd.close }
        fd
      end
    begin
      STDIN.reopen @stdin
    rescue
      $stdin = @stdin
      ::Object.const_set 'STDIN', @stdin
    end
  end
end

#stdout=(io) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/main/base.rb', line 274

def stdout= io
  unless(defined?(@stdout) and (@stdout == io))
    @stdout =
      if io.respond_to? 'write'
        io
      else
        fd = open io.to_s, 'w+'
        @finalizers.push lambda{ fd.close }
        fd
      end
    STDOUT.reopen @stdout rescue($stdout = @stdout)
  end
end