Class Argvector
In: lib/facets/supplemental/facets/argvector.rb
Parent: Object

Argvector

Argvector provides a very simple means of parsing command line arguments.

Unlike other more complex libs this provides only the most basic and standard parsing functionality. In many cases that‘s all one really needs.

Usage is straight foward. Simply instantiate the class and query it for the particular "views" of the command line you want.

  cargs = Argvector.new("-a foo -b=2")

  cargs.parameters    #=> [['foo'],{'a'=>true,'b'=>'2'}]
  cargs.flags         #=> ['a']
  cargs.preoptions    #=> {'a'=>true}
  cargs.preflags      #=> ['a']
  cargs.subcommand    #=> ['foo', [], {'b'=>'2'}]

Methods

Attributes

argv  [R] 
arity  [R] 
line  [R] 

Public Class methods

Takes the command line string (or array) and options. Options have flags and end with a hash of option arity.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 81
  def initialize(line=nil, arity=nil)
    @line, @argv  = parse_line(line)
    @arity = parse_arity(arity||{})
    parse
  end

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 67
  def self.parameters(*args)
    new.parameters(*args)
  end

Public Instance methods

arguments()

Alias for operands

Parse flags takes the command line and transforms it such that flags (eg. -x and —x) are elemental associative arrays.

  line = "--foo hello --try=this"
  argv = Argvector.new(line)

  args = line.split(/\s/)
  argv.assoc_options(args)  #=> [ ["foo",true], "hello", ["try","this"] ]

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 286
  def assoc_options(args)
    ##args = args.dup
    args = multi_flag(args) #unless opts.include?(:simple)
    i = 0
    while i < args.size
      arg = args[i]
      case arg
      when /^-/
        arg = arg.sub(/^-{1,2}/,'')
        if arg.index('=')
          key, val = arg.split('=')
          args[i] = [key, val||true]
        elsif arity.key?(arg)
          cnt = arity[arg]
          key = arg
          val = args[i+1,cnt]
          args[i,cnt+1] = [[key, *val]]
          i += (cnt - 1)
        else
          key = arg
          args[i] = [key,true]
        end
      end
      i += 1
    end
    return args
  end

Return flags, which are true options.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 109
  def flags
    f = []
    @options.each do |k, v|
      if TrueClass===v or FalseClass===v  # not that it's ever false
        f << k
      end
    end
    return f
  end

Format flag options. This converts the associative array of options/flags into a hash. Repeat options will be placed in arrays.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 329
  def format_options(assoc_options)
    opts = {}
    assoc_options.each do |k,v|
      if opts.key?(k)
        opts[k] = [opts[k]].flatten << v
      else
        opts[k] = v
      end
    end
    return opts
  end

Split single letter option groupings into separate options. ie. -xyz => -x -y -z

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 316
  def multi_flag(args=nil)
    args ||= argv
    args.collect { |arg|
      if md = /^-(\w{2,})/.match( arg )
        md[1].split(//).collect { |c| "-#{c}" }
      else
        arg.dup
      end
    }.flatten
  end

Returns operand array.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 90
  def operands
    @operands
  end

Returns options hash.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 98
  def options
    @options
  end

Returns [operands, options], which is good for plugging directly into a method.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 104
  def parameters
    return @operands, @options
  end

Like parameters but without allowing for duplicate options.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 181
  def parameters_without_duplicates
    opts = {}
    @options.each do |k,v|
      if Array===v
        opts[k] = v[0]
      else
        opts[k] =  v
      end
    end
    return @operands, opts
  end

Basic parser partitions the command line into options and operands. Options are converted to a hash and the two parts are returned.

  line = "--trace stamp --file=VERSION"
  argv = Argvector.new(line)

  args, keys = *argv.parse

  args #=> ["stamp"]
  keys #=> {"trace"=>true, "file"=>"VERSION"}

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 207
  def parse
    args = assoc_options(argv) #, *opts_arity)

    opts, opds = args.partition{ |a| Array === a }

    @operands = opds
    @options  = format_options(opts)

    return @operands, @options
  end

Ensure arity is uniform.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 245
  def parse_arity(arity)
    arity2 = {}
    arity.each{ |k,v| arity2[k.to_s] = v.to_i }
    return arity2
  end

First pass parser to split the command line into an array using Shellwords, if not already so divided.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 220
  def parse_line(line=nil)
    if line
      case line
      when String
        argv = Shellwords.shellwords(line)
      else
        argv = line.to_ary.dup
        line = argv.join(' ')
      end
    else
      argv = ARGV.dup
      line = argv.join(' ')
    end
    return line, argv
  end

Parse preoptions. A "preoption" is one that occurs before the first operans (if any).

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 253
  def parse_preoptions(args)
    ##args = args.dup
    args = multi_flag(args) #unless opts.include?(:simple)

    flags = []
    while args.first =~ /^-/
      key = args.shift
      key.sub!(/^-{1,2}/,'')
      if key.index('=')
        key, val = key.split('=')
      elsif a = arity[key]
        val = args.slice!(0,a)
        val = val.first if a == 1
      else
        val = true
      end
      flags << [key, val]
    end

    flags = format_options(flags)

    return flags, args
  end

Same as flags but only returns flags in the preoptions.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 169
  def preflags
    preopts, remainder = *parse_preoptions(argv)
    f = []
    preopts.each do |k, v|
      if TrueClass===v or FalseClass===v  # not that it's ever false
        f << k
      end
    end
    return f
  end

Returns a hash of options that occur before the first operand. This works well with subcommand to get the main command‘s options.

  line = "--trace stamp --file VERSION"
  cargs = Argvector.new(line)
  opts = cargs.preoptions
  opts #=> {"trace"=>true}

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 162
  def preoptions
    preopts, remainder = *parse_preoptions(argv)
    return preopts
  end
subcommand()

Assumes the first operand is a "subcommand" and returns it and the argments following it as another Arguments object.

TODO: This probably should be called ‘subcommand’.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 146
  def subcommand_with_arguments
    opts, args = *parse_preoptions(argv)
    cmd = args.shift
    subargs = self.class.new(args, @arity)
    return cmd, subargs
  end

Assumes the first operand is a "subcommand" and returns it and the argments following it as parameters.

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 122
  def subcommand_with_parameters
    opts, args = *parse_preoptions(argv)
    cmd = args.shift
    subargs = self.class.new(args, @arity)
    return [cmd, *subargs.parameters]
  end

[Source]

# File lib/facets/supplemental/facets/argvector.rb, line 132
  def subcommand_with_preoptions
    pre, args = *parse_preoptions(argv)
    cmd = args.shift
    subargs = self.class.new(args, @arity)
    args, opts = *subargs.parameters
    return [cmd, args, pre.merge(opts)]
  end

[Validate]