Class: Cri::Command
- Inherits:
-
Object
- Object
- Cri::Command
- 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, ParserPartitioningDelegate
Instance Attribute Summary collapse
-
#aliases ⇒ Array<String>
A list of aliases for this command that can be used to invoke this command.
-
#all_opts_as_args ⇒ Boolean
(also: #all_opts_as_args?)
treat all options as arguments.
-
#block ⇒ Proc
The block that should be executed when invoking this command (ignored for commands with subcommands).
-
#commands ⇒ Set<Cri::Command>
(also: #subcommands)
This command’s subcommands.
-
#default_subcommand_name ⇒ Symbol
The name of the default subcommand.
-
#description ⇒ String
The long description (“description”).
-
#explicitly_no_params ⇒ Boolean
(also: #explicitly_no_params?)
Whether or not this command has parameters.
-
#hidden ⇒ Boolean
(also: #hidden?)
True if the command is hidden (e.g. because it is deprecated), false otherwise.
-
#name ⇒ String
The name.
-
#option_definitions ⇒ Array<Cri::OptionDefinition>
The list of option definitions.
-
#parameter_definitions ⇒ Array<Hash>
The list of parameter definitions.
-
#summary ⇒ String
The short description (“summary”).
-
#supercommand ⇒ Cri::Command?
This command’s supercommand, or nil if the command has no supercommand.
-
#usage ⇒ String
The usage, without the “usage:” prefix and without the supercommands’ names.
Class Method Summary collapse
-
.define(string = nil, filename = nil, &block) ⇒ Cri::Command
Creates a new command using the DSL.
-
.load_file(filename, infer_name: false) ⇒ Cri::Command
Creates a new command using a DSL, from code defined in the given filename.
-
.new_basic_help ⇒ Cri::Command
Returns a new command that implements showing help.
-
.new_basic_root ⇒ Cri::Command
Returns a new command that has support for the
-h
/--help
option and also has ahelp
subcommand.
Instance Method Summary collapse
-
#<=>(other) ⇒ -1, ...
Compares this command's name to the other given command's name.
-
#add_command(command) ⇒ void
Adds the given command as a subcommand to the current command.
-
#command_named(name, hard_exit: true) ⇒ Cri::Command
Returns the command with the given name.
-
#commands_named(name) ⇒ Array<Cri::Command>
Returns the commands that could be referred to with the given name.
-
#define_command(name = nil, &block) ⇒ Cri::Command
Defines a new subcommand for the current command using the DSL.
-
#global_option_definitions ⇒ Enumerable<Cri::OptionDefinition>
The option definitions for the command itself and all its ancestors.
-
#help(params = {}) ⇒ String
The help text for this command.
-
#initialize ⇒ Command
constructor
A new instance of Command.
-
#modify(&block) ⇒ Cri::Command
Modifies the command using the DSL.
-
#run(opts_and_args, parent_opts = {}, hard_exit: true) ⇒ void
Runs the command with the given command-line arguments, possibly invoking subcommands and passing on the options and arguments.
-
#run_this(opts_and_args, parent_opts = {}) ⇒ void
Runs the actual command with the given command-line arguments, not invoking any subcommands.
Constructor Details
#initialize ⇒ Command
Returns a new instance of Command
169 170 171 172 173 174 175 176 |
# File 'lib/cri/command.rb', line 169 def initialize @aliases = Set.new @commands = Set.new @option_definitions = Set.new @parameter_definitions = [] @explicitly_no_params = false @default_subcommand_name = nil end |
Instance Attribute Details
#aliases ⇒ Array<String>
Returns A list of aliases for this command that can be used to invoke this command
73 74 75 |
# File 'lib/cri/command.rb', line 73 def aliases @aliases end |
#all_opts_as_args ⇒ Boolean Also known as: all_opts_as_args?
treat all options as arguments.
106 107 108 |
# File 'lib/cri/command.rb', line 106 def all_opts_as_args @all_opts_as_args end |
#block ⇒ Proc
Returns The block that should be executed when invoking this command (ignored for commands with subcommands)
102 103 104 |
# File 'lib/cri/command.rb', line 102 def block @block end |
#commands ⇒ Set<Cri::Command> Also known as: subcommands
Returns This command’s subcommands
62 63 64 |
# File 'lib/cri/command.rb', line 62 def commands @commands end |
#default_subcommand_name ⇒ Symbol
Returns The name of the default subcommand
66 67 68 |
# File 'lib/cri/command.rb', line 66 def default_subcommand_name @default_subcommand_name end |
#description ⇒ String
Returns The long description (“description”)
79 80 81 |
# File 'lib/cri/command.rb', line 79 def description @description end |
#explicitly_no_params ⇒ Boolean Also known as: explicitly_no_params?
Returns Whether or not this command has parameters
97 98 99 |
# File 'lib/cri/command.rb', line 97 def explicitly_no_params @explicitly_no_params end |
#hidden ⇒ Boolean Also known as:
Returns true if the command is hidden (e.g. because it is deprecated), false otherwise
87 88 89 |
# File 'lib/cri/command.rb', line 87 def hidden @hidden end |
#name ⇒ String
Returns The name
69 70 71 |
# File 'lib/cri/command.rb', line 69 def name @name end |
#option_definitions ⇒ Array<Cri::OptionDefinition>
Returns The list of option definitions
91 92 93 |
# File 'lib/cri/command.rb', line 91 def option_definitions @option_definitions end |
#parameter_definitions ⇒ Array<Hash>
Returns The list of parameter definitions
94 95 96 |
# File 'lib/cri/command.rb', line 94 def parameter_definitions @parameter_definitions end |
#summary ⇒ String
Returns The short description (“summary”)
76 77 78 |
# File 'lib/cri/command.rb', line 76 def summary @summary end |
#supercommand ⇒ Cri::Command?
Returns This command’s supercommand, or nil if the command has no supercommand
59 60 61 |
# File 'lib/cri/command.rb', line 59 def supercommand @supercommand end |
#usage ⇒ String
Returns The usage, without the “usage:” prefix and without the supercommands’ names.
83 84 85 |
# File 'lib/cri/command.rb', line 83 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.
122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/cri/command.rb', line 122 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 |
.load_file(filename, infer_name: false) ⇒ Cri::Command
Creates a new command using a DSL, from code defined in the given filename.
141 142 143 144 145 146 147 148 149 |
# File 'lib/cri/command.rb', line 141 def self.load_file(filename, infer_name: false) code = File.read(filename, encoding: 'UTF-8') define(code, filename).tap do |cmd| if infer_name command_name = File.basename(filename, '.rb') cmd.modify { name command_name } end end end |
.new_basic_help ⇒ Cri::Command
Returns a new command that implements showing help.
164 165 166 167 |
# File 'lib/cri/command.rb', line 164 def self.new_basic_help filename = File.dirname(__FILE__) + '/commands/basic_help.rb' define(File.read(filename)) end |
.new_basic_root ⇒ Cri::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, …)
156 157 158 159 |
# File 'lib/cri/command.rb', line 156 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.
380 381 382 |
# File 'lib/cri/command.rb', line 380 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.
209 210 211 212 |
# File 'lib/cri/command.rb', line 209 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”).
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/cri/command.rb', line 264 def command_named(name, hard_exit: true) commands = commands_named(name) if commands.empty? warn "#{self.name}: unknown command '#{name}'\n" raise CriExitException.new(is_error: true) elsif commands.size > 1 warn "#{self.name}: '#{name}' is ambiguous:" warn " #{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.
242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/cri/command.rb', line 242 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.
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/cri/command.rb', line 220 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_definitions ⇒ Enumerable<Cri::OptionDefinition>
Returns The option definitions for the command itself and all its ancestors
197 198 199 200 201 202 |
# File 'lib/cri/command.rb', line 197 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
369 370 371 |
# File 'lib/cri/command.rb', line 369 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.
185 186 187 188 189 190 191 192 193 |
# File 'lib/cri/command.rb', line 185 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.
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/cri/command.rb', line 290 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 (opts_before_subcmd) # Get command if subcmd_name.nil? if default_subcommand_name subcmd_name = default_subcommand_name else warn "#{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, parent_opts.merge(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.
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/cri/command.rb', line 333 def run_this(opts_and_args, parent_opts = {}) if all_opts_as_args? args = opts_and_args global_opts = parent_opts else # Parse parser = Cri::Parser.new( opts_and_args, global_option_definitions, parameter_definitions, explicitly_no_params?, ) handle_errors_while { parser.run } local_opts = parser. global_opts = parent_opts.merge(parser.) # Handle options (local_opts) args = handle_errors_while { parser.gen_argument_list } end # Execute if block.nil? raise NotImplementedError, "No implementation available for '#{name}'" end block.call(global_opts, args, self) end |