require "#{File.dirname(__FILE__)}/flag" require "#{File.dirname(__FILE__)}/exceptions" # Module used to parse commandline arguments module CommandLine # Parse argument lists and return an argument object containing all set flags and switches. class Arguments FLAG_REGEXP = /^--?[A-z0-9]/ attr_reader :flag_definitions attr_reader :flags attr_reader :files attr_reader :command attr_accessor :required_files # Initializer. # arguments The arguments which are going to be parsed (defaults to $*). def initialize(arguments = $*, &block) @arguments = arguments @flag_definitions = {} @begins_with_command = false end # Parse a list of arguments. Intatiates a Argument object with the given arguments and yeilds # it so that flags and switches can be set by the application. # arguments The arguments which are going to be parsed (defaults to $*). # Returns the arguments object.parse! def self.parse(arguments = $*, &block) cla = Arguments.new(arguments) yield(cla) return cla.parse! end # Handle argument switches for the application # switch A switch symbol like :fast # switch_alias An short alias for the same switch (:f). def switch(switch, switch_alias = nil) return self.flag(switch, :alias => switch_alias, :expects => nil) end # Handle argument flags for the application # flag A flag symbol like :fast # Options # * :expects Expects a value after the flag def flag(flag, options = {}) options[:expects] = String unless options.has_key?(:expects) argument = Flag.new(flag, options) @flag_definitions[argument.to_argument] = argument @flag_definitions[argument.to_alias] = argument if argument.has_alias? return argument end # If called argument list must begin with a command. # begins_w_command Defaults to true. def begins_with_command!(begins_w_command=true) @begins_with_command = begins_w_command end # Unknown flags will be silently ignored. # ignore Defaults to true. def ignore_unknown_flags!(ignore = true) @ignore_unknown_flags = ignore end def [](name) return flags[name.to_s.gsub(/_/, '-').to_sym] end # Parse the flags and switches set by the application. # Returns an arguments object containing the flags and switches found in the commandline. def parse! @flags = {} @files = [] i = 0 while @arguments.length > i do arg = @arguments[i] if FLAG_REGEXP =~ arg if @flag_definitions.has_key?(arg) flag = @flag_definitions[arg] if flag.expects_argument? if @arguments.length > (i + 1) && @arguments[i + 1] if flag.multiple? @flags[flag.name] ||= [] @flags[flag.name] << @arguments[i + 1] else @flags[flag.name] = @arguments[i + 1] end i += 1 else raise CommandLine::FlagExpectsArgument.new(arg) end else @flags[flag.name] = true end else raise CommandLine::UnknownFlag.new(arg) unless @ignore_unknown_flags end else if @begins_with_command && @command.nil? @command = arg else @files << arg end end i += 1 end check_parsed_arguments! return self end # Check if the parsed arguments meet their requirements. # Raises CommandLineexception on error. def check_parsed_arguments! @flag_definitions.each do |flag, definition| @flags[definition.name] ||= [] if definition.multiple? && !definition.default? @flags[definition.name] ||= definition.default if definition.default? end if @begins_with_command && @command.nil? raise CommandLine::CommandMissing.new end if @required_files && @files.length < @required_files raise CommandLine::FileMissing.new("You need at least #{@required_files} files") end end end end