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 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
@@ -180,6 +180,4 @@ INCREMENT
180
180
  All Rights Reserved
181
181
 
182
182
  == Author
183
- Daniel J. Berger
184
- djberg96 at nospam at gmail.com
185
- imperator on IRC (freenode)
183
+ Daniel J. Berger
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
@@ -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
@@ -17,7 +17,7 @@ class TC_Getopt_Long < Test::Unit::TestCase
17
17
  end
18
18
 
19
19
  def test_version
20
- assert_equal('1.3.9', Long::VERSION)
20
+ assert_equal('1.4.0', Long::VERSION)
21
21
  end
22
22
 
23
23
  def test_constants
@@ -14,7 +14,7 @@ include Getopt
14
14
  class TC_Getopt_Std < Test::Unit::TestCase
15
15
 
16
16
  def test_version
17
- assert_equal('1.3.9', Std::VERSION)
17
+ assert_equal('1.4.0', Std::VERSION)
18
18
  end
19
19
 
20
20
  def test_getopts_basic
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.3.9
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-07-29 00:00:00 -06:00
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: