boop

Object-oriented programming for bash 4.3+ — real classes, objects, inheritance, and a standard library, in pure bash.


Project maintained by ydbxmhc Hosted on GitHub Pages

Argument Parsing — Design Summary

Two Tools, One Engine

ArgParser — boop class

Standard boop object. Proper into= returns, query via $args.get. Used in constructors and methods. Never touches the caller’s scope directly.

into=args ArgParser '
  o|option:$option
  r|required:$_required
  a|array:@array
' "$@"
$args.get option
$args.get required

CLI::Args — sourceable script convenience

The “naughty” version. Sources directly into the calling script’s scope, declares variables, rewrites "$@". Designed for script authors, not library authors.

. CLI::Args '
  o|option:$option
  r|required:$_required
  a|array:@array
' '
  use: ${0##*/} {-r someVal} [-o value] [-a item]...

  Detailed usage instructions here.
' "$@"

Both tools share the same parsing engine. CLI::Args sources boop internally if not already loaded — works standalone, uses existing framework if present.


The CLI:: Namespace

A “batteries included” layer for script writers. Opinionated, convenient, always prints to stdout, may call exit on bad input — things a well-behaved library would never do unilaterally.

boop/
  boop              — framework
  ArgParser         — proper boop class
  Math              — arbitrary precision class
  ...
  CLI/
    CLI::Args       — declares vars, rewrites $@, generates --help
    CLI::Math       — always printfs, wraps Math.DO
    CLI::Table      — formatted tables from arrays/maps (future)
    ...

CLI:: tools are bonuses for installing boop, not framework primitives.


Declaration Syntax

synonyms:$varName
  • Synonyms are |-delimited
  • Single character → short option (-o)
  • Multiple characters → long option (--option)
  • Multiple synonyms are all equivalent: o|O|option|OPTION:$name
  • No :$varName → use first synonym as variable name

Type Sigils

Sigil Type Behavior
$name scalar Flag (bool) if no value given; string if value given; error if repeated
$_name required scalar Same, but missing at end of parse → error + help
@name array Stacks every occurrence
@_name required array Same, but at least one occurrence required
%name map Each occurrence is bool key or k=v; error on repeated keys
%_name required map Same, but at least one entry required

File Loading — The < Prefix

< before the sigil means the argument value is a filename to load from.

Declaration Delimiter CLI usage Behavior
<$name n/a -x file Slurp entire file into scalar
<@name n/a -x file Load rows into array (newline-split)
<%name = (default) -x file Load rows into map, split on =
<%name: : -x file Load rows into map, split on :
<%name:foo : (none) Always load from foo, split on :
<%name=foo = (none) Always load from foo, split on =

Delimiter rule: any non-identifier character after the sigil+name is the delimiter. If followed by a non-empty string, that string is a hardcoded filename and no CLI argument is accepted for this option.

Required + file (<$_name): the CLI argument must be given, the file must exist, and must be non-empty.

Lazy loading: TBD — possible sigil <+ for deferred/optional file loads.


Map Runtime Assignment

At runtime (non-file), maps accept k=v pairs:

-m a=1      # loads value 1 into key a of map
-m a        # loads boolean true into key a of map

The delimiter in the declaration applies to file loading only; runtime assignment always uses = unless overridden. Repeated keys are an error.


Positional Arguments

Undeclared arguments are not errors — they are collected as positionals.

  • __args_original — the untouched original "$@" as received
  • "$@" is rewritten after parsing to contain only unconsumed (positional) arguments

No special declaration needed for positionals — they’re whatever’s left after all declared options are consumed.


Help Screen

If a usage string is provided as the second argument, it is used verbatim for --help output. If not provided, a usage screen is auto-generated from the declarations.

If both are provided and they disagree (e.g., a required arg appears optional in the usage string), the whole thing bails at startup — the declaration is always authoritative.

CLI::Args handles --help / -h automatically, printing the help screen and calling exit 0.


Example

. CLI::Args '
  v|verbose:$verbose
  o|output:$_output
  f|file:<@_files
  t|tag:%tags
  n|dry-run:$dryRun
' '
  use: ${0##*/} {-o outfile} {-f file}... [-v] [-t k=v]... [-n] [args...]

  -o, --output    Output file (required)
  -f, --file      Input files (required, may repeat)
  -v, --verbose   Enable verbose output
  -t, --tag       Key=value tags (may repeat)
  -n, --dry-run   Dry run, no changes made
' "$@"

# After sourcing:
# $verbose    — "1" or "" (flag)
# $output     — required string value
# ${files[@]} — array of input files (loaded from paths given)
# ${tags[k]}  — associative array of tags
# $dryRun     — "1" or ""
# $@          — remaining positional arguments
# $__args_original — original unmodified argument list

Status

Design phase. @@ Not yet implemented. Prerequisite: ArgParser boop class design finalized first. CLI::Args shares the same parsing engine — implement engine once, wrap differently for each consumer.


↑ Site map