Class: Toys::ArgParser

Inherits:
Object
  • Object
show all
Defined in:
lib/toys/arg_parser.rb

Overview

An internal class that parses command line arguments for a tool.

Generally, you should not need to use this class directly. It is called from CLI.

Defined Under Namespace

Classes: ArgMissingError, ArgValueUnacceptableError, ExtraArgumentsError, FlagAmbiguousError, FlagGroupConstraintError, FlagUnrecognizedError, FlagValueMissingError, FlagValueNotAllowedError, FlagValueUnacceptableError, ToolUnrecognizedError, UsageError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tool, loader, common_data: {}, require_exact_flag_match: false) ⇒ ArgParser

Create an argument parser for a particular tool.

Parameters:

  • tool (Toys::ToolDefinition)

    The tool defining the argument format.

  • loader (Toys::Loader)

    The loader, used to generate suggestions for unrecognized arguments.

  • common_data (Hash) (defaults to: {})

    Additional initial data (such as verbosity).

  • require_exact_flag_match (boolean) (defaults to: false)

    Whether to require flag matches be exact (not partial). Default is false.



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/toys/arg_parser.rb', line 298

def initialize(tool, loader, common_data: {}, require_exact_flag_match: false)
  @tool = tool
  @loader = loader
  @require_exact_flag_match = require_exact_flag_match

  @parsed_args = []
  @unmatched_args = []
  @unmatched_flags = []
  @unmatched_positional = []
  @errors = []
  @data = {
    # These entries alias the arrays above, so that the data always reflects
    # the current state of parsing. Those arrays must therefore be mutated in
    # place for the life of this object, and never reassigned.
    Context::Key::ARGS => @parsed_args,
    Context::Key::UNMATCHED_ARGS => @unmatched_args,
    Context::Key::UNMATCHED_FLAGS => @unmatched_flags,
    Context::Key::UNMATCHED_POSITIONAL => @unmatched_positional,
    Context::Key::USAGE_ERRORS => @errors,
  }
  # Injected common data and the tool's non-nil default data can override the above.
  @data.merge!(common_data)
  @tool.default_data.each { |k, v| @data[k] = v.clone unless v.nil? && @data.key?(k) }

  @seen_flags = []
  @active_flag_def = nil
  @active_flag_arg = nil
  @arg_defs = tool.positional_args
  @arg_def_index = 0
  @flags_allowed = true
  @finished = false
end

Instance Attribute Details

#active_flag_defToys::Flag? (readonly)

The current flag definition whose value is still pending

Returns:

  • (Toys::Flag)

    The pending flag definition

  • (nil)

    if there is no pending flag



379
380
381
# File 'lib/toys/arg_parser.rb', line 379

def active_flag_def
  @active_flag_def
end

#dataHash (readonly)

The collected tool data from parsed arguments.

Returns:

  • (Hash)


365
366
367
# File 'lib/toys/arg_parser.rb', line 365

def data
  @data
end

#errorsArray<Toys::ArgParser::UsageError> (readonly)

An array of parse error messages.

Returns:



371
372
373
# File 'lib/toys/arg_parser.rb', line 371

def errors
  @errors
end

#parsed_argsArray<String> (readonly)

All command line arguments that have been parsed.

Returns:

  • (Array<String>)


341
342
343
# File 'lib/toys/arg_parser.rb', line 341

def parsed_args
  @parsed_args
end

#toolToys::ToolDefinition (readonly)

The tool definition governing this parser.



335
336
337
# File 'lib/toys/arg_parser.rb', line 335

def tool
  @tool
end

#unmatched_argsArray<String> (readonly)

All args that were not matched.

Returns:

  • (Array<String>)


359
360
361
# File 'lib/toys/arg_parser.rb', line 359

def unmatched_args
  @unmatched_args
end

#unmatched_flagsArray<String> (readonly)

Flags that were not matched.

Returns:

  • (Array<String>)


353
354
355
# File 'lib/toys/arg_parser.rb', line 353

def unmatched_flags
  @unmatched_flags
end

#unmatched_positionalArray<String> (readonly)

Extra positional args that were not matched.

Returns:

  • (Array<String>)


347
348
349
# File 'lib/toys/arg_parser.rb', line 347

def unmatched_positional
  @unmatched_positional
end

Instance Method Details

#finishself

Complete parsing. This should be called after all arguments have been processed. It does a final check for any errors, including:

  • The arguments ended with a flag that was expecting a value but wasn't provided.
  • One or more required arguments were never given a value.
  • One or more extra arguments were provided.
  • Restrictions defined in one or more flag groups were not fulfilled.

Any errors are added to the errors array, and are thus reflected in #data under Context::Key::USAGE_ERRORS.

After this method is called, this object is locked down, and no additional arguments may be parsed.

Returns:

  • (self)


442
443
444
445
446
447
448
# File 'lib/toys/arg_parser.rb', line 442

def finish
  finish_active_flag
  finish_arg_defs
  finish_flag_groups
  @finished = true
  self
end

#finished?boolean

Determine if this parser is finished

Returns:

  • (boolean)


393
394
395
# File 'lib/toys/arg_parser.rb', line 393

def finished?
  @finished
end

#flags_allowed?boolean

Whether flags are currently allowed. Returns false after -- is received.

Returns:

  • (boolean)


385
386
387
# File 'lib/toys/arg_parser.rb', line 385

def flags_allowed?
  @flags_allowed
end

#next_arg_defToys::PositionalArg?

The argument definition that will be applied to the next argument.

Returns:

  • (Toys::PositionalArg)

    The next argument definition.

  • (nil)

    if all arguments have been filled.



403
404
405
# File 'lib/toys/arg_parser.rb', line 403

def next_arg_def
  @arg_defs[@arg_def_index]
end

#parse(args) ⇒ self

Incrementally parse a single string or an array of strings

Parameters:

  • args (String, Array<String>)

Returns:

  • (self)


413
414
415
416
417
418
419
420
421
422
# File 'lib/toys/arg_parser.rb', line 413

def parse(args)
  raise "Parser has finished" if @finished
  Array(args).each do |arg|
    @parsed_args << arg
    unless @tool.argument_parsing_disabled?
      check_flag_value(arg) || check_flag(arg) || handle_positional(arg)
    end
  end
  self
end