Class: Cri::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/cri/command.rb

Overview

Cri::Command represents a command that can be executed on the command line. It is also used for the command-line tool itself.

Defined Under Namespace

Classes: CriExitException, OptionParserPartitioningDelegate

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCommand

Returns a new instance of Command



139
140
141
142
143
144
# File 'lib/cri/command.rb', line 139

def initialize
  @aliases            = Set.new
  @commands           = Set.new
  @option_definitions = Set.new
  @default_subcommand_name = nil
end

Instance Attribute Details

#aliasesArray<String>

Returns A list of aliases for this command that can be used to invoke this command

Returns:

  • (Array<String>)

    A list of aliases for this command that can be used to invoke this command



71
72
73
# File 'lib/cri/command.rb', line 71

def aliases
  @aliases
end

#blockProc

Returns The block that should be executed when invoking this command (ignored for commands with subcommands)

Returns:

  • (Proc)

    The block that should be executed when invoking this command (ignored for commands with subcommands)



93
94
95
# File 'lib/cri/command.rb', line 93

def block
  @block
end

#commandsSet<Cri::Command> Also known as: subcommands

Returns This command’s subcommands

Returns:



60
61
62
# File 'lib/cri/command.rb', line 60

def commands
  @commands
end

#default_subcommand_nameSymbol

Returns The name of the default subcommand

Returns:

  • (Symbol)

    The name of the default subcommand



64
65
66
# File 'lib/cri/command.rb', line 64

def default_subcommand_name
  @default_subcommand_name
end

#descriptionString

Returns The long description (“description”)

Returns:

  • (String)

    The long description (“description”)



77
78
79
# File 'lib/cri/command.rb', line 77

def description
  @description
end

#hiddenBoolean Also known as: hidden?

Returns true if the command is hidden (e.g. because it is deprecated), false otherwise

Returns:

  • (Boolean)

    true if the command is hidden (e.g. because it is deprecated), false otherwise



85
86
87
# File 'lib/cri/command.rb', line 85

def hidden
  @hidden
end

#nameString

Returns The name

Returns:



67
68
69
# File 'lib/cri/command.rb', line 67

def name
  @name
end

#option_definitionsArray<Hash>

Returns The list of option definitions

Returns:

  • (Array<Hash>)

    The list of option definitions



89
90
91
# File 'lib/cri/command.rb', line 89

def option_definitions
  @option_definitions
end

#summaryString

Returns The short description (“summary”)

Returns:

  • (String)

    The short description (“summary”)



74
75
76
# File 'lib/cri/command.rb', line 74

def summary
  @summary
end

#supercommandCri::Command?

Returns This command’s supercommand, or nil if the command has no supercommand

Returns:

  • (Cri::Command, nil)

    This command’s supercommand, or nil if the command has no supercommand



57
58
59
# File 'lib/cri/command.rb', line 57

def supercommand
  @supercommand
end

#usageString

Returns The usage, without the “usage:” prefix and without the supercommands’ names.

Returns:

  • (String)

    The usage, without the “usage:” prefix and without the supercommands’ names.



81
82
83
# File 'lib/cri/command.rb', line 81

def usage
  @usage
end

Class Method Details

.define(string = nil, filename = nil, &block) ⇒ Cri::Command

Creates a new command using the DSL. If a string is given, the command will be defined using the string; if a block is given, the block will be used instead.

If the block has one parameter, the block will be executed in the same context with the command DSL as its parameter. If the block has no parameters, the block will be executed in the context of the DSL.

Parameters:

  • string (String, nil) (defaults to: nil)

    The command definition as a string

  • filename (String, nil) (defaults to: nil)

    The filename corresponding to the string parameter (only useful if a string is given)

Returns:



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cri/command.rb', line 108

def self.define(string = nil, filename = nil, &block)
  dsl = Cri::CommandDSL.new
  if string
    args = filename ? [string, filename] : [string]
    dsl.instance_eval(*args)
  elsif [-1, 0].include? block.arity
    dsl.instance_eval(&block)
  else
    block.call(dsl)
  end
  dsl.command
end

.new_basic_helpCri::Command

Returns a new command that implements showing help.

Returns:



134
135
136
137
# File 'lib/cri/command.rb', line 134

def self.new_basic_help
  filename = File.dirname(__FILE__) + '/commands/basic_help.rb'
  define(File.read(filename))
end

.new_basic_rootCri::Command

Returns a new command that has support for the -h/--help option and also has a help subcommand. It is intended to be modified (adding name, summary, description, other subcommands, …)

Returns:



126
127
128
129
# File 'lib/cri/command.rb', line 126

def self.new_basic_root
  filename = File.dirname(__FILE__) + '/commands/basic_root.rb'
  define(File.read(filename))
end

Instance Method Details

#<=>(other) ⇒ -1, ...

Compares this command's name to the other given command's name.

Parameters:

Returns:

  • (-1, 0, 1)

    The result of the comparison between names

See Also:

  • Object<=>


340
341
342
# File 'lib/cri/command.rb', line 340

def <=>(other)
  name <=> other.name
end

#add_command(command) ⇒ void

This method returns an undefined value.

Adds the given command as a subcommand to the current command.

Parameters:

  • command (Cri::Command)

    The command to add as a subcommand



177
178
179
180
# File 'lib/cri/command.rb', line 177

def add_command(command)
  @commands << command
  command.supercommand = self
end

#command_named(name, hard_exit: true) ⇒ Cri::Command

Returns the command with the given name. This method will display error messages and exit in case of an error (unknown or ambiguous command).

The name can be a full command name, a partial command name (e.g. “com” for “commit”) or an aliased command name (e.g. “ci” for “commit”).

Parameters:

  • name (String)

    The full, partial or aliases name of the command

