Class: Argvector

Inherits:
Object show all
Defined in:
lib/standard/facets/argvector.rb

Overview

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'}]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(line = nil, arity = nil) ⇒ Argvector

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


81
82
83
84
85
# File 'lib/standard/facets/argvector.rb', line 81

def initialize(line=nil, arity=nil)
  @line, @argv  = parse_line(line)
  @arity = parse_arity(arity||{})
  parse
end

Instance Attribute Details

#argvObject (readonly)

Returns the value of attribute argv


72
73
74
# File 'lib/standard/facets/argvector.rb', line 72

def argv
  @argv
end

#arityObject (readonly)

Returns the value of attribute arity


73
74
75
# File 'lib/standard/facets/argvector.rb', line 73

def arity
  @arity
end

#lineObject (readonly)

Returns the value of attribute line


71
72
73
# File 'lib/standard/facets/argvector.rb', line 71

def line
  @line
end

Class Method Details

.parameters(*args) ⇒ Object


67
68
69
# File 'lib/standard/facets/argvector.rb', line 67

def self.parameters(*args)
  new.parameters(*args)
end

Instance Method Details

#assoc_options(args) ⇒ Object

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"] ]

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/standard/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

#flagsObject

Return flags, which are true options.


109
110
111
112
113
114
115
116
117
# File 'lib/standard/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_options(assoc_options) ⇒ Object

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


329
330
331
332
333
334
335
336
337
338
339
# File 'lib/standard/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

#multi_flag(args = nil) ⇒ Object

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


316
317
318
319
320
321
322
323
324
325
# File 'lib/standard/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

#operandsObject Also known as: arguments

Returns operand array.


90
91
92
# File 'lib/standard/facets/argvector.rb', line 90

def operands
  @operands
end

#optionsObject

Returns options hash.


98
99
100
# File 'lib/standard/facets/argvector.rb', line 98

def options
  @options
end

#parametersObject

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


104
105
106
# File 'lib/standard/facets/argvector.rb', line 104

def parameters
  return @operands, @options
end

#parameters_without_duplicatesObject

Like parameters but without allowing for duplicate options.


181
182
183
184
185
186
187
188
189
190
191
# File 'lib/standard/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

#parseObject

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"}

207
208
209
210
211
212
213
214
215
216
# File 'lib/standard/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

#parse_arity(arity) ⇒ Object

Ensure arity is uniform.


245
246
247
248
249
# File 'lib/standard/facets/argvector.rb', line 245

def parse_arity(arity)
  arity2 = {}
  arity.each{ |k,v| arity2[k.to_s] = v.to_i }
  return arity2
end

#parse_line(line = nil) ⇒ Object

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


220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/standard/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(args) ⇒ Object

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


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/standard/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

#preflagsObject

Same as flags but only returns flags in the preoptions.


169
170
171
172
173
174
175
176
177
178
# File 'lib/standard/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

#preoptionsObject

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}

162
163
164
165
# File 'lib/standard/facets/argvector.rb', line 162

def preoptions
  preopts, remainder = *parse_preoptions(argv)
  return preopts
end

#subcommand_with_argumentsObject

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'.


146
147
148
149
150
151
# File 'lib/standard/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

#subcommand_with_parametersObject Also known as: subcommand

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


122
123
124
125
126
127
# File 'lib/standard/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

#subcommand_with_preoptionsObject


132
133
134
135
136
137
138
# File 'lib/standard/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