class CTioga2::Commands::Command

One of the commands that can be used.

todo Write a Shortcut command that would simply be a shortcut for other things. Possibly taking arguments ? It could take a description, though that wouldn't be necessary.

todo Use this Shortcut to write DeprecatedShortcut for old ctioga options.

Attributes

arguments[RW]

The compulsory arguments it can take, in the form of an array of CommandArgument

code[RW]

The code that will be called. It must be a Proc object, or any objects that answers a call method.

The corresponding block will be called with the following arguments:

  • first, the PlotMaker instance where the command will be running

  • second, as many arguments as there are arguments.

  • third, if optional_arguments is non-empty, a hash containing the values of the optional arguments. It will be an empty hash if no optional arguments are given in the command). It will be empty if the command is called as an option in the command-line.

Few rules for writing the code:

  • code should avoid as much as possible to rely on closures.

  • the CommandArgument framework will make sure the arguments are given with the appropriate type or raise an exception. Don't bother.

context[RW]

The context of definition [file, line]

documentation_context[RW]

The context of the documentation

group[RW]

The CommandGroup to which the command belongs

long_description[RW]

A longer description. Typically input using a here-document.

long_option[RW]

Its long command-line option, or nil if it should not be called from the command-line (but you really don't want that).

name[RW]

The name of the command, ie how to call it in a commands file

optional_arguments[RW]

Optional arguments to a command, in the form of a Hash 'option name' => CommandArgument

short_description[RW]

A short one-line description of the command

short_option[RW]

Its short command-line option, or nil if none

Public Class Methods

document_command(cmd, desc) click to toggle source

Sets the long documentation of the given command

# File lib/ctioga2/commands/commands.rb, line 151
def self.document_command(cmd, desc)
  tg = Commands::Interpreter.command(cmd)
  if tg
    tg.documentation_context = Command.get_calling_context(1)
    tg.long_description = desc
  end
end
get_calling_context(id=2) click to toggle source
# File lib/ctioga2/commands/commands.rb, line 94
def self.get_calling_context(id=2)
  caller[id].gsub(/.*\/ctioga2\//, 'lib/ctioga2/') =~ /(.*):(\d+)/
  return [$1, $2.to_i]
end
new(n, short, long, args = [], opts = {}, d_short = nil, d_long = nil, group = nil, register = true, &code) click to toggle source

Creates a Command, with all attributes set up. The code can be set using set_code.

Single and double dashes are stripped from the beginning of the short and long options respectively.

# File lib/ctioga2/commands/commands.rb, line 104
def initialize(n, short, long, args = [], opts = {}, 
               d_short = nil, d_long = nil, group = nil,
               register = true, &code)
  @name = n
  @short_option = short && short.gsub(/^-/,'')
  @long_option = long && long.gsub(/^--/,'')
  @arguments = args
  @optional_arguments = opts
  if(@short_option and ! @long_option)
    raise "A long option must always be present if a short one is"
  end
  @code = code
  self.describe(d_short, d_long, group)

  @context = Command.get_calling_context

  # Registers automatically the command
  if register
    Commands::Interpreter.register_command(self)
  end

end

Public Instance Methods

argument_number() click to toggle source

Returns the number of compulsory arguments

# File lib/ctioga2/commands/commands.rb, line 133
def argument_number
  return @arguments.size
end
convert_arguments(args) click to toggle source

Converts the Array of String given into an Array of the type suitable for the code of the Command. This deals only with compulsory arguments. Returns the array.

Any object which is not a String is left as is (useful for instance for the OptionParser with boolean options)

As a special case, if the command takes no arguments and the arguments is [true], no exception is raised, and the correct number of arguments is returned.

# File lib/ctioga2/commands/commands.rb, line 202
def convert_arguments(args)
  if args.size != @arguments.size
    if(@arguments.size == 0 && args.size == 1 && args[0] == true)
      return []
    else
      ar = args.map { |x| "'#{x}'"}
      raise ArgumentNumberMismatch, "Command #{@name} was called with #{args.size} arguments: #{ar.join(", ")}, but it takes #{@arguments.size}"
    end
  end
  retval = []
  @arguments.each_index do |i|
    if ! args[i].is_a? String
      retval << args[i]
    else
      retval << @arguments[i].type.string_to_type(args[i])
    end
  end
  return retval
end
convert_options(options) click to toggle source

Converts the Hash of String given into a Hash of the type suitable for the code of the Command. Only optional arguments are taken into account.

Any object which is not a String is left as is (useful for instance for the OptionParser with boolean options)

# File lib/ctioga2/commands/commands.rb, line 228
def convert_options(options)
  target_options = {}
  conv = target_option_names()
  for k,v in options
    kn = normalize_option_name(k)
    if ! conv.key? kn
      raise CommandOptionUnkown, "Unkown option #{k} for command #{@name}"
    end
    opt = @optional_arguments[conv[kn]]
    if v.is_a? String
      v = opt.type.string_to_type(v)
    end
    target = opt.option_target || conv[kn]
    if opt.option_deprecated
      expl = ""
      if opt.option_target
        expl = " -- please use #{opt.option_target} instead"
      elsif opt.option_deprecated != true # Ie more than plain
                                          # true/false
        expl = " -- #{opt.option_deprecated}"
      end
      Log::warn { "Deprecated option #{k}#{expl}" }
    end

    target_options[target] = v
  end
  return target_options
end
describe(short, long = nil, group = nil) click to toggle source

Sets the descriptions of the command. If the long description is ommitted, the short is reused.

# File lib/ctioga2/commands/commands.rb, line 139
def describe(short, long = nil, group = nil)
  @documentation_context = Command.get_calling_context(1)
  @short_description = short
  @long_description = long || short
  if(group)
    group = Interpreter::group(group) if group.is_a? String
    @group = group
    group.commands << self
  end
end
has_option?(option) click to toggle source

Whether the Command accepts the named option.

# File lib/ctioga2/commands/commands.rb, line 275
def has_option?(option)
  return target_option_names.key?(normalize_option_name(option))
end
has_options?() click to toggle source

Whether the Command accepts any option at all ?

# File lib/ctioga2/commands/commands.rb, line 280
def has_options?
  return !(@optional_arguments.empty?)
end
normalize_option_name(opt) click to toggle source

Returns a lowercase

# File lib/ctioga2/commands/commands.rb, line 270
def normalize_option_name(opt)
  return opt.gsub(/_/,"-").downcase
end
option_strings() click to toggle source

Returns a list of three strings:

  • the short option

  • the long option with arguments

  • the description string

Returns nil if the long option is not defined.

# File lib/ctioga2/commands/commands.rb, line 165
def option_strings
  if ! @long_option
    return nil
  end
  retval = []
  # Short option
  retval << ( @short_option ? "-#{@short_option}" : nil)
  # Long option + arguments
  if @arguments.size > 0
    retval << @arguments.first.type.
      option_parser_long_option(@long_option, 
                                @arguments.first.displayed_name) + 
      if @arguments.size > 1
        " " + 
          @arguments[1..-1].map do |t|
        t.displayed_name.upcase
      end.join(" ")
      else
        ""
      end
  else
    retval << "--#{@long_option}"
  end
  retval << @short_description
  return retval
end
run_command(plotmaker_target, compulsory_args, optional_args = nil) click to toggle source

Runs the command with the given plotmaker_target, the compulsory arguments and the optional ones. Any mismatch in the number of things will result in an Exception.

The arguments will not be processed further.

# File lib/ctioga2/commands/commands.rb, line 290
def run_command(plotmaker_target, compulsory_args, 
                optional_args = nil)
  args = [plotmaker_target]
  if compulsory_args.size != @arguments.size
    raise ArgumentNumberMismatch, "Command #{@name} was called with #{args.size} arguments, but it takes #{@arguments.size}"
  end
  plotmaker_target.interpreter.
    add_instruction(Instruction.new(self, compulsory_args, optional_args))
  args += compulsory_args
  if has_options?
    if optional_args
      args << optional_args
    else
      args << {}
    end
  end
  @code.call(*args)
end
set_code(&code) click to toggle source

Sets the code to the block given.

# File lib/ctioga2/commands/commands.rb, line 128
def set_code(&code)
  @code = code
end
target_option_names() click to toggle source

Returns a hash “normalized option names” => 'real option name'

# File lib/ctioga2/commands/commands.rb, line 258
def target_option_names
  return @tg_op_names if @tg_op_names

  @tg_op_names = {}
  for k in @optional_arguments.keys
    @tg_op_names[normalize_option_name(k)] = k
  end
  return @tg_op_names
end