I’ve been wanting an easy way to output usage info for my programs that use
GetoptLong, without having to duplicate all the option information; once
for the creation of the GetoptLong object, and again in a help message.
I’ve taken a crack at altering GetoptLong to support a “usage” method that
essentially does what I want.
Basically what it does is have you include a fourth parameter for each
option: the description. This is used internally, then removed from each
array, the collection is then passed to the original initialize method for
regular processing. Calling the usage method of your GetoptLong object will
print out a user-defined message (or a default) and then iterates over the
options, printing both long and short versions, and the description. I’ve
included the code below in a test program. I’m not finished with it, but I
wanted to share it. I want to make the output a little prettier and maybe
make it more flexible. I don’t know yet. I welcome any suggestions or
comments.
···
require ‘getoptlong’
class GetoptLong
alias old_init initialize
def initialize(*options)
@descriptions = Hash.new
options.each do |arg|
key = arg[0..1]
desc = arg[3]
@descriptions[key] = desc
arg.pop
end
old_init(*options)
end
def usage(message="Usage:")
puts "#{message}"
@descriptions.sort.each do |k, v|
printf "%15s => %-40s\n", k.join(", "), v
end
end
end
opts = GetoptLong.new(["–date", “-d”, GetoptLong::REQUIRED_ARGUMENT,
“specify a date”],
["–quiet", “-q”, GetoptLong::NO_ARGUMENT, “be verry
quiet”],
["–help", “-h”, GetoptLong::NO_ARGUMENT, “Print this
help page”])
opts.each do |opt, arg|
case opt
when "–date"
puts "Date passed"
when "–help"
opts.usage(“Usage: goltest [options]\n\n”)
# opts.usage
exit
end
end
–
Dean saor, dean saor an spiorad. Is seinn d’orain beo.
That’s a nice coincidence - or a proof for the theory of morphogenetic
fields: I was just today wanting to have the same functionality and
equally thought how nice it would be to simply have an additional string
parameter containing the usage.
Hmmm, let’s see… I’d override set_options instead of initialize because
that is the method douing the work. Try this:
class GetoptLong
alias old_set_options set_options
def set_options(*options)
@descriptions = []
@opt_help = "Options:\n"
options.each do |arg|
if hasDescription? arg
@opt_help << sprintf("%-20s: %s\n", arg[0..-3].join( ',
’ ), arg.pop )
else @opt_help << arg[0…-2].join( ', ’ ) << "\n"
end
end
@opt_help << "\n"
old_set_options(*options)
end
def usage(message="Usage:")
puts message
puts @opt_help
end
private
def hasDescription?(optarray)
case optarray[-1]
when GetoptLong::REQUIRED_ARGUMENT,
GetoptLong::NO_ARGUMENT,
GetoptLong::OPTIONAL_ARGUMENT
false
else
true
end
end
ARGV.options do |options|
options.on(‘-d’, ‘–date=DATE’, String, ‘specify a date’){|v| puts “Date
#{v} passed”}
options.on(‘-q’, ‘–quiet’, ‘be verry quiet’){puts “OK, I’m being very,
very, very quiet… can’t you tell?”}
options.on_tail(‘-h’, ‘–help’, ‘Print this help information’){puts
options; exit}
options.parse!
end
I believe that’s approximately equal to what you posted. I’ve only just
begun using optparse, but it seems quite powerful and easy to use.
I’ve been wanting an easy way to output usage info for my
programs that use GetoptLong, without having to duplicate all
the option information; once for the creation of the
GetoptLong object, and again in a help message. I’ve taken a
crack at altering GetoptLong to support a “usage” method that
essentially does what I want.
Basically what it does is have you include a fourth parameter for each
option: the description. This is used internally, then
removed from each array, the collection is then passed to the
original initialize method for regular processing. Calling
the usage method of your GetoptLong object will print out a
user-defined message (or a default) and then iterates over
the options, printing both long and short versions, and the
description. I’ve included the code below in a test program.
I’m not finished with it, but I wanted to share it. I want to
make the output a little prettier and maybe make it more
flexible. I don’t know yet. I welcome any suggestions or comments.
Why not just key off of the length of the array? If you get a three element
array then you don’t have a description; four elements means description. I
don’t like keying off those constants because more could be added, and
since they are just numbers anyway, you might get a false
positive/negative based on the description. Probably not, I guess… Ah
well. TMTOWTDI, I suppose.
You could rewrite it thusly
def has_description?(optarray)
optarray.length == 3
end
Can we get one or the other of these approaches added to the code base to
make this a standard part of GetoptLong? Matz, what do you think?
def hasDescription?(optarray)
case optarray[-1]
when GetoptLong::REQUIRED_ARGUMENT,
GetoptLong::NO_ARGUMENT,
GetoptLong::OPTIONAL_ARGUMENT
Why not just key off of the length of the array? If you get a three
element
array then you don’t have a description; four elements means
description.
That does not work since the array length is not fixed: There can be
arbitrary many option strings before the argument setting. One could of
course simplify the test to test the last element’s type (String means
description, Fixnum means argument setting):
def has_description?(optarray)
String === optarray[-1]
end
don’t like keying off those constants because more could be added,
Yes, that’s a disadvantage.
and
since they are just numbers anyway, you might get a false
positive/negative based on the description. Probably not, I guess… Ah
well. TMTOWTDI, I suppose.
Err, what?
Can we get one or the other of these approaches added to the code base
to
make this a standard part of GetoptLong? Matz, what do you think?