Class: CTioga2::Commands::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/ctioga2/commands/commands.rb

Overview

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.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(n, short, long, args = [], opts = {}, d_short = nil, d_long = nil, group = nil, register = true, &code) ⇒ Command

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.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# 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

Instance Attribute Details

#argumentsObject

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



54
55
56
# File 'lib/ctioga2/commands/commands.rb', line 54

def arguments
  @arguments
end

#codeObject

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.



83
84
85
# File 'lib/ctioga2/commands/commands.rb', line 83

def code
  @code
end

#contextObject

The context of definition [file, line]



89
90
91
# File 'lib/ctioga2/commands/commands.rb', line 89

def context
  @context
end

#documentation_contextObject

The context of the documentation



92
93
94
# File 'lib/ctioga2/commands/commands.rb', line 92

def documentation_context
  @documentation_context
end

#groupObject

The CommandGroup to which the command belongs



86
87
88
# File 'lib/ctioga2/commands/commands.rb', line 86

def group
  @group
end

#long_descriptionObject

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



64
65
66
# File 'lib/ctioga2/commands/commands.rb', line 64

def long_description
  @long_description
end

#long_optionObject

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



50
51
52
# File 'lib/ctioga2/commands/commands.rb', line 50

def long_option
  @long_option
end

#nameObject

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



43
44
45
# File 'lib/ctioga2/commands/commands.rb', line 43

def name
  @name
end

#optional_argumentsObject

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



58
59
60
# File 'lib/ctioga2/commands/commands.rb', line 58

def optional_arguments
  @optional_arguments
end

#short_descriptionObject

A short one-line description of the command



61
62
63
# File 'lib/ctioga2/commands/commands.rb', line 61

def short_description
  @short_description
end

#short_optionObject

Its short command-line option, or nil if none



46
47
48
# File 'lib/ctioga2/commands/commands.rb', line 46

def short_option
  @short_option
end

Class Method Details

.document_command(cmd, desc) ⇒ Object

Sets the long documentation of the given command



151
152
153
154
155
156
157
# 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) ⇒ Object



94
95
96
97
# 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

Instance Method Details

#argument_numberObject

Returns the number of compulsory arguments



133
134
135
# File 'lib/ctioga2/commands/commands.rb', line 133

def argument_number
  return @arguments.size
end

#convert_arguments(args) ⇒ Object

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.



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# 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
      raise ArgumentNumberMismatch, "Command #{@name} was called with #{args.size} arguments, 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) ⇒ Object

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)



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
# File 'lib/ctioga2/commands/commands.rb', line 227

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) ⇒ Object

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



139
140
141
142
143
144
145
146
147
148
# 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) ⇒ Boolean

Whether the Command accepts the named option.

Returns:

  • (Boolean)


273
274
275
# File 'lib/ctioga2/commands/commands.rb', line 273

def has_option?(option)
  return target_option_names.key?(normalize_option_name(option))
end

#has_options?Boolean

Whether the Command accepts any option at all ?

Returns:

  • (Boolean)


278
279
280
# File 'lib/ctioga2/commands/commands.rb', line 278

def has_options?
  return !(@optional_arguments.empty?)
end

#normalize_option_name(opt) ⇒ Object

Returns a lowercase



268
269
270
# File 'lib/ctioga2/commands/commands.rb', line 268

def normalize_option_name(opt)
  return opt.gsub(/_/,"-").downcase
end

#option_stringsObject

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.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# 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) ⇒ Object

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.



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/ctioga2/commands/commands.rb', line 288

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
  args += compulsory_args
  if has_options?
    if optional_args
      args << optional_args
    else
      args << {}
    end
  end
  @code.call(*args)
end

#set_code(&code) ⇒ Object

Sets the code to the block given.



128
129
130
# File 'lib/ctioga2/commands/commands.rb', line 128

def set_code(&code)
  @code = code
end

#target_option_namesObject

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



257
258
259
260
261
262
263
264
265
# File 'lib/ctioga2/commands/commands.rb', line 257

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