# = consoleapp.rb # # == Copyright (c) 2005 Thomas Sawyer # # Ruby License # # This module is free software. You may use, modify, and/or # redistribute this software under the same terms as Ruby. # # This program is distributed in the hope that it will be # useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. # # == Author(s) # # * Thomas Sawyer # # == Developer Notes # # TODO Add documentation features. (NOT SO SURE NOW!) # # TODO Move to console/command.rb, but I'm not sure yet if # adding subdirectories to more/ is a good idea. # # Author:: Thomas Sawyer # Copyright:: Copyright (c) 2005 Thomas Sawyer # License:: Ruby License # = Console # # Console namespace for use by tools specifically designed # for command line interfaces. module Console ; end # = Console Command # # Console::Command provides a clean and easy way # to create a command line interface for your program. # The unique technique utlizes a Commandline to Object # Mapping (COM) to make it quick and easy. # # == Synopsis # # Let's make an executable called 'mycmd'. # # #!/usr/bin/env ruby # # require 'facet/console_command' # # MyCmd << Console::Command # # def _v # $VERBOSE = true # end # # def jump # if $VERBOSE # puts "JUMP! JUMP! JUMP!" # else # puts "Jump" # end # end # # end # # MyCmd.execute # # Then on the command line: # # > mycmd jump # Jump # # > mycmd -v jump # JUMP! JUMP! JUMP! # #-- # You can also add help information quite easily. If the following code # is saved as 'foo' for instance. # # MyCmd << Console::Command # # help "Dispays the word JUMP!" # # def jump # if $VERBOSE # puts "JUMP! JUMP! JUMP!" # else # puts "Jump" # end # end # # end # # MyCmd.go # # then by running 'foo help' on the command line, standard help information # will be displayed. # # foo # # jump Displays the word JUMP! # #++ class Console::Command class << self # Starts the command execution. def execute( *args ) new.execute( *args ) end # Alias for #execute. alias_method :start, :execute end # Do not let this pass through on to # any included module. def initialize ; end # Execute the command. def execute( *argv ) argv = argv.empty? ? ARGV : argv # process options argv2 = argv.collect { |arg| if md = %r{^-(\w+)}.match( arg ) if md[1].size > 1 md[1].split(//).collect { |c| "-#{c}" } else arg end else arg end }.flatten args = argv2.dup i = 0; while i < args.size if md = %r{^[-]}.match( args[i] ) opt = args[i].gsub('-','_') if self.respond_to?( opt ) m = method( opt ) c = m.arity if c > 0 m.call(*args[i+1..i+c]) args[i..i+c] = nil i += c else m.call args[i] = nil end else $stderr << "Unknown option '#{args[i]}'\n" exit -1 end end i += 1 end args.compact! # no secondary commands if self.respond_to?(:main) main( *args ) # secondary commands elsif not args.empty? if self.respond_to?( args.first ) __send__( *args ) else if self.private_methods.include?( "no_command_error" ) no_command_error( *args ) else $stderr << "Non-applicable command #{args.join(' ')}\n" exit -1 end end # default secondary command elsif self.respond_to?( :default ) default(*args) # error else if self.private_methods.include?( "no_action_error" ) no_action_error( *args ) else $stderr << "Nothing to do.\n" exit -1 end end end # # We include a module here so you can define your own help command # # and call #super to utilize this one. # # module Help # # def help # opts = help_options # s = "" # s << "#{File.basename($0)}\n\n" # unless opts.empty? # s << "OPTIONS\n" # s << help_options # s << "\n" # end # s << "COMMANDS\n" # s << help_commands # puts s # end # # private # # def help_commands # help = self.class.help # bufs = help.keys.collect{ |a| a.to_s.size }.max + 3 # lines = [] # help.each { |cmd, str| # cmd = cmd.to_s # if cmd !~ /^_/ # lines << " " + cmd + (" " * (bufs - cmd.size)) + str # end # } # lines.join("\n") # end # # def help_options # help = self.class.help # bufs = help.keys.collect{ |a| a.to_s.size }.max + 3 # lines = [] # help.each { |cmd, str| # cmd = cmd.to_s # if cmd =~ /^_/ # lines << " " + cmd.gsub(/_/,'-') + (" " * (bufs - cmd.size)) + str # end # } # lines.join("\n") # end # # module ClassMethods # # def help( str=nil ) # return (@help ||= {}) unless str # @current_help = str # end # # def method_added( meth ) # if @current_help # @help ||= {} # @help[meth] = @current_help # @current_help = nil # end # end # # end # # end # # include Help # extend Help::ClassMethods end # _____ _ # |_ _|__ ___| |_ # | |/ _ \/ __| __| # | | __/\__ \ |_ # |_|\___||___/\__| # =begin test require 'test/unit' class TCCommand < Test::Unit::TestCase class MyCmd < Console::Command def _x ; $X = true ; end def _y ; $Y = true ; end def go ; $output = [$X, $Y] ; end end MyCmd.execute( '-x', '-y', 'go' ) def test_001 assert_equal( [true, true], $output ) end end =end