getopt 1.3.9 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +7 -0
- data/README +1 -3
- data/Rakefile +34 -0
- data/getopt.gemspec +29 -0
- data/lib/getopt/long.rb +244 -0
- data/lib/getopt/std.rb +108 -0
- data/test/test_getopt_long.rb +1 -1
- data/test/test_getopt_std.rb +1 -1
- metadata +9 -5
data/CHANGES
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 1.4.0 - 5-Sep-2009
|
2
|
+
* Fixed a packaging bug where the libs weren't actually being included! Gah!
|
3
|
+
Thanks go to Steven Hilton for the spot.
|
4
|
+
* Other minor refactorings to the gemspec.
|
5
|
+
* The release number does not reflect any code changes. I simply ran out
|
6
|
+
of numbers. :)
|
7
|
+
|
1
8
|
== 1.3.9 - 29-Jul-2009
|
2
9
|
* Now compatible with Ruby 1.9.x.
|
3
10
|
* Gemspec updates, including a license change to Artistic 2.0.
|
data/README
CHANGED
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
desc "Install the getopt package (non-gem)"
|
5
|
+
task :install do
|
6
|
+
dest = File.join(Config::CONFIG['sitelibdir'], 'getopt')
|
7
|
+
Dir.mkdir(dest) unless File.exists? dest
|
8
|
+
cp 'lib/getopt/std.rb', dest, :verbose => true
|
9
|
+
cp 'lib/getopt/long.rb', dest, :verbose => true
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Install the getopt package as a gem"
|
13
|
+
task :install_gem do
|
14
|
+
ruby 'getopt.gemspec'
|
15
|
+
file = Dir["*.gem"].first
|
16
|
+
sh "gem install #{file}"
|
17
|
+
end
|
18
|
+
|
19
|
+
Rake::TestTask.new do |t|
|
20
|
+
t.warning = true
|
21
|
+
t.verbose = true
|
22
|
+
end
|
23
|
+
|
24
|
+
Rake::TestTask.new('test_getopt_long') do |t|
|
25
|
+
t.test_files = 'test/test_getopt_long.rb'
|
26
|
+
t.warning = true
|
27
|
+
t.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
Rake::TestTask.new('test_getopt_std') do |t|
|
31
|
+
t.test_files = 'test/test_getopt_std.rb'
|
32
|
+
t.warning = true
|
33
|
+
t.verbose = true
|
34
|
+
end
|
data/getopt.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'getopt'
|
5
|
+
gem.version = '1.4.0'
|
6
|
+
gem.author = 'Daniel J. Berger'
|
7
|
+
gem.license = 'Artistic 2.0'
|
8
|
+
gem.email = 'djberg96@gmail.com'
|
9
|
+
gem.homepage = 'http://www.rubyforge.org/projects/shards'
|
10
|
+
gem.platform = Gem::Platform::RUBY
|
11
|
+
gem.summary = 'Getopt::Std and Getopt::Long option parsers for Ruby'
|
12
|
+
gem.test_files = Dir['test/*.rb']
|
13
|
+
gem.has_rdoc = true
|
14
|
+
gem.files = Dir['**/*'].reject{ |f| f.include?('CVS') }
|
15
|
+
|
16
|
+
gem.rubyforge_project = 'shards'
|
17
|
+
gem.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
|
18
|
+
|
19
|
+
gem.add_development_dependency('test-unit', '>= 2.0.3')
|
20
|
+
|
21
|
+
gem.description = <<-EOF
|
22
|
+
The getopt library provides two different command line option parsers.
|
23
|
+
They are meant as easier and more convenient replacements for the
|
24
|
+
command line parsers that ship as part of the Ruby standard library.
|
25
|
+
Please see the README for additional comments.
|
26
|
+
EOF
|
27
|
+
end
|
28
|
+
|
29
|
+
Gem::Builder.new(spec).build
|
data/lib/getopt/long.rb
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
# The Getopt module serves as a namespace only
|
2
|
+
module Getopt
|
3
|
+
|
4
|
+
REQUIRED = 0 # Argument is required if switch is provided.
|
5
|
+
BOOLEAN = 1 # Value of argument is true if provided, false otherwise.
|
6
|
+
OPTIONAL = 2 # Argument is optional if switch is provided.
|
7
|
+
INCREMENT = 3 # Argument is incremented by 1 each time the switch appears.
|
8
|
+
|
9
|
+
# NEGATABLE = 4 # Automatically provide negative switch equivalent.
|
10
|
+
# INTEGER = 5 # Argument automatically converted to integer if provided.
|
11
|
+
# FLOAT = 6 # Argument automatically converted to float if provided.
|
12
|
+
|
13
|
+
# The Getopt::Long class encapsulates longhanded parameter parsing options
|
14
|
+
class Long
|
15
|
+
|
16
|
+
# Error raised if an illegal option or argument is passed
|
17
|
+
class Error < StandardError; end
|
18
|
+
|
19
|
+
# The version of the getopt library
|
20
|
+
VERSION = '1.4.0'
|
21
|
+
|
22
|
+
# Takes an array of switches. Each array consists of up to three
|
23
|
+
# elements that indicate the name and type of switch. Returns a hash
|
24
|
+
# containing each switch name, minus the '-', as a key. The value
|
25
|
+
# for each key depends on the type of switch and/or the value provided
|
26
|
+
# by the user.
|
27
|
+
#
|
28
|
+
# The long switch _must_ be provided. The short switch defaults to the
|
29
|
+
# first letter of the short switch. The default type is BOOLEAN.
|
30
|
+
#
|
31
|
+
# Example:
|
32
|
+
#
|
33
|
+
# opts = Getopt::Long.getopts(
|
34
|
+
# ['--debug' ],
|
35
|
+
# ['--verbose', '-v' ],
|
36
|
+
# ['--level', '-l', INCREMENT]
|
37
|
+
# )
|
38
|
+
#
|
39
|
+
# See the README file for more information.
|
40
|
+
#
|
41
|
+
def self.getopts(*switches)
|
42
|
+
if switches.empty?
|
43
|
+
raise ArgumentError, 'no switches provided'
|
44
|
+
end
|
45
|
+
|
46
|
+
hash = {} # Hash returned to user
|
47
|
+
valid = [] # Tracks valid switches
|
48
|
+
types = {} # Tracks argument types
|
49
|
+
syns = {} # Tracks long and short arguments, or multiple shorts
|
50
|
+
|
51
|
+
# If a string is passed, split it and convert it to an array of arrays
|
52
|
+
if switches.first.kind_of?(String)
|
53
|
+
switches = switches.join.split
|
54
|
+
switches.map!{ |switch| switch = [switch] }
|
55
|
+
end
|
56
|
+
|
57
|
+
# Set our list of valid switches, and proper types for each switch
|
58
|
+
switches.each{ |switch|
|
59
|
+
valid.push(switch[0]) # Set valid long switches
|
60
|
+
|
61
|
+
# Set type for long switch, default to BOOLEAN.
|
62
|
+
if switch[1].kind_of?(Fixnum)
|
63
|
+
switch[2] = switch[1]
|
64
|
+
types[switch[0]] = switch[2]
|
65
|
+
switch[1] = switch[0][1..2]
|
66
|
+
else
|
67
|
+
switch[2] ||= BOOLEAN
|
68
|
+
types[switch[0]] = switch[2]
|
69
|
+
switch[1] ||= switch[0][1..2]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Create synonym hash. Default to first char of long switch for
|
73
|
+
# short switch, e.g. "--verbose" creates a "-v" synonym. The same
|
74
|
+
# synonym can only be used once - first one wins.
|
75
|
+
syns[switch[0]] = switch[1] unless syns[switch[1]]
|
76
|
+
syns[switch[1]] = switch[0] unless syns[switch[1]]
|
77
|
+
|
78
|
+
switch[1] = [switch[1]] if RUBY_VERSION.to_f >= 1.9
|
79
|
+
|
80
|
+
switch[1].each{ |char|
|
81
|
+
types[char] = switch[2] # Set type for short switch
|
82
|
+
valid.push(char) # Set valid short switches
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
re_long = /^(--\w+[-\w+]*)?$/
|
87
|
+
re_short = /^(-\w)$/
|
88
|
+
re_long_eq = /^(--\w+[-\w+]*)?=(.*?)$|(-\w?)=(.*?)$/
|
89
|
+
re_short_sq = /^(-\w)(\S+?)$/
|
90
|
+
|
91
|
+
ARGV.each_with_index{ |opt, index|
|
92
|
+
|
93
|
+
# Allow either -x -v or -xv style for single char args
|
94
|
+
if re_short_sq.match(opt)
|
95
|
+
chars = opt.split("")[1..-1].map{ |s| s = "-#{s}" }
|
96
|
+
|
97
|
+
chars.each_with_index{ |char, i|
|
98
|
+
unless valid.include?(char)
|
99
|
+
raise Error, "invalid switch '#{char}'"
|
100
|
+
end
|
101
|
+
|
102
|
+
# Grab the next arg if the switch takes a required arg
|
103
|
+
if types[char] == REQUIRED
|
104
|
+
# Deal with a argument squished up against switch
|
105
|
+
if chars[i+1]
|
106
|
+
arg = chars[i+1..-1].join.tr('-', '')
|
107
|
+
ARGV.push(char, arg)
|
108
|
+
break
|
109
|
+
else
|
110
|
+
arg = ARGV.delete_at(index+1)
|
111
|
+
if arg.nil? || valid.include?(arg) # Minor cheat here
|
112
|
+
err = "no value provided for required argument '#{char}'"
|
113
|
+
raise Error, err
|
114
|
+
end
|
115
|
+
ARGV.push(char, arg)
|
116
|
+
end
|
117
|
+
elsif types[char] == OPTIONAL
|
118
|
+
if chars[i+1] && !valid.include?(chars[i+1])
|
119
|
+
arg = chars[i+1..-1].join.tr("-","")
|
120
|
+
ARGV.push(char, arg)
|
121
|
+
break
|
122
|
+
elsif
|
123
|
+
if ARGV[index+1] && !valid.include?(ARGV[index+1])
|
124
|
+
arg = ARGV.delete_at(index+1)
|
125
|
+
ARGV.push(char, arg)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
ARGV.push(char)
|
129
|
+
end
|
130
|
+
else
|
131
|
+
ARGV.push(char)
|
132
|
+
end
|
133
|
+
}
|
134
|
+
next
|
135
|
+
end
|
136
|
+
|
137
|
+
if match = re_long.match(opt) || match = re_short.match(opt)
|
138
|
+
switch = match.captures.first
|
139
|
+
end
|
140
|
+
|
141
|
+
if match = re_long_eq.match(opt)
|
142
|
+
switch, value = match.captures.compact
|
143
|
+
ARGV.push(switch, value)
|
144
|
+
next
|
145
|
+
end
|
146
|
+
|
147
|
+
# Make sure that all the switches are valid. If 'switch' isn't
|
148
|
+
# defined at this point, it means an option was passed without
|
149
|
+
# a preceding switch, e.g. --option foo bar.
|
150
|
+
unless valid.include?(switch)
|
151
|
+
switch ||= opt
|
152
|
+
raise Error, "invalid switch '#{switch}'"
|
153
|
+
end
|
154
|
+
|
155
|
+
# Required arguments
|
156
|
+
if types[switch] == REQUIRED
|
157
|
+
nextval = ARGV[index+1]
|
158
|
+
|
159
|
+
# Make sure there's a value for mandatory arguments
|
160
|
+
if nextval.nil?
|
161
|
+
err = "no value provided for required argument '#{switch}'"
|
162
|
+
raise Error, err
|
163
|
+
end
|
164
|
+
|
165
|
+
# If there is a value, make sure it's not another switch
|
166
|
+
if valid.include?(nextval)
|
167
|
+
err = "cannot pass switch '#{nextval}' as an argument"
|
168
|
+
raise Error, err
|
169
|
+
end
|
170
|
+
|
171
|
+
# If the same option appears more than once, put the values
|
172
|
+
# in array.
|
173
|
+
if hash[switch]
|
174
|
+
hash[switch] = [hash[switch], nextval].flatten
|
175
|
+
else
|
176
|
+
hash[switch] = nextval
|
177
|
+
end
|
178
|
+
ARGV.delete_at(index+1)
|
179
|
+
end
|
180
|
+
|
181
|
+
# For boolean arguments set the switch's value to true.
|
182
|
+
if types[switch] == BOOLEAN
|
183
|
+
if hash.has_key?(switch)
|
184
|
+
raise Error, 'boolean switch already set'
|
185
|
+
end
|
186
|
+
hash[switch] = true
|
187
|
+
end
|
188
|
+
|
189
|
+
# For increment arguments, set the switch's value to 0, or
|
190
|
+
# increment it by one if it already exists.
|
191
|
+
if types[switch] == INCREMENT
|
192
|
+
if hash.has_key?(switch)
|
193
|
+
hash[switch] += 1
|
194
|
+
else
|
195
|
+
hash[switch] = 1
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# For optional argument, there may be an argument. If so, it
|
200
|
+
# cannot be another switch. If not, it is set to true.
|
201
|
+
if types[switch] == OPTIONAL
|
202
|
+
nextval = ARGV[index+1]
|
203
|
+
if valid.include?(nextval)
|
204
|
+
hash[switch] = true
|
205
|
+
else
|
206
|
+
hash[switch] = nextval
|
207
|
+
ARGV.delete_at(index+1)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
}
|
211
|
+
|
212
|
+
# Set synonymous switches to the same value, e.g. if -t is a synonym
|
213
|
+
# for --test, and the user passes "--test", then set "-t" to the same
|
214
|
+
# value that "--test" was set to.
|
215
|
+
#
|
216
|
+
# This allows users to refer to the long or short switch and get
|
217
|
+
# the same value
|
218
|
+
hash.each{ |switch, val|
|
219
|
+
if syns.keys.include?(switch)
|
220
|
+
syns[switch] = [syns[switch]] if RUBY_VERSION.to_f >= 1.9
|
221
|
+
syns[switch].each{ |key|
|
222
|
+
hash[key] = val
|
223
|
+
}
|
224
|
+
end
|
225
|
+
}
|
226
|
+
|
227
|
+
# Get rid of leading "--" and "-" to make it easier to reference
|
228
|
+
hash.each{ |key, value|
|
229
|
+
if key =~ /^-/
|
230
|
+
if key[0,2] == '--'
|
231
|
+
nkey = key.sub('--', '')
|
232
|
+
else
|
233
|
+
nkey = key.sub('-', '')
|
234
|
+
end
|
235
|
+
hash.delete(key)
|
236
|
+
hash[nkey] = value
|
237
|
+
end
|
238
|
+
}
|
239
|
+
|
240
|
+
hash
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
end
|
data/lib/getopt/std.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# The Getopt module serves as a namespace only
|
2
|
+
module Getopt
|
3
|
+
|
4
|
+
# The Getopt::Std class serves as a base class for the getopts method.
|
5
|
+
class Std
|
6
|
+
|
7
|
+
# The Getopt::Std::Error class is raised if there are any illegal
|
8
|
+
# command line arguments.
|
9
|
+
#
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
# The version of the getopt library
|
13
|
+
VERSION = '1.4.0'
|
14
|
+
|
15
|
+
# Processes single character command line options with option
|
16
|
+
# clustering. This information is parsed from ARGV and returned
|
17
|
+
# as a hash, with the switch (minus the "-") as the key. The value
|
18
|
+
# for that key is either true/false (boolean switches) or the argument
|
19
|
+
# that was passed to the switch.
|
20
|
+
#
|
21
|
+
# Characters followed by a ":" require an argument. The rest are
|
22
|
+
# considered boolean switches. If a switch that accepts an argument
|
23
|
+
# appears more than once, the value for that key becomes an array
|
24
|
+
# of values.
|
25
|
+
#
|
26
|
+
# Example:
|
27
|
+
#
|
28
|
+
# # Look for -o with argument, and -I and -D boolean arguments
|
29
|
+
# opt = Getopt::Std.getopts("o:ID")
|
30
|
+
#
|
31
|
+
# if opt["I"]
|
32
|
+
# # Do something if -I passed
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# if opt["D"]
|
36
|
+
# # Do something if -D passed
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# if opt["o"]
|
40
|
+
# case opt["o"]
|
41
|
+
# # Do something
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
def self.getopts(switches)
|
46
|
+
args = switches.split(/ */)
|
47
|
+
hash = {}
|
48
|
+
|
49
|
+
while !ARGV.empty? && ARGV.first =~ /^-(.)(.*)/s
|
50
|
+
first, rest = $1, $2
|
51
|
+
pos = switches.index(first)
|
52
|
+
|
53
|
+
# Switches on the command line must appear among the characters
|
54
|
+
# declared in +switches+.
|
55
|
+
raise Error, "invalid option '#{first}'" unless pos
|
56
|
+
|
57
|
+
if args[pos+1] == ":"
|
58
|
+
ARGV.shift
|
59
|
+
if rest.empty?
|
60
|
+
rest = ARGV.shift
|
61
|
+
|
62
|
+
# Ensure that switches requiring arguments actually
|
63
|
+
# receive a (non-switch) argument.
|
64
|
+
if rest.nil? || rest.empty?
|
65
|
+
raise Error, "missing argument for '-#{args[pos]}'"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Do not permit switches that require arguments to be
|
69
|
+
# followed immediately by another switch.
|
70
|
+
temp_args = args.map{ |e| "-#{e}" }
|
71
|
+
|
72
|
+
if temp_args.include?(rest) || temp_args.include?(rest[1..-1])
|
73
|
+
err = "cannot use switch '#{rest}' as argument "
|
74
|
+
err << "to another switch"
|
75
|
+
raise Error, err
|
76
|
+
end
|
77
|
+
|
78
|
+
# For non boolean switches, arguments that appear multiple
|
79
|
+
# times are converted to an array (or pushed onto an already
|
80
|
+
# existant array).
|
81
|
+
if hash.has_key?(first)
|
82
|
+
hash[first] = [hash[first], rest].flatten
|
83
|
+
else
|
84
|
+
hash[first] = rest
|
85
|
+
end
|
86
|
+
else
|
87
|
+
# Do not permit switches that require arguments to be
|
88
|
+
# followed immediately by another switch.
|
89
|
+
if args.include?(rest) || args.include?(rest[1..-1])
|
90
|
+
err = "cannot use switch '#{rest}' as argument "
|
91
|
+
err += "to another switch"
|
92
|
+
raise Error, err
|
93
|
+
end
|
94
|
+
end
|
95
|
+
else
|
96
|
+
hash[first] = true # Boolean switch
|
97
|
+
if rest.empty?
|
98
|
+
ARGV.shift
|
99
|
+
else
|
100
|
+
ARGV[0] = "-#{rest}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
hash
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/test/test_getopt_long.rb
CHANGED
data/test/test_getopt_std.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: getopt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-05 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -33,13 +33,17 @@ extra_rdoc_files:
|
|
33
33
|
- CHANGES
|
34
34
|
- MANIFEST
|
35
35
|
files:
|
36
|
+
- CHANGES
|
36
37
|
- examples/example_long.rb
|
37
38
|
- examples/example_std.rb
|
39
|
+
- getopt.gemspec
|
40
|
+
- lib/getopt/long.rb
|
41
|
+
- lib/getopt/std.rb
|
42
|
+
- MANIFEST
|
43
|
+
- Rakefile
|
44
|
+
- README
|
38
45
|
- test/test_getopt_long.rb
|
39
46
|
- test/test_getopt_std.rb
|
40
|
-
- README
|
41
|
-
- CHANGES
|
42
|
-
- MANIFEST
|
43
47
|
has_rdoc: true
|
44
48
|
homepage: http://www.rubyforge.org/projects/shards
|
45
49
|
licenses:
|