lib/tap/app/api.rb in tap-0.19.0 vs lib/tap/app/api.rb in tap-1.3.0

- old
+ new

@@ -1,7 +1,6 @@ -require 'configurable' -require 'tap/signals/help' +require 'tap/app' module Tap class App # Api implements the application interface described in the @@ -28,11 +27,11 @@ # subclass. The parser is also setup to print usage (using the desc # for the subclass) and exit for the '-h' and '--help' options. # # The parse method uses parser by default, so subclasses can simply # modify parser and ensure parse still works correctly. - def parser + def parser(app) opts = ConfigParser.new unless configurations.empty? opts.separator "configurations:" opts.add(configurations) @@ -40,38 +39,48 @@ end opts.separator "options:" # add option to print help - opts.on("-h", "--help", "Print this help") do - puts "#{self}#{desc.empty? ? '' : ' -- '}#{desc.to_s}" - puts help - puts opts - exit + opts.on("--help", "Print this help") do + lines = ["#{self}#{desc.empty? ? '' : ' -- '}#{desc.to_s}"] + lines << help + lines << "usage: tap #{to_s.underscore} #{respond_to?(:args) ? args : nil}" + lines << nil + lines << opts + raise lines.join("\n") end opts end + def parse(argv=ARGV, app=Tap::App.current, &block) + parse!(argv.dup, app, &block) + end + # Parses the argv into an instance of self. Internally parse parses # an argh then calls build, but there is no requirement that this # occurs in subclasses. - def parse(argv=ARGV, app=Tap::App.instance) - parse!(argv.dup, app) - end - - # Same as parse, but removes arguments destructively. - def parse!(argv=ARGV, app=Tap::App.instance) - parser = self.parser - argv = parser.parse!(argv, :add_defaults => false) + # + # Returns the instance. If a block is given, the instance and any + # remaining arguments will be yielded to it. + def parse!(argv=ARGV, app=Tap::App.current) + parser = self.parser(app) + args = parser.parse!(argv, :add_defaults => false) + obj = build(convert_to_spec(parser, args), app) - [build({'config' => parser.nested_config}, app), argv] + if block_given? + yield(obj, args) + else + parser.warn_ignored_args(args) + obj + end end - + # Returns an instance of self. By default build calls new with the # configurations specified by spec['config'], and app. - def build(spec={}, app=Tap::App.instance) + def build(spec={}, app=Tap::App.current) new(spec['config'] || {}, app) end # Returns a help string that formats the desc documentation. def help @@ -83,21 +92,27 @@ lines.push(line) end lines.join("\n") end + + protected + + def convert_to_spec(parser, args) + {'config' => parser.nested_config} + end end include Configurable include Signals - signal :help, :class => Help, :bind => nil # signals help + define_signal :help, Help # signals help - # The App receiving self during enq + # The app for self attr_reader :app - def initialize(config={}, app=Tap::App.instance) + def initialize(config={}, app=Tap::App.current) @app = app initialize_config(config) end # By default associations returns nil. @@ -106,10 +121,16 @@ # By default to_spec returns a hash like {'config' => config} where # config is a stringified representation of the configurations for self. def to_spec config = self.config.to_hash {|hash, key, value| hash[key.to_s] = value } - {'config' => config} + config.empty? ? {} : {'config' => config} + end + + # Provides an abbreviated version of the default inspect, with only the + # class, object_id, and configurations listed. + def inspect + "#<#{self.class.to_s}:#{object_id} #{config.to_hash.inspect} >" end end end end \ No newline at end of file