class Cri::Parser

Cri::Parser is used for parsing command-line options and arguments.

Attributes

delegate[RW]

The delegate to which events will be sent. The following methods will be send to the delegate:

  • `option_added(key, value, cmd)`

  • `argument_added(argument, cmd)`

@return [#option_added, argument_added] The delegate

options[R]

The options that have already been parsed.

If the parser was stopped before it finished, this will not contain all options and `unprocessed_arguments_and_options` will contain what is left to be processed.

@return [Hash] The already parsed options.

unprocessed_arguments_and_options[R]

The options and arguments that have not yet been processed. If the parser wasn’t stopped (using {#stop}), this list will be empty.

@return [Array] The not yet parsed options and arguments.

Public Class Methods

new(arguments_and_options, option_defns, param_defns, explicitly_no_params) click to toggle source

Creates a new parser with the given options/arguments and definitions.

@param [Array<String>] arguments_and_options An array containing the

command-line arguments (will probably be `ARGS` for a root command)

@param [Array<Cri::OptionDefinition>] option_defns An array of option

definitions

@param [Array<Cri::ParamDefinition>] param_defns An array of parameter

definitions
# File lib/cri/parser.rb, line 65
def initialize(arguments_and_options, option_defns, param_defns, explicitly_no_params)
  @unprocessed_arguments_and_options = arguments_and_options.dup
  @option_defns = option_defns
  @param_defns = param_defns
  @explicitly_no_params = explicitly_no_params

  @options       = {}
  @raw_arguments = []

  @running = false
  @no_more_options = false
end

Public Instance Methods

gen_argument_list() click to toggle source

@return [Cri::ArgumentList] The list of arguments that have already been

parsed, excluding the -- separator.
# File lib/cri/parser.rb, line 128
def gen_argument_list
  ArgumentList.new(@raw_arguments, @explicitly_no_params, @param_defns)
end
run() click to toggle source

Parses the command-line arguments into options and arguments.

During parsing, two errors can be raised:

@raise IllegalOptionError if an unrecognised option was encountered,

i.e. an option that is not present in the list of option definitions

@raise OptionRequiresAnArgumentError if an option was found that did not

have a value, even though this value was required.

@return [Cri::Parser] The option parser self

# File lib/cri/parser.rb, line 102
def run
  @running = true

  while running?
    # Get next item
    e = @unprocessed_arguments_and_options.shift
    break if e.nil?

    if e == '--'
      handle_dashdash(e)
    elsif e =~ /^--./ && !@no_more_options
      handle_dashdash_option(e)
    elsif e =~ /^-./ && !@no_more_options
      handle_dash_option(e)
    else
      add_argument(e)
    end
  end

  self
ensure
  @running = false
end
running?() click to toggle source

@return [Boolean] true if the parser is running, false otherwise.

# File lib/cri/parser.rb, line 79
def running?
  @running
end
stop() click to toggle source

Stops the parser. The parser will finish its current parse cycle but will not start parsing new options and/or arguments.

@return [void]

# File lib/cri/parser.rb, line 87
def stop
  @running = false
end

Private Instance Methods

add_argument(value) click to toggle source
# File lib/cri/parser.rb, line 238
def add_argument(value)
  @raw_arguments << value

  unless value == '--'
    delegate&.argument_added(value, self)
  end
end
add_option(option_defn, value, transform: true) click to toggle source
# File lib/cri/parser.rb, line 205
def add_option(option_defn, value, transform: true)
  key = key_for(option_defn)

  value = transform ? transform_value(option_defn, value) : value

  if option_defn.multiple
    options[key] ||= []
    options[key] << value
  else
    options[key] = value
  end

  delegate&.option_added(key, value, self)
end
find_option_value(option_defn, option_key) click to toggle source
# File lib/cri/parser.rb, line 190
def find_option_value(option_defn, option_key)
  option_value = @unprocessed_arguments_and_options.shift
  if option_value.nil? || option_value =~ /^-/
    if option_defn.argument == :optional && option_defn.default
      option_value = option_defn.default
    elsif option_defn.argument == :required
      raise OptionRequiresAnArgumentError.new(option_key)
    else
      @unprocessed_arguments_and_options.unshift(option_value)
      option_value = true
    end
  end
  option_value
end
handle_dash_option(elem) click to toggle source
# File lib/cri/parser.rb, line 167
def handle_dash_option(elem)
  # Get option keys
  option_keys = elem[1..-1].scan(/./)

  # For each key
  option_keys.each do |option_key|
    # Find definition
    option_defn = @option_defns.find { |d| d.short == option_key }
    raise IllegalOptionError.new(option_key) if option_defn.nil?

    if %i[required optional].include?(option_defn.argument)
      # Get option value
      option_value = find_option_value(option_defn, option_key)

      # Store option
      add_option(option_defn, option_value)
    else
      # Store option
      add_option(option_defn, true)
    end
  end
end
handle_dashdash(elem) click to toggle source
# File lib/cri/parser.rb, line 134
def handle_dashdash(elem)
  add_argument(elem)
  @no_more_options = true
end
handle_dashdash_option(elem) click to toggle source
# File lib/cri/parser.rb, line 139
def handle_dashdash_option(elem)
  # Get option key, and option value if included
  if elem =~ /^--([^=]+)=(.+)$/
    option_key   = Regexp.last_match[1]
    option_value = Regexp.last_match[2]
  else
    option_key    = elem[2..-1]
    option_value  = nil
  end

  # Find definition
  option_defn = @option_defns.find { |d| d.long == option_key }
  raise IllegalOptionError.new(option_key) if option_defn.nil?

  if %i[required optional].include?(option_defn.argument)
    # Get option value if necessary
    if option_value.nil?
      option_value = find_option_value(option_defn, option_key)
    end

    # Store option
    add_option(option_defn, option_value)
  else
    # Store option
    add_option(option_defn, true)
  end
end
key_for(option_defn) click to toggle source
# File lib/cri/parser.rb, line 234
def key_for(option_defn)
  (option_defn.long || option_defn.short).to_sym
end
transform_value(option_defn, value) click to toggle source
# File lib/cri/parser.rb, line 220
def transform_value(option_defn, value)
  transformer = option_defn.transform

  if transformer
    begin
      transformer.call(value)
    rescue StandardError
      raise IllegalOptionValueError.new(option_defn, value)
    end
  else
    value
  end
end