lib/getopt/long.rb in getopt-1.3.6 vs lib/getopt/long.rb in getopt-1.3.7
- old
+ new
@@ -1,232 +1,234 @@
-module Getopt
-
- REQUIRED = 0
- BOOLEAN = 1
- OPTIONAL = 2
- INCREMENT = 3
- NEGATABLE = 4
- NUMERIC = 5
-
- class Long
- class Error < StandardError; end
-
- VERSION = '1.3.6'
-
- # Takes an array of switches. Each array consists of up to three
- # elements that indicate the name and type of switch. Returns a hash
- # containing each switch name, minus the '-', as a key. The value
- # for each key depends on the type of switch and/or the value provided
- # by the user.
- #
- # The long switch _must_ be provided. The short switch defaults to the
- # first letter of the short switch. The default type is BOOLEAN.
- #
- # Example:
- #
- # opts = Getopt::Long.getopts(
- # ["--debug"],
- # ["--verbose", "-v"],
- # ["--level", "-l", NUMERIC]
- # )
- #
- # See the README file for more information.
- #
- 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
- }
- }
-
- 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
-
- end
-end
+module Getopt
+
+ REQUIRED = 0
+ BOOLEAN = 1
+ OPTIONAL = 2
+ INCREMENT = 3
+ NEGATABLE = 4
+ NUMERIC = 5
+
+ class Long
+ class Error < StandardError; end
+
+ VERSION = '1.3.7'
+
+ # Takes an array of switches. Each array consists of up to three
+ # elements that indicate the name and type of switch. Returns a hash
+ # containing each switch name, minus the '-', as a key. The value
+ # for each key depends on the type of switch and/or the value provided
+ # by the user.
+ #
+ # The long switch _must_ be provided. The short switch defaults to the
+ # first letter of the short switch. The default type is BOOLEAN.
+ #
+ # Example:
+ #
+ # opts = Getopt::Long.getopts(
+ # ["--debug"],
+ # ["--verbose", "-v"],
+ # ["--level", "-l", NUMERIC]
+ # )
+ #
+ # See the README file for more information.
+ #
+ 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
+ }
+ }
+
+ 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 =~ /^-/
+ if key[0,2] == '--'
+ nkey = key.sub('--', '')
+ else
+ nkey = key.sub('-', '')
+ end
+ hash.delete(key)
+ hash[nkey] = value
+ end
+ }
+
+ hash
+ end
+
+ end
+end