Class: CmdParse::CommandParser
- Inherits:
-
Object
- Object
- CmdParse::CommandParser
- Defined in:
- lib/cmdparse.rb
Overview
Main Class for Creating a Command Based CLI Program
This class can directly be used (or sub-classed, if need be) to create a command based CLI program.
The CLI program itself is represented by the #main_command, a Command instance (as are all commands and sub-commands). This main command can either hold sub-commands (the normal use case) which represent the programs top level commands or take no commands in which case it acts similar to a simple OptionParser based program (albeit with better help functionality).
Parsing the command line for commands is done by this class, option parsing is delegated to the battle tested OptionParser of the Ruby standard library.
Usage
After initialization some optional information is expected to be set on the Command#options of the #main_command:
- banner
-
A banner that appears in the help output before anything else.
- program_name
-
The name of the program. If not set, this value is computed from $0.
- version
-
The version string of the program.
In addition to the main command’s options instance (which represents the top level options that need to be specified before any command name), there is also a #global_options instance which represents options that can be specified anywhere on the command line.
Top level commands can be added to the main command by using the #add_command method.
Once everything is set up, the #parse method is used for parsing the command line.
Instance Attribute Summary collapse
-
#current_command ⇒ Object
readonly
The command that is being executed.
-
#data ⇒ Object
A data store (initially an empty Hash) that can be used for storing anything.
-
#handle_exceptions ⇒ Object
readonly
Should exceptions be handled gracefully? I.e.
-
#help_desc_indent ⇒ Object
The indentation used for, among other things, command descriptions.
-
#help_indent ⇒ Object
The amount of spaces to indent the content of help sections.
-
#help_line_width ⇒ Object
The maximum width of the help lines.
-
#main_command ⇒ Object
readonly
The top level command representing the program itself.
Instance Method Summary collapse
-
#add_command(*args, **kws, &block) ⇒ Object
Adds a top level command.
-
#global_options {|@global_options| ... } ⇒ Object
:call-seq: cmdparse.global_options -> OptionParser instance cmdparse.gloabl_options {|opts| …} -> opts (OptionParser instance).
-
#initialize(handle_exceptions: false, takes_commands: true) ⇒ CommandParser
constructor
Creates a new CommandParser object.
-
#main_options {|@main_command.options| ... } ⇒ Object
:call-seq: cmdparse.main_options -> OptionParser instance cmdparse.main_options {|opts| …} -> opts (OptionParser instance).
-
#parse(argv = ARGV) ⇒ Object
Parses the command line arguments.
Constructor Details
#initialize(handle_exceptions: false, takes_commands: true) ⇒ CommandParser
Creates a new CommandParser object.
Options:
- handle_exceptions
-
Set to
true
if exceptions should be handled gracefully by showing the error and a help message, or tofalse
if exception should not be handled at all. If this options is set to :no_help, the exception is handled but no help message is shown. - takes_commands
-
Specifies whether the main program takes any commands.
807 808 809 810 811 812 813 814 815 816 817 |
# File 'lib/cmdparse.rb', line 807 def initialize(handle_exceptions: false, takes_commands: true) @global_options = OptionParser.new @main_command = Command.new('main', takes_commands: takes_commands) @main_command.super_command = self @main_command..stack[0] = MultiList.new(@global_options.stack) @handle_exceptions = handle_exceptions @help_line_width = 80 @help_indent = 4 @help_desc_indent = 18 @data = {} end |
Instance Attribute Details
#current_command ⇒ Object (readonly)
The command that is being executed. Only available during parsing of the command line arguments.
777 778 779 |
# File 'lib/cmdparse.rb', line 777 def current_command @current_command end |
#data ⇒ Object
A data store (initially an empty Hash) that can be used for storing anything. For example, it can be used to store global option values. cmdparse itself doesn’t do anything with it.
781 782 783 |
# File 'lib/cmdparse.rb', line 781 def data @data end |
#handle_exceptions ⇒ Object (readonly)
Should exceptions be handled gracefully? I.e. by printing error message and the help screen?
See ::new for possible values.
786 787 788 |
# File 'lib/cmdparse.rb', line 786 def handle_exceptions @handle_exceptions end |
#help_desc_indent ⇒ Object
The indentation used for, among other things, command descriptions.
795 796 797 |
# File 'lib/cmdparse.rb', line 795 def help_desc_indent @help_desc_indent end |
#help_indent ⇒ Object
The amount of spaces to indent the content of help sections.
792 793 794 |
# File 'lib/cmdparse.rb', line 792 def help_indent @help_indent end |
#help_line_width ⇒ Object
The maximum width of the help lines.
789 790 791 |
# File 'lib/cmdparse.rb', line 789 def help_line_width @help_line_width end |
#main_command ⇒ Object (readonly)
The top level command representing the program itself.
773 774 775 |
# File 'lib/cmdparse.rb', line 773 def main_command @main_command end |
Instance Method Details
#add_command(*args, **kws, &block) ⇒ Object
Adds a top level command.
See Command#add_command for detailed invocation information.
848 849 850 |
# File 'lib/cmdparse.rb', line 848 def add_command(*args, **kws, &block) @main_command.add_command(*args, **kws, &block) end |
#global_options {|@global_options| ... } ⇒ Object
:call-seq:
cmdparse.global_options -> OptionParser instance
cmdparse.gloabl_options {|opts| ...} -> opts (OptionParser instance)
Yields the global options if a block is given and returns them.
The global options are those options that can be used on the top level and with any command.
840 841 842 843 |
# File 'lib/cmdparse.rb', line 840 def yield(@global_options) if block_given? @global_options end |
#main_options {|@main_command.options| ... } ⇒ Object
:call-seq:
cmdparse.main_options -> OptionParser instance
cmdparse.main_options {|opts| ...} -> opts (OptionParser instance)
Yields the main options (that are only available directly after the program name) if a block is given and returns them.
The main options are also used for setting the program name, version and banner.
827 828 829 830 |
# File 'lib/cmdparse.rb', line 827 def yield(@main_command.) if block_given? @main_command. end |
#parse(argv = ARGV) ⇒ Object
Parses the command line arguments.
If a block is given, the current hierarchy level and the name of the current command is yielded after the option parsing is done but before a command is executed.
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 |
# File 'lib/cmdparse.rb', line 856 def parse(argv = ARGV) # :yields: level, command_name level = 0 @current_command = @main_command while true argv = if @current_command.takes_commands? || ENV.include?('POSIXLY_CORRECT') @current_command..order(argv) else @current_command..permute(argv) end yield(level, @current_command.name) if block_given? if @current_command.takes_commands? cmd_name = argv.shift || @current_command.default_command if cmd_name.nil? raise NoCommandGivenError.new elsif !@current_command.commands.key?(cmd_name) raise InvalidCommandError.new(cmd_name) end @current_command = @current_command.commands[cmd_name] level += 1 else original_n = @current_command.arity n = (original_n < 0 ? -original_n - 1 : original_n) if argv.size < n raise NotEnoughArgumentsError.new("#{n} - #{@current_command.usage_arguments}") elsif argv.size > n && original_n > 0 raise TooManyArgumentsError.new("#{n} - #{@current_command.usage_arguments}") end argv.slice!(n..-1) unless original_n < 0 @current_command.execute(*argv) break end end rescue ParseError, OptionParser::ParseError => e raise unless @handle_exceptions puts "Error while parsing command line:\n " + e. if @handle_exceptions != :no_help && @main_command.commands.key?('help') puts @main_command.commands['help'].execute(*@current_command.command_chain.map(&:name)) end exit(64) # FreeBSD standard exit error for "command was used incorrectly" rescue Interrupt exit(128 + 2) rescue Errno::EPIPE # Behave well when used in a pipe ensure @current_command = nil end |