lib/main/base.rb in ThiagoLelis-backgroundjob-1.0.4 vs lib/main/base.rb in ThiagoLelis-backgroundjob-1.0.5
- old
+ new
@@ -1,515 +1,515 @@
-module Main
- class Base
- class << self
- def wrap_run!
- const_set :RUN, instance_method(:run)
-
- class_eval do
- def run *a, &b
- argv.push "--#{ argv.shift }" if argv.first == 'help'
- return mode_run! if mode_given?
-
- status =
- catch :exit do
- begin
-
- parse_parameters
-
- if params['help'] and params['help'].given?
- print usage.to_s
- exit
- end
-
- pre_run
- before_run
- self.class.const_get(:RUN).bind(self).call(*a, &b)
- after_run
- post_run
-
- finalize
- rescue Exception => e
- handle_exception e
- end
- nil
- end
-
- handle_throw status
- end
- end
- end
-
- 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
-
- def self.inheritable_fattr name, &block
- block ||= lambda{}
- fattr( 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
-
- # fattrs
- fattr( 'name' ){ File.basename $0 }
- fattr( 'synopsis' ){ Usage.default_synopsis(self) }
- fattr( 'description' )
- fattr( 'usage' ){ Usage.default_usage self }
- fattr( 'modes' ){ Mode.list }
- fattr( 'mode_definitions' ){ Array.new }
- fattr( 'mode_name' ){ 'main' }
- fattr( 'parent' ){ nil }
- fattr( 'children' ){ Set.new }
-
- fattr( 'program' ){ File.basename $0 }
- fattr( 'author' )
- fattr( 'version' )
- fattr( 'stdin' ){ $stdin }
- fattr( 'stdout' ){ $stdout }
- fattr( 'stderr' ){ $stderr }
- fattr( 'logger' ){ stderr }
- fattr( 'logger_level' ){ Logger::INFO }
- fattr( 'exit_status' ){ EXIT_SUCCESS }
- fattr( 'exit_success' ){ EXIT_SUCCESS }
- fattr( 'exit_failure' ){ EXIT_FAILURE }
- fattr( 'exit_warn' ){ EXIT_WARN }
- inheritable_fattr( 'parameters' ){ Parameter::List[] }
- inheritable_fattr( 'can_has_hash' ){ Hash.new }
- inheritable_fattr( 'mixin_table' ){ Hash.new }
-
- # override a few fattrs
- def mode_name=(value)
- @mode_name = Mode.new value
- end
-
- def usage *argv, &block
- usage! unless defined? @usage
- return @usage if argv.empty? and block.nil?
- key, value, *ignored = argv
- value = block.call if block
- @usage[key.to_s] = value.to_s
- end
-
- 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!
- #child.wrap_run! unless child.const_defined?(:RUN)
- mode_definitions.each do |name, block|
- klass =
- create context do
- mode_name name.to_s
- module_eval &block if block
- end
- modes.add klass
- end
- end
- end
- end
-
- def context &block
- @@context ||= []
- unless block
- @@context.last
- else
- begin
- @@context.push self
- block.call @@context.last
- ensure
- @@context.pop
- end
- end
- end
-
- module ::Main
- singleton_class{
- def current
- ::Main::Base.context
- end
- }
- end
-
- def fully_qualified_mode
- list = []
- ancestors.each do |ancestor|
- break unless ancestor < Base
- list << ancestor.mode_name
- end
- list.reverse[1..-1]
- end
-
- def run(&b) define_method(:run, &b) end
-
- def new(*a, &b)
- allocate.instance_eval do
- pre_initialize
- before_initialize
- main_initialize *a, &b
- initialize
- after_initialize
- post_initialize
- self
- end
- end
- end
-
- module DSL
- def parameter *a, &b
- (parameters << Parameter.create(:parameter, *a, &b)).last
- 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' unless parameters.has_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'
-
-=begin
- def mode name, &b
- klass =
- create context do
- mode_name name.to_s
- module_eval &b if b
- end
- modes.add klass
- end
-=end
-
- def mode name, &b
- mode_definitions << [name, b]
- end
-
- def can_has ptype, *a, &b
- key = a.map{|s| s.to_s}.sort_by{|s| -s.size }.first
- can_has_hash.update key => [ptype, a, b]
- key
- end
-
- def has key, *keys
- keys = [key, *keys].flatten.compact.map{|k| k.to_s}
- keys.map do |key|
- ptype, a, b = can_has_hash[key]
- abort "yo - can *not* has #{ key.inspect }!?" unless(ptype and a and b)
- send ptype, *a, &b
- key
- end
- end
-
- def mixin name, *names, &block
- names = [name, *names].flatten.compact.map{|name| name.to_s}
- if block
- names.each do |name|
- mixin_table[name] = block
- end
- else
- names.each do |name|
- module_eval &mixin_table[name]
- end
- end
- end
-
-## TODO - for some reason these hork the usage!
-
- %w[ examples samples api ].each do |chunkname|
- module_eval <<-code
- def #{ chunkname } *a, &b
- txt = b ? b.call : a.join("\\n")
- usage['#{ chunkname }'] = txt
- end
- code
- end
- alias_method 'example', 'examples'
- alias_method 'sample', 'samples'
- end
- extend DSL
-
- fattr 'argv'
- fattr 'env'
- fattr 'params'
- fattr 'logger'
- fattr 'stdin'
- fattr 'stdout'
- fattr 'stderr'
-
- %w(
- program name synopsis description author version
- exit_status exit_success exit_failure exit_warn
- logger_level
- usage
- ).each{|a| fattr(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( debug info warn fatal error ).each do |m|
- module_eval <<-code
- def #{ m } *a, &b
- logger.#{ m } *a, &b
- end
- code
- end
-
-=begin
-=end
- def pre_initialize() :hook end
- def before_initialize() :hook end
- def main_initialize argv = ARGV, env = ENV, opts = {}
- @argv, @env, @opts = argv, env, opts
- setup_finalizers
- setup_io_restoration
- setup_io_redirection
- setup_logging
- end
- def initialize() :hook end
- def after_initialize() :hook 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
- @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
-
- 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
- end
- 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 before_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 after_parse_parameters() :hook end
- def post_parse_parameters() :hook end
-
- def pre_run() :hook end
- def before_run() :hook end
- def run
- raise NotImplementedError, 'run not defined'
- end
- def after_run() :hook end
- def post_run() :hook end
-
- def mode_given?
- begin
- modes.size > 0 and
- argv.size > 0 and
- modes.find_by_mode(argv.first)
- rescue Mode::Ambiguous
- true
- end
- end
- 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
- def modes
- self.class.modes
- end
- fattr 'mode'
-
- def help! status = 0
- print usage.to_s
- exit(status)
- end
-
- def abort message = 'exit'
- raise SystemExit.new(message)
- end
-
- 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
- quiet = ((SystemExit === e and e.message.respond_to?('abort')) or # see main/stdext.rb
- (SystemExit === e and e.message == 'exit'))
- stderr.puts e.message unless quiet
- 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
-
- 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
-
- def handle_throw status
- exit(( Integer(status) rescue 0 ))
- end
-
- %w[ before instead after ].each do |which|
- module_eval <<-code
- def error_handler_#{ which } *argv, &block
- block.call *argv
- end
- code
- end
-
- 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
- end
-end
+module Main
+ class Base
+ class << self
+ def wrap_run!
+ const_set :RUN, instance_method(:run)
+
+ class_eval do
+ def run *a, &b
+ argv.push "--#{ argv.shift }" if argv.first == 'help'
+ return mode_run! if mode_given?
+
+ status =
+ catch :exit do
+ begin
+
+ parse_parameters
+
+ if params['help'] and params['help'].given?
+ print usage.to_s
+ exit
+ end
+
+ pre_run
+ before_run
+ self.class.const_get(:RUN).bind(self).call(*a, &b)
+ after_run
+ post_run
+
+ finalize
+ rescue Exception => e
+ handle_exception e
+ end
+ nil
+ end
+
+ handle_throw status
+ end
+ end
+ end
+
+ 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
+
+ def self.inheritable_fattr name, &block
+ block ||= lambda{}
+ fattr( 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
+
+ # fattrs
+ fattr( 'name' ){ File.basename $0 }
+ fattr( 'synopsis' ){ Usage.default_synopsis(self) }
+ fattr( 'description' )
+ fattr( 'usage' ){ Usage.default_usage self }
+ fattr( 'modes' ){ Mode.list }
+ fattr( 'mode_definitions' ){ Array.new }
+ fattr( 'mode_name' ){ 'main' }
+ fattr( 'parent' ){ nil }
+ fattr( 'children' ){ Set.new }
+
+ fattr( 'program' ){ File.basename $0 }
+ fattr( 'author' )
+ fattr( 'version' )
+ fattr( 'stdin' ){ $stdin }
+ fattr( 'stdout' ){ $stdout }
+ fattr( 'stderr' ){ $stderr }
+ fattr( 'logger' ){ stderr }
+ fattr( 'logger_level' ){ Logger::INFO }
+ fattr( 'exit_status' ){ EXIT_SUCCESS }
+ fattr( 'exit_success' ){ EXIT_SUCCESS }
+ fattr( 'exit_failure' ){ EXIT_FAILURE }
+ fattr( 'exit_warn' ){ EXIT_WARN }
+ inheritable_fattr( 'parameters' ){ Parameter::List[] }
+ inheritable_fattr( 'can_has_hash' ){ Hash.new }
+ inheritable_fattr( 'mixin_table' ){ Hash.new }
+
+ # override a few fattrs
+ def mode_name=(value)
+ @mode_name = Mode.new value
+ end
+
+ def usage *argv, &block
+ usage! unless defined? @usage
+ return @usage if argv.empty? and block.nil?
+ key, value, *ignored = argv
+ value = block.call if block
+ @usage[key.to_s] = value.to_s
+ end
+
+ 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!
+ #child.wrap_run! unless child.const_defined?(:RUN)
+ mode_definitions.each do |name, block|
+ klass =
+ create context do
+ mode_name name.to_s
+ module_eval &block if block
+ end
+ modes.add klass
+ end
+ end
+ end
+ end
+
+ def context &block
+ @@context ||= []
+ unless block
+ @@context.last
+ else
+ begin
+ @@context.push self
+ block.call @@context.last
+ ensure
+ @@context.pop
+ end
+ end
+ end
+
+ module ::Main
+ singleton_class{
+ def current
+ ::Main::Base.context
+ end
+ }
+ end
+
+ def fully_qualified_mode
+ list = []
+ ancestors.each do |ancestor|
+ break unless ancestor < Base
+ list << ancestor.mode_name
+ end
+ list.reverse[1..-1]
+ end
+
+ def run(&b) define_method(:run, &b) end
+
+ def new(*a, &b)
+ allocate.instance_eval do
+ pre_initialize
+ before_initialize
+ main_initialize *a, &b
+ initialize
+ after_initialize
+ post_initialize
+ self
+ end
+ end
+ end
+
+ module DSL
+ def parameter *a, &b
+ (parameters << Parameter.create(:parameter, *a, &b)).last
+ 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' unless parameters.has_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'
+
+=begin
+ def mode name, &b
+ klass =
+ create context do
+ mode_name name.to_s
+ module_eval &b if b
+ end
+ modes.add klass
+ end
+=end
+
+ def mode name, &b
+ mode_definitions << [name, b]
+ end
+
+ def can_has ptype, *a, &b
+ key = a.map{|s| s.to_s}.sort_by{|s| -s.size }.first
+ can_has_hash.update key => [ptype, a, b]
+ key
+ end
+
+ def has key, *keys
+ keys = [key, *keys].flatten.compact.map{|k| k.to_s}
+ keys.map do |key|
+ ptype, a, b = can_has_hash[key]
+ abort "yo - can *not* has #{ key.inspect }!?" unless(ptype and a and b)
+ send ptype, *a, &b
+ key
+ end
+ end
+
+ def mixin name, *names, &block
+ names = [name, *names].flatten.compact.map{|name| name.to_s}
+ if block
+ names.each do |name|
+ mixin_table[name] = block
+ end
+ else
+ names.each do |name|
+ module_eval &mixin_table[name]
+ end
+ end
+ end
+
+## TODO - for some reason these hork the usage!
+
+ %w[ examples samples api ].each do |chunkname|
+ module_eval <<-code
+ def #{ chunkname } *a, &b
+ txt = b ? b.call : a.join("\\n")
+ usage['#{ chunkname }'] = txt
+ end
+ code
+ end
+ alias_method 'example', 'examples'
+ alias_method 'sample', 'samples'
+ end
+ extend DSL
+
+ fattr 'argv'
+ fattr 'env'
+ fattr 'params'
+ fattr 'logger'
+ fattr 'stdin'
+ fattr 'stdout'
+ fattr 'stderr'
+
+ %w(
+ program name synopsis description author version
+ exit_status exit_success exit_failure exit_warn
+ logger_level
+ usage
+ ).each{|a| fattr(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( debug info warn fatal error ).each do |m|
+ module_eval <<-code
+ def #{ m } *a, &b
+ logger.#{ m } *a, &b
+ end
+ code
+ end
+
+=begin
+=end
+ def pre_initialize() :hook end
+ def before_initialize() :hook end
+ def main_initialize argv = ARGV, env = ENV, opts = {}
+ @argv, @env, @opts = argv, env, opts
+ setup_finalizers
+ setup_io_restoration
+ setup_io_redirection
+ setup_logging
+ end
+ def initialize() :hook end
+ def after_initialize() :hook 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
+ @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
+
+ 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
+ end
+ 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 before_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 after_parse_parameters() :hook end
+ def post_parse_parameters() :hook end
+
+ def pre_run() :hook end
+ def before_run() :hook end
+ def run
+ raise NotImplementedError, 'run not defined'
+ end
+ def after_run() :hook end
+ def post_run() :hook end
+
+ def mode_given?
+ begin
+ modes.size > 0 and
+ argv.size > 0 and
+ modes.find_by_mode(argv.first)
+ rescue Mode::Ambiguous
+ true
+ end
+ end
+ 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
+ def modes
+ self.class.modes
+ end
+ fattr 'mode'
+
+ def help! status = 0
+ print usage.to_s
+ exit(status)
+ end
+
+ def abort message = 'exit'
+ raise SystemExit.new(message)
+ end
+
+ 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
+ quiet = ((SystemExit === e and e.message.respond_to?('abort')) or # see main/stdext.rb
+ (SystemExit === e and e.message == 'exit'))
+ stderr.puts e.message unless quiet
+ 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
+
+ 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
+
+ def handle_throw status
+ exit(( Integer(status) rescue 0 ))
+ end
+
+ %w[ before instead after ].each do |which|
+ module_eval <<-code
+ def error_handler_#{ which } *argv, &block
+ block.call *argv
+ end
+ code
+ end
+
+ 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
+ end
+end