ruby syntactic sugar for core only arg parsing
Syntactic sugar for counting the non-switch args?
argn = 0
ARGV.each do 开发者_开发知识库|arg|
mission = Mission_DB.new unless mission
if(arg.match(/^\-.*=/)) then
fsav = arg.split('=')[1] if arg.match(/\-save=/)
skip = arg.split('=')[1].split(',') if arg.match(/\-skip=/)
mission.mission = arg.split('=')[1].downcase if arg.match(/\-mission=/)
else
argn += 1
mission.parseP1SCLRV(arg) if argn == 1
template = arg if argn == 2
mission.parseP1SCLRVPLV(arg) if argn == 3
mission.parseDbUserLimits(arg) if argn == 4
end
end
I've tried to find a reusable, clean core only arg parsing syntax that is intuitive (readable without comments). This isn't bad ... but its not best good enough.
- I hate the argn crap
- I hate the if /-.*=/ followed by each individual switch
- each_with_index won't really accomplish what I'm looking for as switches could be embedded anywhere within the non switched args
Feel free to revamp entirely provided we are sufficing the "clean, core only, intuitive" requirements.
Thanks and Cheers --Reed
Have you considered using optparse? It comes with the Ruby standard library.
Here's a class that uses optparse to do option parsing for the arguments in your example. It handles errors, prints its usage if "-h" or "--help" is given, and encapsulates the parsed arguments into a nice class you can pass around:
require 'optparse'
class Arguments
POSITIONAL_ARGS = %w(p1sclrv template p1sclrvplv db_user_limits)
attr_reader :mission
attr_reader :save_path
attr_reader :what_to_skip
attr_reader *POSITIONAL_ARGS
def initialize(argv)
option_parser.parse!(argv)
POSITIONAL_ARGS.each do |positional_arg|
value = argv.shift
instance_variable_set("@#{positional_arg}", value)
raise OptionParser::MissingArgument, positional_arg.to_s unless value
end
raise OptionParser::NeedlessArgument, argv.first unless argv.empty?
rescue OptionParser::ParseError => e
puts e
puts option_parser
exit(1)
end
private
def option_parser
OptionParser.new do |op|
op.banner += ' ' + POSITIONAL_ARGS.join(' ')
op.on('--save=PATH', 'Save to PATH') do |value|
@save_path = value
end
op.on('--skip=WHAT', 'Skip WHAT') do |value|
@what_to_skip = value
end
op.on('--mission=NAME', 'Do mission NAME') do |value|
@mission = value
end
end
end
end
In real use, pass ARGV to it:
args = Arguments.new(ARGV)
Here's an example passing a made-up ARGV and printing the parsed arguments:
args = Arguments.new(%w(--skip=FOO alpha bravo charley delta))
p args.p1sclrv # => "alpha"
p args.template # => "bravo"
p args.p1sclrvplv # => "charley"
p args.db_user_limits # => "delta"
p args.mission # => nil
p args.save_path # => nil
p args.what_to_skip # => "FOO"
Here's what the help looks like:
Arguments.new(%w(--help))
# => Usage: foo [options] p1sclrv template p1sclrvplv db_user_limits
# => --save=PATH Save to PATH
# => --skip=WHAT Skip WHAT
# => --mission=NAME Do mission NAME
My own iterating:
fsav = nil
skip = []
template = p1sclrv = p1sclrvplv = dbuserlimits = nil
ARGV.each do |arg|
case arg
when /\-save=/ then fsav = arg.split('=')[1]
when /\-skip=/ then skip = arg.split('=')[1].split(',')
when /\-mission=/ then mission.mission = arg.split('=')[1].downcase
else
unless(p1sclrv) then p1sclrv = arg; next; end
unless(template) then template = arg; next; end
unless(p1sclrvplv) then p1sclrvplv = arg; next; end
unless(dbuserlimits) then dbuserlimits = arg; next; end
end
end
EDIT: Getting better.
精彩评论