Returns:



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/cri/command.rb', line 232

def command_named(name, hard_exit: true)
  commands = commands_named(name)

  if commands.empty?
    $stderr.puts "#{self.name}: unknown command '#{name}'\n"
    raise CriExitException.new(is_error: true)
  elsif commands.size > 1
    $stderr.puts "#{self.name}: '#{name}' is ambiguous:"
    $stderr.puts "  #{commands.map(&:name).sort.join(' ')}"
    raise CriExitException.new(is_error: true)
  else
    commands[0]
  end
rescue CriExitException => e
  exit(e.error? ? 1 : 0) if hard_exit
end

#commands_named(name) ⇒ Array<Cri::Command>

Returns the commands that could be referred to with the given name. If the result contains more than one command, the name is ambiguous.

Parameters:

  • name (String)

    The full, partial or aliases name of the command

Returns:

  • (Array<Cri::Command>)

    A list of commands matching the given name



210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/cri/command.rb', line 210

def commands_named(name)
  # Find by exact name or alias
  @commands.each do |cmd|
    found = cmd.name == name || cmd.aliases.include?(name)
    return [cmd] if found
  end

  # Find by approximation
  @commands.select do |cmd|
    cmd.name[0, name.length] == name
  end
end

#define_command(name = nil, &block) ⇒ Cri::Command

Defines a new subcommand for the current command using the DSL.

Parameters:

  • name (String, nil) (defaults to: nil)

    The name of the subcommand, or nil if no name should be set (yet)

Returns:



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/cri/command.rb', line 188

def define_command(name = nil, &block)
  # Execute DSL
  dsl = Cri::CommandDSL.new
  dsl.name name unless name.nil?
  if [-1, 0].include? block.arity
    dsl.instance_eval(&block)
  else
    yield(dsl)
  end

  # Create command
  cmd = dsl.command
  add_command(cmd)
  cmd
end

#global_option_definitionsHash

Returns The option definitions for the command itself and all its ancestors

Returns:

  • (Hash)

    The option definitions for the command itself and all its ancestors



165
166
167
168
169
170
# File 'lib/cri/command.rb', line 165

def global_option_definitions
  res = Set.new
  res.merge(option_definitions)
  res.merge(supercommand.global_option_definitions) if supercommand
  res
end

#help(params = {}) ⇒ String

Returns The help text for this command

Parameters:

  • params (Hash) (defaults to: {})

    a customizable set of options

Options Hash (params):

  • :verbose (Boolean)

    true if the help output should be verbose, false otherwise.

  • :io (IO) — default: $stdout

    the IO the help text is intended for. This influences the decision to enable/disable colored output.

Returns:

  • (String)

    The help text for this command



329
330
331
# File 'lib/cri/command.rb', line 329

def help(params = {})
  HelpRenderer.new(self, params).render
end

#modify(&block) ⇒ Cri::Command

Modifies the command using the DSL.

If the block has one parameter, the block will be executed in the same context with the command DSL as its parameter. If the block has no parameters, the block will be executed in the context of the DSL.

Returns:



153
154
155
156
157
158
159
160
161
# File 'lib/cri/command.rb', line 153

def modify(&block)
  dsl = Cri::CommandDSL.new(self)
  if [-1, 0].include? block.arity
    dsl.instance_eval(&block)
  else
    yield(dsl)
  end
  self
end

#run(opts_and_args, parent_opts = {}, hard_exit: true) ⇒ void

This method returns an undefined value.

Runs the command with the given command-line arguments, possibly invoking subcommands and passing on the options and arguments.

Parameters:

  • opts_and_args (Array<String>)

    A list of unparsed arguments

  • parent_opts (Hash) (defaults to: {})

    A hash of options already handled by the supercommand



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/cri/command.rb', line 258

def run(opts_and_args, parent_opts = {}, hard_exit: true)
  # Parse up to command name
  stuff = partition(opts_and_args)
  opts_before_subcmd, subcmd_name, opts_and_args_after_subcmd = *stuff

  if subcommands.empty? || (subcmd_name.nil? && !block.nil?)
    run_this(opts_and_args, parent_opts)
  else
    # Handle options
    handle_options(opts_before_subcmd)

    # Get command
    if subcmd_name.nil?
      if default_subcommand_name
        subcmd_name = default_subcommand_name
      else
        $stderr.puts "#{name}: no command given"
        raise CriExitException.new(is_error: true)
      end
    end
    subcommand = command_named(subcmd_name, hard_exit: hard_exit)
    return if subcommand.nil?

    # Run
    subcommand.run(opts_and_args_after_subcmd, opts_before_subcmd, hard_exit: hard_exit)
  end
rescue CriExitException => e
  exit(e.error? ? 1 : 0) if hard_exit
end

#run_this(opts_and_args, parent_opts = {}) ⇒ void

This method returns an undefined value.

Runs the actual command with the given command-line arguments, not invoking any subcommands. If the command does not have an execution block, an error ir raised.

Parameters:

  • opts_and_args (Array<String>)

    A list of unparsed arguments

  • parent_opts (Hash) (defaults to: {})

    A hash of options already handled by the supercommand

Raises:



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/cri/command.rb', line 301

def run_this(opts_and_args, parent_opts = {})
  # Parse
  parser = Cri::OptionParser.new(
    opts_and_args, global_option_definitions
  )
  handle_parser_errors_while { parser.run }
  local_opts  = parser.options
  global_opts = parent_opts.merge(parser.options)
  args = parser.arguments

  # Handle options
  handle_options(local_opts)

  # Execute
  if block.nil?
    raise NotImplementedError,
          "No implementation available for '#{name}'"
  end
  block.call(global_opts, args, self)
end