Class: Clio::Usage::Subcommand

Inherits:
Object
  • Object
show all
Defined in:
lib/clio/usage/subcommand.rb

Overview

Commandline Usage Command

This is the heart of usage; subclassed by Main and containing together Options and Arguments.

usage = Usage.new

Direct Known Subclasses

Command

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, parent = nil, &block) ⇒ Subcommand

Returns a new instance of Subcommand.



48
49
50
51
52
53
54
55
56
# File 'lib/clio/usage/subcommand.rb', line 48

def initialize(name, parent=nil, &block)
  @name        = name.to_s
  @parent      = parent
  @subcommands = []
  @options     = []
  @arguments   = []
  @help        = ''
  instance_eval(&block) if block
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(key, *args, &blk) ⇒ Object

METHOD MISSING




73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/clio/usage/subcommand.rb', line 73

def method_missing(key, *args, &blk)
  key = key.to_s
  case key
  when /\?$/
    option(key.chomp('?'), *args, &blk)
  else
    #k = full_name ? "#{full_name} #{key}" : "#{key}"
    c = command(key, &blk)
    args.each{ |a| c[a] }
    c
  end
end

Instance Attribute Details

#argumentsObject (readonly)

Array of arguments. Arguments and subcommands are mutually exclusive, ie. either @arguments or @subcommands will be empty.

TODO: Could use single attribute for both subcommands and arguments and use a flag to designate which type.



36
37
38
# File 'lib/clio/usage/subcommand.rb', line 36

def arguments
  @arguments
end

#help(string = nil) ⇒ Object (readonly)

Help text.



42
43
44
# File 'lib/clio/usage/subcommand.rb', line 42

def help
  @help
end

#nameObject (readonly)

Name of the command.



25
26
27
# File 'lib/clio/usage/subcommand.rb', line 25

def name
  @name
end

#optionsObject (readonly) Also known as: switches

Array of options.



39
40
41
# File 'lib/clio/usage/subcommand.rb', line 39

def options
  @options
end

#parentObject (readonly)

Parent command. This is needed to support cascading options. – NOTE: If it were possible to have this it would be better. ++



22
23
24
# File 'lib/clio/usage/subcommand.rb', line 22

def parent
  @parent
end

#subcommandsObject (readonly) Also known as: commands

Array of subcommands.



28
29
30
# File 'lib/clio/usage/subcommand.rb', line 28

def subcommands
  @subcommands
end

Instance Method Details

#===(other_name) ⇒ Object



341
342
343
# File 'lib/clio/usage/subcommand.rb', line 341

def ===(other_name)
  name == other_name.to_s
end

#[](*x) ⇒ Object

Super shorthand notation.

cli['document']['--output=FILE -o']['<files>']


292
293
294
295
296
297
298
299
300
301
# File 'lib/clio/usage/subcommand.rb', line 292

def [](*x)
  case x[0].to_s[0,1]
  when '-'
    opt(*x)
  when '<'
    arg(*x)
  else
    subcommand(*x)
  end
end

#argument(*n_type, &block) ⇒ Object Also known as: arg

Define an argument. Takes a name, optional index and block.

Indexing of arguments starts at 1, not 0.

Examples

argument(:path)
argument(1, :path)

Raises:

  • (ArgumentError)


216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/clio/usage/subcommand.rb', line 216

def argument(*n_type, &block)
  index = Integer===n_type[0] ? n_type.shift : @arguments.size + 1
  type  = n_type.shift
  help  = n_type.shift

  index = index - 1
  type = type.to_s.sub(/^\</,'').chomp('>')

  if type[0,1] == '*'
    type.sub!('*', '')
    splat = true
  elsif type[-1,1] == '*'
    type.sub!(/[*]$/, '')
    splat = true
  else
    splat = false
  end

  #if type.index(':')
  #  name, type = *type.split(':')
  #  name = name.downcase
  #  type = type.upcase
  #else
  #  if type.upcase == type
  #    name = nil
  #  else
  #    name = type
  #    type = type.upcase
  #  end
  #end

  raise ArgumentError, "Command cannot have both arguments (eg. #{type}) and subcommands." unless subcommands.empty?

  if arg = @arguments[index]
    arg.type(type) if type
    #arg.name(name) if name
    arg.help(help) if help
    arg.splat(splat) if splat
    arg.instance_eval(&block) if block
  else
    if type || block
      arg = Argument.new(type, &block) #self, &block)
      #arg.name(name) if name
      arg.help(help) if help
      arg.splat(splat) if splat
      @arguments[index] = arg
    end
  end
  return arg
end

#completionObject



307
308
309
310
311
312
313
314
315
# File 'lib/clio/usage/subcommand.rb', line 307

def completion
  if subcommands.empty?
    options.collect{|o| o.to_s.strip } +
    arguments.collect{|c| c.name}
  else
    options.collect{|o| o.to_s.strip } +
    subcommands.collect{|c| c.name}
  end
end

#full_nameObject

Full callable command name.



359
360
361
362
363
364
365
# File 'lib/clio/usage/subcommand.rb', line 359

def full_name
  if parent && parent.full_name
    "#{parent.full_name} #{name}"
  else
    "#{name}"
  end
end

#help!(*args) ⇒ Object



