Class: Getopt::Long
Overview
The Getopt::Long class encapsulates longhanded parameter parsing options
Defined Under Namespace
Classes: Error
Constant Summary
Constants included from Version
Class Method Summary collapse
-
.getopts(*switches) ⇒ Object
Takes an array of switches.
Class Method Details
.getopts(*switches) ⇒ Object
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', INCREMENT]
)
See the README file for more information.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/getopt/long.rb', line 41 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?(Integer) 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] = [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.dup.each{ |switch, val| if syns.keys.include?(switch) syns[switch] = [syns[switch]] syns[switch].each{ |key| hash[key] = val } end } # Get rid of leading "--" and "-" to make it easier to reference hash.dup.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 |