opt-simple 0.7.1
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/GPLv2-LICENSE +18 -0
- data/README +160 -0
- data/extensions/test_unit_extensions.rb +21 -0
- data/lib/opt_simple.rb +369 -0
- data/lib/test_unit_extensions.rb +21 -0
- data/test/test_arglist.rb +38 -0
- data/test/test_help.rb +45 -0
- data/test/test_usage.rb +28 -0
- metadata +62 -0
data/GPLv2-LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
OptSimple is a utility for parsing command line arguments.
|
2
|
+
Copyright (C) 2011 Ethan Stryker
|
3
|
+
|
4
|
+
This program is free software; you can redistribute it and/or
|
5
|
+
modify it under the terms of the GNU General Public License
|
6
|
+
as published by the Free Software Foundation; either version 2
|
7
|
+
of the License, or (at your option) any later version.
|
8
|
+
|
9
|
+
This program is distributed in the hope that it will be useful,
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
GNU General Public License for more details.
|
13
|
+
|
14
|
+
You should have received a copy of the GNU General Public License
|
15
|
+
along with this program; if not, write to the Free Software
|
16
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
|
18
|
+
Questions/Comments on OptSimple can be mailed to Ethan Stryker, e.stryker@gmail.com
|
data/README
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
= OptSimple provides a very simple interface to command line parsing.
|
2
|
+
|
3
|
+
== Description
|
4
|
+
Parameter specification, validity checking and argument transformations
|
5
|
+
can be put in one place, default parameters are easily set, and an automatic
|
6
|
+
usage statement is constructed.
|
7
|
+
|
8
|
+
There are three methods to define command line parameters:
|
9
|
+
|
10
|
+
flag - a command line switch with no arguments following (although you can still use flag
|
11
|
+
as a synonym for option. But default behavior is to expect no args.)
|
12
|
+
|
13
|
+
option - an optional command line parameter with one or more arguments
|
14
|
+
|
15
|
+
argument - a mandatory command line parameter with one or more arguments
|
16
|
+
|
17
|
+
Inside the blocks in flag, option, and argument a shortcut function called 'set_opt'
|
18
|
+
can be used to set an option that will be returned in the options hash.
|
19
|
+
|
20
|
+
The number of arguments are determined by the 'arity' of the block.
|
21
|
+
|
22
|
+
The order in which the parameters are defined dictate their order on the command line.
|
23
|
+
|
24
|
+
User defined help banners, summaries or the whole usage statement can be defined.
|
25
|
+
|
26
|
+
== Documentation
|
27
|
+
|
28
|
+
See OptSimple for the API specification
|
29
|
+
|
30
|
+
== Installation
|
31
|
+
|
32
|
+
It is recommended to install OptSimple using RubyGems:
|
33
|
+
|
34
|
+
$ sudo gem install opt-simple
|
35
|
+
|
36
|
+
== Examples
|
37
|
+
|
38
|
+
=== A very simple example with no error checking. Use at your own risk!
|
39
|
+
|
40
|
+
require 'opt_simple'
|
41
|
+
|
42
|
+
defaults = {
|
43
|
+
'max' => 40
|
44
|
+
}
|
45
|
+
|
46
|
+
options,arguments = OptSimple.new(defaults).parse_opts!
|
47
|
+
|
48
|
+
puts "Options"
|
49
|
+
puts options.inspect
|
50
|
+
|
51
|
+
puts "Arguments"
|
52
|
+
puts arguments.inspect
|
53
|
+
|
54
|
+
puts "ARGV"
|
55
|
+
puts ARGV
|
56
|
+
|
57
|
+
|
58
|
+
=== An example that provides error checking on ARGV, using all default behavior
|
59
|
+
|
60
|
+
require 'opt_simple'
|
61
|
+
|
62
|
+
options,arguments = OptSimple.new.parse_opts! do
|
63
|
+
argument "-i","inFile"
|
64
|
+
option %w[-p --pattern --glob-pattern], "glob pattern"
|
65
|
+
flag "-v","Verbose"
|
66
|
+
flag "-whatever"
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "Options"
|
70
|
+
puts options.inspect
|
71
|
+
|
72
|
+
puts "Arguments"
|
73
|
+
puts arguments.inspect
|
74
|
+
|
75
|
+
puts "ARGV"
|
76
|
+
puts ARGV
|
77
|
+
|
78
|
+
|
79
|
+
=== An example that shows how to use 'set_opt', set the banner string, and add a summary.
|
80
|
+
|
81
|
+
require 'opt_simple'
|
82
|
+
|
83
|
+
defaults = {
|
84
|
+
"max" => 10
|
85
|
+
}
|
86
|
+
|
87
|
+
options,arguments = OptSimple.new(defaults).parse_opts! do
|
88
|
+
banner "USAGE: #{$0}"
|
89
|
+
summary "Show how to set a banner and summary."
|
90
|
+
|
91
|
+
argument "-i","inFile"
|
92
|
+
option %w[-m -max --maximum-value],"Maximum val" do |arg|
|
93
|
+
set_opt arg.to_i
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
puts "Options"
|
98
|
+
puts options.inspect
|
99
|
+
|
100
|
+
puts "Arguments"
|
101
|
+
puts arguments.inspect
|
102
|
+
|
103
|
+
puts "ARGV"
|
104
|
+
puts ARGV
|
105
|
+
|
106
|
+
=== An example that shows that you can easily set your defaults in normal Ruby variables and provide your own help.
|
107
|
+
|
108
|
+
require 'opt_simple'
|
109
|
+
|
110
|
+
in_file = nil
|
111
|
+
min = 0
|
112
|
+
max = 10
|
113
|
+
pattern = "*"
|
114
|
+
|
115
|
+
usage_string = <<-UL
|
116
|
+
Usage: $0 [options]
|
117
|
+
|
118
|
+
-i, --infile FILE
|
119
|
+
[--range (min - default #{min}, max - default #{max})]
|
120
|
+
[-p, --pattern, --glob-pattern (default #{pattern})]
|
121
|
+
[-v (verbose)]
|
122
|
+
[-h, --help (help)]
|
123
|
+
|
124
|
+
UL
|
125
|
+
|
126
|
+
OptSimple.new.parse_opts! do
|
127
|
+
help usage_string
|
128
|
+
|
129
|
+
argument %w[-i --infile],"inFile" do |arg|
|
130
|
+
in_file = arg
|
131
|
+
error "inFile must exist and be readable" unless(File.readable?(in_file))
|
132
|
+
end
|
133
|
+
|
134
|
+
option ["--range"], "range: min,max (both >0) default is #{min},#{max}" do | arg1,arg2 |
|
135
|
+
min = arg1.to_i
|
136
|
+
max = arg2.to_i
|
137
|
+
|
138
|
+
error "max must be greater than min" unless max > min
|
139
|
+
error "both must be >=0" if min < 0
|
140
|
+
end
|
141
|
+
|
142
|
+
option %w[-p --pattern --glob-pattern], "glob pattern, default is #{pattern}" do |arg|
|
143
|
+
pattern = arg
|
144
|
+
end
|
145
|
+
|
146
|
+
flag "-v","Verbose"
|
147
|
+
end
|
148
|
+
|
149
|
+
puts "in_file #{in_file}"
|
150
|
+
puts "min #{min}"
|
151
|
+
puts "max #{max}"
|
152
|
+
puts "pattern #{pattern}"
|
153
|
+
|
154
|
+
puts "ARGV"
|
155
|
+
puts ARGV
|
156
|
+
|
157
|
+
== Questions and/or Comments
|
158
|
+
|
159
|
+
email {Ethan Stryker}[mailto:e.stryker@gmail.com]
|
160
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Test::Unit
|
2
|
+
# Used to fix a minor minitest/unit incompatibility in flexmock
|
3
|
+
AssertionFailedError = Class.new(StandardError)
|
4
|
+
|
5
|
+
class TestCase
|
6
|
+
|
7
|
+
def self.must(name, &block)
|
8
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
9
|
+
defined = instance_method(test_name) rescue false
|
10
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
11
|
+
if block_given?
|
12
|
+
define_method(test_name, &block)
|
13
|
+
else
|
14
|
+
define_method(test_name) do
|
15
|
+
flunk "No implementation provided for #{name}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/opt_simple.rb
ADDED
@@ -0,0 +1,369 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
= OptSimple provides a very simple interface to command line parsing.
|
4
|
+
|
5
|
+
There are three methods to define command line parameters:
|
6
|
+
|
7
|
+
flag - a command line switch with no arguments following (although you can still use flag
|
8
|
+
as a synonym for option. But default behavior is to expect no args.)
|
9
|
+
|
10
|
+
option - an optional command line parameter with one or more arguments
|
11
|
+
|
12
|
+
argument - a mandatory command line parameter with one or more arguments
|
13
|
+
|
14
|
+
Inside the blocks in flag, option, and argument a shortcut function called 'set_opt'
|
15
|
+
can be used to set an option that will be returned in the options hash.
|
16
|
+
|
17
|
+
The number of arguments are determined by the 'arity' of the block.
|
18
|
+
|
19
|
+
The order in which the parameters are defined dictate their order on the command line.
|
20
|
+
|
21
|
+
User defined help banners, summaries or the whole usage statement can be defined.
|
22
|
+
=end
|
23
|
+
class OptSimple
|
24
|
+
attr_accessor :args
|
25
|
+
attr_reader :mandatory_opts, :optional_opts
|
26
|
+
|
27
|
+
# default keys should should be strings,
|
28
|
+
# args can be any list of strings, but defaults to ARGV
|
29
|
+
def initialize(defaults = {},args = ARGV)
|
30
|
+
@mandatory_opts = []
|
31
|
+
@optional_opts = []
|
32
|
+
@parameters = []
|
33
|
+
@param_names = {}
|
34
|
+
@longest_switch_len = 0
|
35
|
+
@options = defaults.dup # not sure if I have to dup this
|
36
|
+
@positional_arguments = []
|
37
|
+
@args = args
|
38
|
+
@banner = "Usage: #{File.basename($0)} [options]"
|
39
|
+
@summary = ""
|
40
|
+
@help = ""
|
41
|
+
end
|
42
|
+
|
43
|
+
# set the Summary string at the end of the usage statement
|
44
|
+
def summary(str)
|
45
|
+
@summary = str
|
46
|
+
end
|
47
|
+
|
48
|
+
# provide a user defined help string, and override the auto-generated one
|
49
|
+
def help(str)
|
50
|
+
@help = str
|
51
|
+
end
|
52
|
+
|
53
|
+
# set the banner to str, overriding the default: "Usage: #{File.basename($0)} [options]"
|
54
|
+
def banner(str)
|
55
|
+
@banner = str
|
56
|
+
end
|
57
|
+
|
58
|
+
# Parse the options, destructively pulling them out of the args array as it goes.
|
59
|
+
# If no block is given, then a default parser with no error checking will be run.
|
60
|
+
def parse_opts!(&block)
|
61
|
+
|
62
|
+
if block_given?
|
63
|
+
# call the block to register all the parameters and
|
64
|
+
# their corresponding code blocks
|
65
|
+
# We use instance_exec so that the API is cleaner.
|
66
|
+
begin
|
67
|
+
instance_exec(@options,@positional_arguments,&block)
|
68
|
+
ensure
|
69
|
+
# we are ensuring that the options that occur before any break statement
|
70
|
+
# actually get parsed.
|
71
|
+
|
72
|
+
# add the help option at the end
|
73
|
+
option %w[-h --help] ,"(for this help message)"
|
74
|
+
|
75
|
+
# first look for a call for help
|
76
|
+
unless (%w[-h --help] & @args).empty?
|
77
|
+
$stdout.puts self.to_s
|
78
|
+
exit(0)
|
79
|
+
end
|
80
|
+
|
81
|
+
mandatory_check = mandatory_opts.map {|m| m.switches}
|
82
|
+
|
83
|
+
if(loc = @args.index('--'))
|
84
|
+
#remove the '--', but don't include it w/ positional arguments
|
85
|
+
@positional_arguments += @args.slice!(loc..-1)[1..-1]
|
86
|
+
end
|
87
|
+
|
88
|
+
# now actually parse the args, and call all the stored up blocks from the options
|
89
|
+
@parameters.each do | parm |
|
90
|
+
intersection = @args & parm.switches
|
91
|
+
unless intersection.empty?
|
92
|
+
loc = @args.index(intersection.first)
|
93
|
+
|
94
|
+
# remove the flag, but skip it to put it into pieces
|
95
|
+
pieces = @args.slice!(loc .. loc + parm.block.arity)[1..-1]
|
96
|
+
if pieces.length < parm.block.arity or
|
97
|
+
pieces.any? {|p| p.start_with?('-')}
|
98
|
+
raise OptSimple::MissingArgument.new "Not enough args following #{intersection.first}",self
|
99
|
+
end
|
100
|
+
|
101
|
+
mandatory_check.delete(parm.switches)
|
102
|
+
|
103
|
+
begin
|
104
|
+
parm.instance_exec(*pieces,&parm.block)
|
105
|
+
rescue OptSimple::Error => e
|
106
|
+
raise OptSimple::Error.new e.message,self
|
107
|
+
end
|
108
|
+
|
109
|
+
@options.merge!(parm.param_options)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
unless mandatory_check.empty?
|
114
|
+
raise MissingArgument.new "Must set the following parameters: #{mandatory_check.map {|a| a.join(' OR ')}.join(', ')}",self
|
115
|
+
end
|
116
|
+
|
117
|
+
extra_switches = @args.find_all {|a| a.start_with?('-') }
|
118
|
+
raise OptSimple::InvalidOption.new "Unknown options: #{extra_switches.join(' ')}",self unless extra_switches.empty?
|
119
|
+
|
120
|
+
@positional_arguments += @args.slice!(0..-1)
|
121
|
+
end
|
122
|
+
else
|
123
|
+
#parse the @args array by looking for switches/args by regex
|
124
|
+
default_arg_parser
|
125
|
+
end
|
126
|
+
return [@options,@positional_arguments]
|
127
|
+
end
|
128
|
+
|
129
|
+
# Parse the options in a non-destructive way to the args array passed in.
|
130
|
+
# If no block is given, then a default parser with no error checking will be run.
|
131
|
+
def parse_opts(&block)
|
132
|
+
@original_args = @args # do I really need these around?
|
133
|
+
@args = @args.dup
|
134
|
+
parse_opts! &block
|
135
|
+
end
|
136
|
+
|
137
|
+
# You do not want to call this function.
|
138
|
+
# This provides a default behavior for all switches on the command line if no
|
139
|
+
# block is given to parse_opts
|
140
|
+
def default_arg_parser
|
141
|
+
flag = nil
|
142
|
+
@args.each_with_index do |arg,loc|
|
143
|
+
if arg == '--'
|
144
|
+
# end of flag marker
|
145
|
+
@positional_args += @args[i+1 .. -1]
|
146
|
+
break
|
147
|
+
elsif arg =~ /^-+(.*)/
|
148
|
+
# assume flags are boolean
|
149
|
+
@options[$1] = true
|
150
|
+
flag = $1
|
151
|
+
elsif flag
|
152
|
+
# unless followed by an arg
|
153
|
+
@options[flag] = arg
|
154
|
+
flag = nil
|
155
|
+
else
|
156
|
+
@positional_args << arg
|
157
|
+
end
|
158
|
+
end
|
159
|
+
@args.slice!(0..-1)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Registers an optional parameter, usually with nothing following it.
|
163
|
+
# although if the block has arity > 0, we'll be happy to handle
|
164
|
+
# it as such.
|
165
|
+
# 'switches' can be a String or an Array of Strings, and specifies the switches expected on the CL.
|
166
|
+
# 'help' provides a description of the parameter
|
167
|
+
# and an optional block can do parameter validation/transformation.
|
168
|
+
# If no block is given, then the strings specified (after the
|
169
|
+
# leading '-'s removed) will be used as keys in the options hash
|
170
|
+
# and the values set to true when seen in the args array
|
171
|
+
def flag(switches,help="",&block)
|
172
|
+
add_parameter(Flag.new(switches,help,&block))
|
173
|
+
end
|
174
|
+
|
175
|
+
# Registers an optional parameter, with one or more argument following it.
|
176
|
+
# 'switches' can be a String or an Array of Strings, and specifies the switches expected on the CL.
|
177
|
+
# 'help' provides a description of the parameter
|
178
|
+
# and an optional block can do parameter validation/transformation.
|
179
|
+
# If no block is given, then the strings specified (after the
|
180
|
+
# leading '-'s removed) will be used as keys in the options hash
|
181
|
+
# and the values set to the arg following the switch in the args array.
|
182
|
+
def option(switches,help="",&block)
|
183
|
+
add_parameter(Option.new(switches,help,&block))
|
184
|
+
end
|
185
|
+
|
186
|
+
# Registers a mandatory parameter, with one or more argument following it.
|
187
|
+
# 'switches' can be a String or an Array of Strings, and specifies the switches expected on the CL.
|
188
|
+
# 'help' provides a description of the parameter
|
189
|
+
# and an optional block can do parameter validation/transformation.
|
190
|
+
# If no block is given, then the strings specified (after the
|
191
|
+
# leading '-'s removed) will be used as keys in the options hash
|
192
|
+
# and the values set to the arg following the switch the args array.
|
193
|
+
def argument(switches,help="",&block)
|
194
|
+
add_parameter(Argument.new(switches,help,&block))
|
195
|
+
end
|
196
|
+
|
197
|
+
# A shortcut for raising an OptSimple::Error exception
|
198
|
+
def error(string=nil)
|
199
|
+
raise OptSimple::Error.new string
|
200
|
+
end
|
201
|
+
|
202
|
+
# returns the automatic usage statement
|
203
|
+
def to_s
|
204
|
+
if @help.empty?
|
205
|
+
help_str = ""
|
206
|
+
|
207
|
+
help_str << " MANDATORY ARGS:\n" unless mandatory_opts.empty?
|
208
|
+
mandatory_opts.each do | parm |
|
209
|
+
help_str << parm.help_str(@longest_switch_len) << "\n"
|
210
|
+
end
|
211
|
+
help_str << "\n" unless mandatory_opts.empty?
|
212
|
+
|
213
|
+
help_str << " OPTIONS:\n" unless optional_opts.empty?
|
214
|
+
optional_opts.each do | parm |
|
215
|
+
help_str << parm.help_str(@longest_switch_len)
|
216
|
+
|
217
|
+
# check to see if we have any defaults set to help in the help doc
|
218
|
+
intersection = @options.keys & parm.names
|
219
|
+
if intersection.empty?
|
220
|
+
help_str << "\n\n"
|
221
|
+
else
|
222
|
+
help_str << " (default is #{@options[intersection.first]})\n\n"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
help_str << " SUMMARY:\n\n #{@summary}\n\n" unless @summary.empty?
|
226
|
+
|
227
|
+
@help = @banner + "\n\n" + help_str
|
228
|
+
end
|
229
|
+
@help
|
230
|
+
end
|
231
|
+
|
232
|
+
# You probably don't want to call this method.
|
233
|
+
# A lower level function that adds a Flag, Option, or Argument,
|
234
|
+
def add_parameter(parm)
|
235
|
+
total_switch_len = parm.switches.join(', ').length
|
236
|
+
@longest_switch_len = total_switch_len if total_switch_len > @longest_switch_len
|
237
|
+
|
238
|
+
parm.names.each do | n |
|
239
|
+
if @param_names.has_key?(n)
|
240
|
+
raise OptSimple::Error.new "Command line switch already in use!"
|
241
|
+
else
|
242
|
+
@param_names[n] = true
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
@parameters << parm
|
247
|
+
@mandatory_opts << parm if parm.mandatory?
|
248
|
+
@optional_opts << parm if not parm.mandatory?
|
249
|
+
end
|
250
|
+
|
251
|
+
# The base class for command line parameter objects from which Flag,
|
252
|
+
# Option and Argument are derived. Provides documentation methods,
|
253
|
+
# an 'error method', and the 'set_opt' utility funciton.
|
254
|
+
class Parameter
|
255
|
+
attr_reader :switches,:param_options,:block
|
256
|
+
|
257
|
+
# 'switches' can be a String or an Array of Strings, and specifies the switches expected on the CL.
|
258
|
+
# 'help' provides a description of the parameter
|
259
|
+
# and an optional block can do parameter validation/transformation.
|
260
|
+
def initialize(switches,help="",&block)
|
261
|
+
self.switches = switches
|
262
|
+
@help = help
|
263
|
+
@block = block
|
264
|
+
@param_options = {}
|
265
|
+
@names = nil
|
266
|
+
end
|
267
|
+
|
268
|
+
# ensures that the switches is an array. Should be an array of Strings
|
269
|
+
def switches=(switches)
|
270
|
+
@switches = [switches].flatten
|
271
|
+
end
|
272
|
+
|
273
|
+
# returns a list of the switches without the leading '-'s
|
274
|
+
def names
|
275
|
+
@names ||= switches.map {|s| s.sub(/^-+/,'')}
|
276
|
+
end
|
277
|
+
|
278
|
+
# a single line that will be put in the overall usage string
|
279
|
+
def help_str(switch_len)
|
280
|
+
short_parms = @switches.find_all {|st| st.start_with?('-') and st.length == 2 and st[1] != '-'}
|
281
|
+
long_parms = @switches.find_all {|st| st.start_with?('--') or (st.start_with?('-') and st.length > 2)}
|
282
|
+
other_parms = @switches.find_all {|st| not st.start_with?('-')}
|
283
|
+
|
284
|
+
sh_str = short_parms.empty? ? " " * 4 : short_parms.first
|
285
|
+
long_str = long_parms.join(', ') + other_parms.join(', ')
|
286
|
+
sh_str << ', ' unless sh_str =~/^\s+$/ or long_str.empty?
|
287
|
+
|
288
|
+
" %-#{switch_len}s" % (sh_str + long_str) + " \t#{@help}"
|
289
|
+
end
|
290
|
+
|
291
|
+
# A shortcut for raising an OptSimple::Error exception
|
292
|
+
def error(string)
|
293
|
+
raise OptSimple::Error.new string
|
294
|
+
end
|
295
|
+
|
296
|
+
# A utility function that sets all the names to the specified value
|
297
|
+
# in the param_options hash.
|
298
|
+
def set_opt val
|
299
|
+
names.each {|n| @param_options[n] = val}
|
300
|
+
end
|
301
|
+
|
302
|
+
# is it mandatory to see this parameter on the command line?
|
303
|
+
def mandatory?; false; end
|
304
|
+
|
305
|
+
end
|
306
|
+
|
307
|
+
# An optional parameter, usually with nothing following it.
|
308
|
+
# although if the block has arity > 0, we'll be happy to handle
|
309
|
+
# it as such.
|
310
|
+
# 'switches' can be a String or an Array of Strings, and specifies the switches expected on the CL.
|
311
|
+
# 'help' provides a description of the parameter
|
312
|
+
# and an optional block can do parameter validation/transformation.
|
313
|
+
# If no block is given, then the strings specified (after the
|
314
|
+
# leading '-'s removed) will be used as keys in the options hash
|
315
|
+
# and the values set to true when seen in the args array
|
316
|
+
class Flag < Parameter
|
317
|
+
def initialize(switches,help="",&block)
|
318
|
+
super(switches,help,&block)
|
319
|
+
unless block_given?
|
320
|
+
@block = Proc.new { names.each {|n| @param_options[n] = true}}
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# An optional parameter, with one or more argument following it.
|
326
|
+
# 'switches' can be a String or an Array of Strings, and specifies the switches expected on the CL.
|
327
|
+
# 'help' provides a description of the parameter
|
328
|
+
# and an optional block can do parameter validation/transformation.
|
329
|
+
# If no block is given, then the strings specified (after the
|
330
|
+
# leading '-'s removed) will be used as keys in the options hash
|
331
|
+
# and the values set to the arg following the switch in the args array.
|
332
|
+
class Option < Parameter
|
333
|
+
def initialize(switches,help="",&block)
|
334
|
+
super(switches,help,&block)
|
335
|
+
unless block_given?
|
336
|
+
@block = Proc.new {|arg| names.each {|n| @param_options[n] = arg}}
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# A mandatory parameter, with one or more argument following it.
|
342
|
+
# 'switches' can be a String or an Array of Strings, and specifies the switches expected on the CL.
|
343
|
+
# 'help' provides a description of the parameter
|
344
|
+
# and an optional block can do parameter validation/transformation.
|
345
|
+
# If no block is given, then the strings specified (after the
|
346
|
+
# leading '-'s removed) will be used as keys in the options hash
|
347
|
+
# and the values set to the arg following the switch the args array.
|
348
|
+
class Argument < Option
|
349
|
+
def mandatory?; true; end
|
350
|
+
end
|
351
|
+
|
352
|
+
# A general error in the options
|
353
|
+
class Error < Exception
|
354
|
+
def initialize(string,option_obj=nil)
|
355
|
+
super("#{string}\n#{option_obj.to_s}")
|
356
|
+
set_backtrace []
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
# An exception that is thrown if an unspecified parameter
|
361
|
+
# is used on the command line
|
362
|
+
class InvalidOption < Error;end
|
363
|
+
|
364
|
+
# An exception thrown if a mandatory parameter is not
|
365
|
+
# used on the command line
|
366
|
+
class MissingArgument < Error;end
|
367
|
+
|
368
|
+
end
|
369
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Test::Unit
|
2
|
+
# Used to fix a minor minitest/unit incompatibility in flexmock
|
3
|
+
AssertionFailedError = Class.new(StandardError)
|
4
|
+
|
5
|
+
class TestCase
|
6
|
+
|
7
|
+
def self.must(name, &block)
|
8
|
+
test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
9
|
+
defined = instance_method(test_name) rescue false
|
10
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
11
|
+
if block_given?
|
12
|
+
define_method(test_name, &block)
|
13
|
+
else
|
14
|
+
define_method(test_name) do
|
15
|
+
flunk "No implementation provided for #{name}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'opt_simple'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'test_unit_extensions'
|
4
|
+
|
5
|
+
class ArglistTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@args = %w[infile1 -v infile2 -o out.txt infile3 -- -infile4 infile5]
|
8
|
+
@os = OptSimple.new({},@args)
|
9
|
+
@block = Proc.new {
|
10
|
+
flag '-v'
|
11
|
+
argument '-o'
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
must "put all args after the dash dash in the pos argument list" do
|
16
|
+
options,arguments = @os.parse_opts &@block
|
17
|
+
assert arguments.include? '-infile4' and arguments.include? 'infile5'
|
18
|
+
end
|
19
|
+
|
20
|
+
must "return all positional args in the arguments list" do
|
21
|
+
options,arguments = @os.parse_opts &@block
|
22
|
+
assert_equal arguments.sort,%w[infile1 infile2 infile3 -infile4 infile5].sort
|
23
|
+
end
|
24
|
+
|
25
|
+
must "empty out ARGV when using parse_opts!" do
|
26
|
+
arg_copy = @args.dup
|
27
|
+
@os.parse_opts! &@block
|
28
|
+
assert @args.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
must "preserve ARGV when using parse_opts" do
|
32
|
+
arg_copy = @args.dup
|
33
|
+
@os.parse_opts &@block
|
34
|
+
|
35
|
+
assert_equal @args.sort,arg_copy.sort
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/test/test_help.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'opt_simple'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'test_unit_extensions'
|
4
|
+
|
5
|
+
class TestHelpStatement < Test::Unit::TestCase
|
6
|
+
|
7
|
+
must "add default info to help string" do
|
8
|
+
defaults = {
|
9
|
+
'a' => 1000
|
10
|
+
}
|
11
|
+
os = OptSimple.new(defaults)
|
12
|
+
os.add_parameter(OptSimple::Option.new '-a' )
|
13
|
+
|
14
|
+
assert os.to_s =~/default.*#{defaults['a']}/
|
15
|
+
end
|
16
|
+
|
17
|
+
must "order help according to specification order" do
|
18
|
+
os = OptSimple.new({},['-h'])
|
19
|
+
os.add_parameter(OptSimple::Option.new '-a')
|
20
|
+
os.add_parameter(OptSimple::Flag.new '-b')
|
21
|
+
os.add_parameter(OptSimple::Option.new '-c')
|
22
|
+
os.add_parameter(OptSimple::Argument.new '-x')
|
23
|
+
os.add_parameter(OptSimple::Argument.new '-y')
|
24
|
+
os.add_parameter(OptSimple::Argument.new '-z')
|
25
|
+
|
26
|
+
assert os.to_s.match(Regexp.new("\-x.*\-y.*\-z.*\-a.*\-b.*\-c.*",Regexp::MULTILINE))
|
27
|
+
end
|
28
|
+
|
29
|
+
must "allow user defined help statements" do
|
30
|
+
my_help = "Totally irrelevant"
|
31
|
+
os = OptSimple.new({},['-h'])
|
32
|
+
os.add_parameter(OptSimple::Option.new '-a')
|
33
|
+
os.add_parameter(OptSimple::Flag.new '-b')
|
34
|
+
os.help my_help
|
35
|
+
|
36
|
+
assert os.to_s == my_help
|
37
|
+
end
|
38
|
+
|
39
|
+
must "provide user specified summary statement in help" do
|
40
|
+
os = OptSimple.new({},['-h'])
|
41
|
+
os.add_parameter(OptSimple::Option.new '-a')
|
42
|
+
os.summary "My summary"
|
43
|
+
assert os.to_s.match(Regexp.new("My summary",Regexp::MULTILINE))
|
44
|
+
end
|
45
|
+
end
|
data/test/test_usage.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'opt_simple'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'test_unit_extensions'
|
4
|
+
|
5
|
+
class TestHelpStatement < Test::Unit::TestCase
|
6
|
+
|
7
|
+
must "disallow name collisions in argument spec" do
|
8
|
+
assert_raise(OptSimple::Error) { OptSimple.new.parse_opts! {option %w[-a --awesome]; flag '-awesome' } }
|
9
|
+
end
|
10
|
+
|
11
|
+
must "raise error when unknown option is given" do
|
12
|
+
os = OptSimple.new({},['-not-specified'])
|
13
|
+
assert_raise(OptSimple::InvalidOption) { os.parse_opts! { option %w[-a --awesome] } }
|
14
|
+
end
|
15
|
+
|
16
|
+
must "raise error when not enough arguments are given" do
|
17
|
+
os = OptSimple.new({},['-a'])
|
18
|
+
assert_raise(OptSimple::MissingArgument) do
|
19
|
+
os.parse_opts! do
|
20
|
+
option '-a' do |arg|
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opt-simple
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ethan Stryker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2011-03-04 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: " Parameter specification, validity checking and argument transformations \n can be put in one place, default parameters are easily set, and an \n automatic usage statement is constructed.\n"
|
17
|
+
email: e.stryker@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/test_unit_extensions.rb
|
26
|
+
- lib/opt_simple.rb
|
27
|
+
- test/test_help.rb
|
28
|
+
- test/test_usage.rb
|
29
|
+
- test/test_arglist.rb
|
30
|
+
- extensions/test_unit_extensions.rb
|
31
|
+
- README
|
32
|
+
- GPLv2-LICENSE
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://opt-simple.rubyforge.org/
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project: opt-simple
|
57
|
+
rubygems_version: 1.3.5
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: A simple and elegant command line option parser.
|
61
|
+
test_files: []
|
62
|
+
|