开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