module Main class Base class << self attribute( 'program' ){ File.basename $0 } attribute( 'name' ){ File.basename $0 } attribute( 'synopsis' ){ Usage.default_synopsis self } attribute( 'description' ) attribute( 'author' ) attribute( 'version' ) attribute( 'stdin' ){ $stdin } attribute( 'stdout' ){ $stdout } attribute( 'stderr' ){ $stderr } attribute( 'logger' ){ stderr } attribute( 'logger_level' ){ Logger::INFO } attribute( 'exit_status' ){ EXIT_SUCCESS } attribute( 'exit_success' ){ EXIT_SUCCESS } attribute( 'exit_failure' ){ EXIT_FAILURE } attribute( 'exit_warn' ){ EXIT_WARN } attribute( 'usage' ){ Usage.default_usage self } def parameters @parameters ||= Parameter::List[] end def parameter *a, &b parameters << Parameter.new(*a, &b) end def option *a, &b (parameters << Parameter.create(:option, *a, &b)).last end alias_method 'opt', 'option' alias_method 'switch', 'option' def default_options! option 'help', 'h' end def argument *a, &b (parameters << Parameter.create(:argument, *a, &b)).last end alias_method 'arg', 'argument' def keyword *a, &b (parameters << Parameter.create(:keyword, *a, &b)).last end alias_method 'kw', 'keyword' def environment *a, &b (parameters << Parameter.create(:environment, *a, &b)).last end alias_method 'env', 'environment' def run *a, &b define_method 'run' &b end end attribute 'argv' attribute 'env' attribute 'params' attribute 'logger' attribute 'stdin' attribute 'stdout' attribute 'stderr' %w( program name synopsis description author version exit_status exit_success exit_failure exit_warn logger_level usage ).each{|a| attribute(a){ self.class.send a}} %w( parameters param ).each do |dst| alias_method "#{ dst }", "params" alias_method "#{ dst }=", "params=" alias_method "#{ dst }?", "params?" end %w( exit_success! exit_failure! exit_warn! ).each do |code| module_eval <<-code def #{ code } *a, &b exit #{ code.chop } end code end %w( debug info warn fatal error ).each do |m| module_eval <<-code def #{ m } *a, &b logger.#{ m } *a, &b end code end def pre_initialize() :hook end def initialize argv = ARGV, env = ENV, opts = {} @argv, @env, @opts = argv, env, opts setup_finalizers setup_io_restoration setup_io_redirection setup_logging end def post_initialize() :hook end def setup_finalizers @finalizers = finalizers = [] ObjectSpace.define_finalizer(self) do while((f = finalizers.pop)); f.call; end end end def finalize while((f = @finalizers.pop)); f.call; end end 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 def setup_logging log = self.class.logger || stderr self.logger = log end 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 end def setup_io_restoration [STDIN, STDOUT, STDERR].each do |io| dup = io.dup and @finalizers.push lambda{ io.reopen dup } end end 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 #p STDIN #p STDIN.read end #p 'STDIN' => STDIN #p '@stdin' => @stdin #p '$stdin' => $stdin end end 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 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 def pre_parse_parameters() :hook end 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 def post_parse_parameters() :hook end def pre_run() end def run raise NotImplementedError, 'run not defined' end def post_run() end end end