I don’t know exactly how useful any of you out there will find the
following, but I thought it was interesting enough to share. The main
modification is to allow the ‘get’ and ‘each’ methods to take an
argument – an array of strings akin to ARGV. If this argument is
present, it is processed by the Getoptlong object instead of ARGV. If
the argument is not present, ARGV is processed as in the original
version. I overrode the existing get method, copying it almost verbatim
except for basically substituting the passed-in argument for ARGV
everywhere. The following code can be put in your code to gain the
enhancement in behavior.
Why did I do this? I had an existing program whose code was not
encapsulated in a class, and I needed to do so in order to enable
someone else to use this code. I didn’t want to lose the ability to
flexibly process arbitrary arguments, so I decided to see how hard it
would be to modify Getoptlong. As it turns out, it was pretty easy.
Within 90 minutes I had worked out all the little kinks (e.g., is it
*args or args in my method definition?), resulting in a new version
which was 100% compatible with existing clients’ uses of the code and
also cleanly usable as an object by new clients.
Al
class GetoptLong
Give ourselves read access to some of GetoptLong’s internal data
structures
(makes printing the usage information for programs easier).
attr_reader :canonical_names, :argument_flags
alias :original_get :get
Changed so that we can specify an array of arguments to process,
which defaults to ARGV for backward compatibility.
def get( arguments )
if arguments.empty? then
arguments = ARGV
end
option_name, option_argument = nil, ''
# Check status.
return nil if @error != nil
case @status
when STATUS_YET
@status = STATUS_STARTED
when STATUS_TERMINATED
return nil
end
···
# Get next option argument.
#
if 0 < @rest_singles.length
argument = '-' + @rest_singles
elsif (arguments.length == 0)
terminate
return nil
elsif @ordering == PERMUTE
while 0 < arguments.length && arguments[0] !~ /^-./
@non_option_arguments.push(arguments.shift)
end
if arguments.length == 0
terminate
return nil
end
argument = arguments.shift
elsif @ordering == REQUIRE_ORDER
if (arguments[0] !~ /^-./)
terminate
return nil
end
argument = arguments.shift
else
argument = arguments.shift
end
#
# Check the special argument `--'.
# `--' indicates the end of the option list.
#
if argument == '--' && @rest_singles.length == 0
terminate
return nil
end
#
# Check for long and short options.
#
if argument =~ /^(--[^=]+)/ && @rest_singles.length == 0
#
# This is a long style option, which start with `--'.
#
pattern = $1
if @canonical_names.include?(pattern)
option_name = pattern
else
#
# The option `option_name' is not registered in
@canonical_names'. # It may be an abbreviated. # match_count = 0 @canonical_names.each_key do |key| if key.index(pattern) == 0 option_name = key match_count += 1 end end if 2 <= match_count set_error(AmbigousOption, "option
#{argument}’ is ambiguous")
elsif match_count == 0
set_error(InvalidOption, “unrecognized option `#{argument}’”)
end
end
#
# Check an argument to the option.
#
if @argument_flags[option_name] == REQUIRED_ARGUMENT
if argument =~ /=(.*)$/
option_argument = $1
elsif 0 < arguments.length
option_argument = arguments.shift
else
set_error(MissingArgument,
"option `#{argument}' requires an argument")
end
elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
if argument =~ /=(.*)$/
option_argument = $1
elsif 0 < arguments.length && arguments[0] !~ /^-./
option_argument = arguments.shift
else
option_argument = ''
end
elsif argument =~ /=(.*)$/
set_error(NeedlessArgument,
"option `#{option_name}' doesn't allow an argument")
end
elsif argument =~ /^(-(.))(.*)/
#
# This is a short style option, which start with `-' (not `--').
# Short options may be catinated (e.g. `-l -g' is equivalent to
# `-lg').
#
option_name, ch, @rest_singles = $1, $2, $3
if @canonical_names.include?(option_name)
#
# The option `option_name' is found in `@canonical_names'.
# Check its argument.
#
if @argument_flags[option_name] == REQUIRED_ARGUMENT
if 0 < @rest_singles.length
option_argument = @rest_singles
@rest_singles = ''
elsif 0 < arguments.length
option_argument = arguments.shift
else
# 1003.2 specifies the format of this message.
set_error(MissingArgument, "option requires an argument --
#{ch}")
end
elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
if 0 < @rest_singles.length
option_argument = @rest_singles
@rest_singles = ''
elsif 0 < arguments.length && arguments[0] !~ /^-./
option_argument = arguments.shift
else
option_argument = ''
end
end
else
#
# This is an invalid option.
# 1003.2 specifies the format of this message.
#
if ENV.include?(‘POSIXLY_CORRECT’)
set_error(InvalidOption, “illegal option – #{ch}”)
else
set_error(InvalidOption, “invalid option – #{ch}”)
end
end
else
#
# This is a non-option argument.
# Only RETURN_IN_ORDER falled into here.
#
return ‘’, argument
end
return @canonical_names[option_name], option_argument
end
Make sure get_option is an alias for the new get method defined
above!
alias :get_option :get
alias :original_each :each
Changed so that we can specify an array of arguments to process,
which defaults to ARGV for backward compatibility.
def each( arguments = nil )
loop do
if arguments.nil? then
option_name, option_argument = get_option
else
option_name, option_argument = get_option( arguments )
end
break if option_name == nil
yield option_name, option_argument
end
end
end
–
Albert Davidson Chou, QA Manager
TeaLeaf Technology, Inc.
(415) 932-5031
AChou@TeaLeaf.com | http://www.TeaLeaf.com/
Evaluate TeaLeaf Technology today:
http://www.TeaLeaf.com/demo/