class Getopt::Long

def self.getopts(*switches)


See the README file for more information.

)
["--level", "-l", NUMERIC]
["--verbose", "-v"],
["--debug"],
opts = Getopt::Long.getopts(

Example:

first letter of the short switch. The default type is BOOLEAN.
The long switch _must_ be provided. The short switch defaults to the

by the user.
for each key depends on the type of switch and/or the value provided
containing each switch name, minus the '-', as a key. The value
elements that indicate the name and type of switch. Returns a hash
Takes an array of switches. Each array consists of up to three
def self.getopts(*switches)
   if switches.empty?
      raise ArgumentError, "no switches provided"
   end
   hash  = {} # Hash returned to user
   valid = [] # Tracks valid switches
   types = {} # Tracks argument types
   syns  = {} # Tracks long and short arguments, or multiple shorts
   # If a string is passed, split it and convert it to an array of arrays
   if switches.first.kind_of?(String)
      switches = switches.join.split
      switches.map!{ |switch| switch = [switch] }
   end
   # Set our list of valid switches, and proper types for each switch
   switches.each{ |switch|
      valid.push(switch[0])       # Set valid long switches
      # Set type for long switch, default to BOOLEAN.
      if switch[1].kind_of?(Fixnum)
         switch[2] = switch[1]
         types[switch[0]] = switch[2]
         switch[1] = switch[0][1..2]
      else
         switch[2] ||= BOOLEAN
         types[switch[0]] = switch[2]
         switch[1] ||= switch[0][1..2]
      end
      # Create synonym hash.  Default to first char of long switch for 
      # short switch, e.g. "--verbose" creates a "-v" synonym.  The same
      # synonym can only be used once - first one wins.
      syns[switch[0]] = switch[1] unless syns[switch[1]]
      syns[switch[1]] = switch[0] unless syns[switch[1]]
      switch[1].each{ |char|      
         types[char] = switch[2]  # Set type for short switch
         valid.push(char)         # Set valid short switches
      }
      if ARGV.empty? && switch[2] == REQUIRED
        raise Error, "no value provided for required argument '#{switch[0]}'"
      end            
   }
   re_long     = /^(--\w+[-\w+]*)?$/
   re_short    = /^(-\w)$/
   re_long_eq  = /^(--\w+[-\w+]*)?=(.*?)$|(-\w?)=(.*?)$/
   re_short_sq = /^(-\w)(\S+?)$/
   ARGV.each_with_index{ |opt, index|
      # Allow either -x -v or -xv style for single char args
      if re_short_sq.match(opt)
         chars = opt.split("")[1..-1].map{ |s| s = "-#{s}" }
         chars.each_with_index{ |char, i|
            unless valid.include?(char)  
               raise Error, "invalid switch '#{char}'"
            end
            # Grab the next arg if the switch takes a required arg
            if types[char] == REQUIRED
               # Deal with a argument squished up against switch
               if chars[i+1]
                  arg = chars[i+1..-1].join.tr("-","")
                  ARGV.push(char, arg)
                  break
               else
                  arg = ARGV.delete_at(index+1)
                  if arg.nil? || valid.include?(arg) # Minor cheat here
                     err = "no value provided for required argument '#{char}'"
                     raise Error, err
                  end
                  ARGV.push(char, arg)
               end
            elsif types[char] == OPTIONAL
               if chars[i+1] && !valid.include?(chars[i+1])
                  arg = chars[i+1..-1].join.tr("-","")
                  ARGV.push(char, arg)
                  break
               elsif
                  if ARGV[index+1] && !valid.include?(ARGV[index+1])
                     arg = ARGV.delete_at(index+1)
                     ARGV.push(char, arg)
                  end
               else
                  ARGV.push(char)
               end
            else
               ARGV.push(char)
            end
         }
         next
      end
      if match = re_long.match(opt) || match = re_short.match(opt)
         switch = match.captures.first
      end
      if match = re_long_eq.match(opt)
         switch, value = match.captures.compact
         ARGV.push(switch, value)
         next
      end
      # Make sure that all the switches are valid.  If 'switch' isn't
      # defined at this point, it means an option was passed without
      # a preceding switch, e.g. --option foo bar.
      unless valid.include?(switch)
         switch ||= opt
         raise Error, "invalid switch '#{switch}'"
      end
      # Required arguments
      if types[switch] == REQUIRED
         nextval = ARGV[index+1]
         # Make sure there's a value for mandatory arguments
         if nextval.nil?
            err = "no value provided for required argument '#{switch}'"
            raise Error, err
         end
         # If there is a value, make sure it's not another switch
         if valid.include?(nextval)
            err = "cannot pass switch '#{nextval}' as an argument"
            raise Error, err
         end
         # If the same option appears more than once, put the values
         # in array.
         if hash[switch]
            hash[switch] = [hash[switch], nextval].flatten
         else
            hash[switch] = nextval
         end
         ARGV.delete_at(index+1)
      end
      # For boolean arguments set the switch's value to true.
      if types[switch] == BOOLEAN
         if hash.has_key?(switch)
            raise Error, "boolean switch already set"
         end
         hash[switch] = true
      end
      # For increment arguments, set the switch's value to 0, or
      # increment it by one if it already exists.
      if types[switch] == INCREMENT
         if hash.has_key?(switch)
            hash[switch] += 1
         else
            hash[switch] = 1
         end
      end
      # For optional argument, there may be an argument.  If so, it
      # cannot be another switch.  If not, it is set to true.
      if types[switch] == OPTIONAL
         nextval = ARGV[index+1]
         if valid.include?(nextval)
            hash[switch] = true
         else
            hash[switch] = nextval
            ARGV.delete_at(index+1)
         end
      end
   }
   # Set synonymous switches to the same value, e.g. if -t is a synonym
   # for --test, and the user passes "--test", then set "-t" to the same
   # value that "--test" was set to.
   #
   # This allows users to refer to the long or short switch and get
   # the same value
   hash.each{ |switch, val|
      if syns.keys.include?(switch)
         syns[switch].each{ |key|
            hash[key] = val   
         }
      end
   }
   # Get rid of leading "--" and "-" to make it easier to reference
   hash.each{ |key, value|
      if key[0,2] == '--'
         nkey = key.sub('--', '')
      else
         nkey = key.sub('-', '')
      end
      hash.delete(key)
      hash[nkey] = value
   }
   hash
end