87
88
89
90
91
# File 'lib/clio/usage/subcommand.rb', line 87

def help!(*args)
  Hash[*args].each do |key, desc|
    self[key, desc]
  end
end

#initialize_copy(c) ⇒ Object



59
60
61
62
63
64
65
66
# File 'lib/clio/usage/subcommand.rb', line 59

def initialize_copy(c)
  @parent      = c.parent
  @name        = c.name.dup
  @options     = c.options.dup
  @arguments   = c.arguments.dup
  @subcommands = c.subcommands.dup
  @help        = c.help.dup
end

#inspectObject



346
347
348
349
350
351
352
353
354
355
356
# File 'lib/clio/usage/subcommand.rb', line 346

def inspect
  s = ''
  s << "#<#{self.class}:#{object_id} #{@name}"
  s << " @arguments=#{@arguments.inspect} " unless @arguments.empty?
  s << " @options=#{@options.inspect} "     unless @options.empty?
  #s << "@switches=#{@switches.inspect} "   unless @switches.empty?
  s << " @help=#{@help.inspect}"            unless @help.empty?
  #s << "@commands=#{@commands.inspect} "  unless @commands.empty?
  s << ">"
  s
end

#keyObject



68
# File 'lib/clio/usage/subcommand.rb', line 68

def key ; @name.to_sym ; end

#opt(name, help = nil) ⇒ Object Also known as: swt

Option shorthand.

opt('--output=FILE -o', 'output directory')


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/clio/usage/subcommand.rb', line 150

def opt(name, help=nil)
  name, *aliases = name.split(/\s+/)
  name, type = *name.split('=')
  mult = false
  if type && type[0,1] == '*'
    mult = true
    type = type[1..-1]
  end
  name = option_name(name).to_sym
  o = option(name, *aliases)
  o.help(help) if help
  o.argument(type) if type
  o.multiple(mult)
  self
end

#option(name, *aliases, &block) ⇒ Object Also known as: switch, switch?

Define an option.

option(:output, :o)


132
133
134
135
136
137
138
139
140
141
142
# File 'lib/clio/usage/subcommand.rb', line 132

def option(name, *aliases, &block)
  opt = options.find{|o| o === name}
  if not opt
    opt = Option.new(name) #, self)
    #opt.aliases(*aliases)
    @options << opt
  end
  opt.aliases(*aliases) unless aliases.empty?
  opt.instance_eval(&block) if block
  opt
end

#option?(name) ⇒ Boolean

Option defined?

Returns:

  • (Boolean)


319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/clio/usage/subcommand.rb', line 319

def option?(name)
  opt = options.find{|o| o === name}
  if parent && !opt
    opt = parent.option?(name)
  end
  opt
  #return opt if opt
  #options.each do |o|
  #  return o if o.aliases.include?(key)
  #end
  #nil
end

#parse(argv, index = 0) ⇒ Object

Parse usage.



428
429
430
431
# File 'lib/clio/usage/subcommand.rb', line 428

def parse(argv, index=0)
  @parser ||= Parser.new(self, argv, index)
  @parser.parse
end

#subcommand(name, help = nil, &block) ⇒ Object Also known as: cmd, command

Define or retrieve a command.

subcommand('remote')

A shortcut to accessing subcommands of subcommands, the following statements are equivalent:

subcommand('remote').subcommand('add')

subcommand('remote add')


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/clio/usage/subcommand.rb', line 104

def subcommand(name, help=nil, &block)
  name, names = *name.to_s.strip.split(/\s+/)
  if names
    names = [name, *names]
    cmd = names.inject(self) do |c, n|
      c.subcommand(n)
    end
  else
    cmd = subcommands.find{ |c| c === name }
    unless cmd
      cmd = Subcommand.new(name, self)
      subcommands << cmd
    end
  end
  cmd.help(help) if help
  cmd.instance_eval(&block) if block
  cmd
end

#to_sObject

Usage text.



369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/clio/usage/subcommand.rb', line 369

def to_s
  #s = [full_name]
  s = [name]

  case options.size
  when 0
  when 1, 2, 3
    s.concat(options.collect{ |o| "[#{o.to_s.strip}]" })
  else
    s << "[switches]"  # switches? vs. options
  end

  s << arguments.join(' ') unless arguments.empty?

  case subcommands.size
  when 0
  when 1
    s << subcommands.join('')
  when 2, 3
    s << '[' + subcommands.join(' | ') + ']'
  else
    s << 'command'
  end

  s.flatten.join(' ')
end

#to_s_helpObject

Help text.



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/clio/usage/subcommand.rb', line 398

def to_s_help
  s = []
  unless help.empty?
    s << help
    s << ''
  end
  s << "Usage:"
  s << "  " + to_s
  unless subcommands.empty?
    s << ''
    s << 'Commands:'
    s.concat(subcommands.collect{ |x| "  %-20s %s" % [x.name, x.help] }.sort)
  end
  unless arguments.empty?
    s << ''
    s << "Arguments:"
    s.concat(arguments.collect{ |x| "  %-20s %s" % [x, x.help] })
  end
  unless options.empty?
    s << ''
    s << 'Switches:'
    s.concat(options.collect{ |x| "  %-20s %s" % [x, x.help] })
  end
  s.flatten.join("\n")
end