Class: ParseOpts

Inherits:
Object
  • Object
show all
Defined in:
lib/parseOpts.rb

Overview

parseOpts parses commandline options and arguments.

For more information, please see the README

Defined Under Namespace

Classes: ArgSpec, BadUsageError, OptSpec

Constant Summary collapse

VERSION =
"0.0.2"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ ParseOpts

Create a new object that parses the command line specified by the given block.

The block is evaluated in the context of the new object instance and should call its summary, opt and arg methods.



108
109
110
111
112
# File 'lib/parseOpts.rb', line 108

def initialize (&block)
	@summary = nil
	@optList, @argList = [], []
	instance_eval(&block)
end

Class Method Details

.run(args = ARGV, &block) ⇒ Object

Convenience method to construct an parser object as specified by a block and call its parse method with the argument array given, or ARGV if it is ommitted.

If parsing fails, the usage message is displayed on stderr and exit is called.



262
263
264
265
266
267
268
269
270
# File 'lib/parseOpts.rb', line 262

def ParseOpts.run (args = ARGV, &block)
	parser = ParseOpts.new(&block)
	begin
 parser.parse(args)
	rescue BadUsageError
 $stderr.puts parser.usage_message
 exit(1)
	end
end

Instance Method Details

#arg(spec, desc, params = {}) ⇒ Object

Add an argument.

spec

The name of the argument, possibly followed by a quantifier. The name itself is used as the hash key to return the argument’s value(s)

desc

Human readable description of the argument.

params

An optional hash of additional parameters.

Possible argument quantifiers are:

?

Indicates that this argument may occur zero or once only

*

Indicates that this argument may occur zero or more times

+

Indicates that this argument may occur one or more times

If no quantifier is given, the argument must occur exactly once. If an argument can occur more than once, the value returned for it will be an array of the values passed.

Allowed keyword arguments are:

:choice

An array contating the allowed values of this argument.

:match

An object constraining the values of this argument. The matching is done with ruby’s === operator, so any object that supports this will work - e.g. a regular expression.

:default

A default value if the argument is not present.

Raises:

  • (ArgumentError)


174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/parseOpts.rb', line 174

def arg(spec, desc, params = {})
	name = spec.sub(/(\?|\*|\+)$/, "")
	quant = $1 || ""
	pred = if params.has_key?(:choice)
	 choices = params.delete(:choice)
	 desc += "\n    One of: " + choices.join(' ')
	 lambda {|x| choices.include?(x) }
   elsif params.has_key?(:match)
	 match = params.delete(:match)
	 lambda {|x| match === x }
   else
	 nil
   end
	default = params.delete(:default)
	raise ArgumentError, "Unknown keyword arguments passed: #{params.keys.join(", ")}" unless
 params.size == 0
	@argList << ArgSpec.new(name, quant, desc, pred, default)
end

#opt(spec, desc, params = {}) ⇒ Object

Add an option.

spec

A string specifying the option name and alternatives, and whether the option can take an argument. Alternatives are specified by listing them separated by a ‘|’ character and an argument is specified by following that with a space and the argument name.

The first word of the specification is the name, and is used as the hash key to return its value.

For example: "-l|--long-name argName" will recognise both -l and --long-name, and will take an argument. The key used for the result hash is “-l”.

desc

Human readable description of the option.

params

An optional hash of additional parameters.

Allowed additonal parameters are:

:multiple

Indicates that this option is allowed to occur more than once. In this case the value returned for this option will be an array.

:default

The default value if this option is not passed. Only allowed when the option takes an argument

Raises:

  • (ArgumentError)


140
141
142
143
144
145
146
147
148
149
150
# File 'lib/parseOpts.rb', line 140

def opt(spec, desc, params = {})
	words = spec.split(/ /)
	raise "Bad format for option spec '#{spec}'" unless words.size <= 2
	arg = words[1]
	matches = words[0].split(/\|/)
	default = params.delete(:default)
	multiple = params.delete(:multiple)
	raise ArgumentError, "Unknown keyword arguments passed: #{params.keys.join(", ")}" unless 
 params.size == 0
	@optList << OptSpec.new(matches, arg, desc, multiple, default)
end

#parse(args) ⇒ Object

Parse the command line arguments given and return a hash where the keys are the names of the options and arguments and the values are those that have been extracted from the command line.

Options are parsed first, and may be present in any order. Option parsing stops when there are no more optons, or if "--" is encountered.

The remaining input is parsed as arguments.

This method raised BadUsageError if the parameters do not conform to the specification given when the object was created.

Raises:



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/parseOpts.rb', line 203

def parse(args)
	allSpecs = @optList + @argList
	allSpecs.each {|spec| spec.init }
	parse_next_opt(args) while args.size > 0 && args[0] =~ /^-/ && args[0] != '--'
	args.shift if args[0] == '--'
	@argPos = 0
	while args.size > 0 && @argPos < @argList.size do
 parse_next_arg(@argList[@argPos], args)
 @argPos += 1
	end
	raise BadUsageError if args.size > 0  || @argList[@argPos..-1].find {|s| !s.optional }
	result = {}
	allSpecs.each {|spec| result[spec.name] = spec.value if spec.value}
	return result
end

#summary(string) ⇒ Object

Set the summary text that is output in the usage message.



115
116
117
# File 'lib/parseOpts.rb', line 115

def summary(string)
	@summary = string
end

#usage_messageObject

Generate a usage message explaining the allowed syntax of the command line.



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/parseOpts.rb', line 220

def usage_message
	name = $0 =~ /[^\/]+$/ ? $& : ''
	usageArgs = @argList.collect{|s| s.name + s.quant }
	usageArgs.unshift('options*') if @optList.size > 0
	usageArgs.unshift(name)

	lines = [ "usage: " + usageArgs.join(' ') ]
	lines += [ "", @summary ] if @summary

	if @optList.size > 0
 lines += [ "", "Options:" ] + @optList.map do |opt|
line = "  " + opt.matches.join(", ")
line += " " + opt.arg if opt.arg
line += ": " + opt.desc
if opt.default
  d = opt.default
  d = d.kind_of?(Array) ? d.join(' ') : d.to_s
  line += "\n    Default: " + d
end
line
 end
	end

	if @argList.size > 0
 lines += [ "", "Arguments:" ] + @argList.map do |arg|
line = "  " + arg.name + ": " + arg.desc
if arg.default
  d = arg.default
  d = d.kind_of?(Array) ? d.join(' ') : d.to_s
  line += "\n    Default: " + d
end
line
 end
	end

	lines.join("\n")
end