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, OptionParserPartitioningDelegate
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”).
-
#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<Hash>
The list of option 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.
-
.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 ⇒ Hash
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
144 145 146 147 148 149 |
# File 'lib/cri/command.rb', line 144 def initialize @aliases = Set.new @commands = Set.new @option_definitions = Set.new @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
71 72 73 |
# File 'lib/cri/command.rb', line 71 def aliases @aliases end |
#all_opts_as_args ⇒ Boolean Also known as: all_opts_as_args?
treat all options as arguments.
97 98 99 |
# File 'lib/cri/command.rb', line 97 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)
93 94 95 |
# File 'lib/cri/command.rb', line 93 def block @block end |
#commands ⇒ Set<Cri::Command> Also known as: subcommands
Returns This command’s subcommands
60 61 62 |
# File 'lib/cri/command.rb', line 60 def commands @commands end |
#default_subcommand_name ⇒ Symbol
Returns The name of the default subcommand
64 65 66 |
# File 'lib/cri/command.rb', line 64 def default_subcommand_name @default_subcommand_name end |
#description ⇒ String
Returns The long description (“description”)
77 78 79 |
# File 'lib/cri/command.rb', line 77 def description @description end |
#hidden ⇒ Boolean Also known as:
Returns 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 |
#option_definitions ⇒ Array<Hash>
Returns The list of option definitions
89 90 91 |
# File 'lib/cri/command.rb', line 89 def option_definitions @option_definitions end |
#summary ⇒ String
Returns The short description (“summary”)
74 75 76 |
# File 'lib/cri/command.rb', line 74 def summary @summary end |
#supercommand ⇒ Cri::Command?
Returns 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 |
#usage ⇒ String
Returns 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.
113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/cri/command.rb', line 113 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_help ⇒ Cri::Command
Returns a new command that implements showing help.
139 140 141 142 |
# File 'lib/cri/command.rb', line 139 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, …)
131 132 133 134 |
# File 'lib/cri/command.rb', line 131 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.
350 351 352 |
# File 'lib/cri/command.rb', line 350 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.
182 183 184 185 |
# File 'lib/cri/command.rb', line 182 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”).
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/cri/command.rb', line 237 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.
215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/cri/command.rb', line 215 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.
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/cri/command.rb', line 193 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 ⇒ Hash
Returns The option definitions for the command itself and all its ancestors
170 171 172 173 174 175 |
# File 'lib/cri/command.rb', line 170 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
339 340 341 |
# File 'lib/cri/command.rb', line 339 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.
158 159 160 161 162 163 164 165 166 |
# File 'lib/cri/command.rb', line 158 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.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/cri/command.rb', line 263 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, 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.
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/cri/command.rb', line 306 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::OptionParser.new( opts_and_args, global_option_definitions ) handle_parser_errors_while { parser.run } local_opts = parser. global_opts = parent_opts.merge(parser.) args = parser.arguments # Handle options (local_opts) end # Execute if block.nil? raise NotImplementedError, "No implementation available for '#{name}'" end block.call(global_opts, args, self) end |