class CTioga2::Commands::Parsers::CommandLineParser
This class is in charge of parsing a command-line against a list of known commands.
Attributes
The list of commands
A [number of args, Command] for the default command, ie the one that applies on non-command files.
A hash 'long-option-name' => [number of args, Command]
A hash 'short-option-letter' => [number of args, Command]
Public Class Methods
Creates a CommandLineParser
that will understand the given commands
# File lib/ctioga2/commands/parsers/command-line.rb, line 57 def initialize(commands, default = nil) @commands = commands prepare_option_hashes(default) end
Public Instance Methods
Takes an argv array representing the command-line and a target intepreter, and runs the commands found on the command line. Yields arguments which are not part of a command, or feed them to the default_command
if it was specified.
# File lib/ctioga2/commands/parsers/command-line.rb, line 68 def parse_command_line(argv, interpreter) # We duplicate the original array argv = argv.dup options = nil # currently never used. number = 0 while argv.size > 0 current = argv.shift if current =~ /^--(.*)/ # a long option if @long_options.key?($1) command, arguments, options = extract_command_arguments(argv, @long_options[$1]) number += 1 interpreter.context.parsing_option(current, number) interpreter.run_command(command, arguments, options) else raise OptionUnkown, "Long option #{current} is not known" end elsif current =~ /^-(.*)/ # Short options # We do the same as above, but splitting into letters first: short_options = $1.split('') for short in short_options if @short_options.key?(short) command, arguments, options = extract_command_arguments(argv, @short_options[short]) number += 1 interpreter.context.parsing_option("-#{short}", number) interpreter.run_command(command, arguments, options) else raise OptionUnkown, "Short option -#{short} is not known" end end else if @default_command argv.unshift current command, arguments, options = extract_command_arguments(argv, @default_command) number += 1 interpreter.context.parsing_option("(default)", number) interpreter.run_command(command, arguments, options) else yield current end end end end
Protected Instance Methods
Extract command, arguments and potential options from the given argv array. The second argument is what is stored in the short_options
and long_options
hashes.
Returns an array
[command, arguments, options]
# File lib/ctioga2/commands/parsers/command-line.rb, line 160 def extract_command_arguments(argv, cmd_val) number, command = cmd_val options = {} # Special case for boolean arguments if number < 0 arguments = [number == -1] else arguments = argv.slice!(0,number) end # We try and go fishing for options, in the form # /option=stuff, or /option stuff... while argv.first =~ /^\/([\w-]+)(?:=(.*))?$/ if command.has_option? $1 argv.shift if $2 options[$1] = $2 else options[$1] = argv.shift end else warn { "Argument #{argv.first} looks like an option, but does not match any of the command #{command.name}" } break end end return [command, arguments, options] end
Prepares the short_options
and long_options
hashes for use in parse_command_line
# File lib/ctioga2/commands/parsers/command-line.rb, line 119 def prepare_option_hashes(default = nil) @short_options = {} @long_options = {} for cmd in @commands short = cmd.short_option boolean = (cmd.argument_number == 1 && cmd.arguments.first.type.boolean?) if short if @short_options.key? short raise OptionRedefined, "Short option #{short} was already defined as command #{cmd.name}" end if boolean @short_options[short] = [-1, cmd] else @short_options[short] = [cmd.argument_number, cmd] end end long = cmd.long_option if long if @long_options.key? short raise OptionRedefined, "Long option #{long} was already defined as command #{cmd.name}" end if boolean @long_options[long] = [-1, cmd] @long_options["no-#{long}"] = [-2, cmd] else @long_options[long] = [cmd.argument_number, cmd] end end end if default @default_command = [default.argument_number, default] end end