JustBash.Commands.ArgParser (JustBash v0.4.0)

View Source

Declarative command-line argument parser for shell commands.

Provides a simple DSL for defining command flags and their behaviors, eliminating repetitive manual parsing code.

Usage

@flags [
  silent: [short: "-s", long: "--silent", type: :boolean],
  output: [short: "-o", long: "--output", type: :string],
  count: [short: "-n", type: :integer, default: 1],
  method: [short: "-X", long: "--request", type: :string, default: "GET"]
]

case ArgParser.parse(args, @flags) do
  {:ok, opts, positional} ->
    # opts is a map like %{silent: true, output: "file.txt", count: 1}
    # positional is remaining non-flag arguments
  {:error, message} ->
    # e.g., "unknown option: --foo"
end

Flag Types

  • :boolean - Flag is present or absent (no value needed)
  • :string - Takes a string value
  • :integer - Takes an integer value
  • :float - Takes a floating-point value
  • :accumulator - Accumulates multiple values into a list (for -H headers, etc.)

Options

  • :short - Short flag form (e.g., "-s")
  • :long - Long flag form (e.g., "--silent")
  • :aliases - Additional long forms accepted for the same flag (e.g., ["--quiet"]). :long stays the canonical spelling used in help and error messages
  • :type - Value type (:boolean, :string, :integer, :float, :accumulator)
  • :default - Default value if flag not provided
  • :required - When true, parsing fails if the flag is not provided
  • :values - List of allowed values; parsing fails on anything else (enum)
  • :transform - Optional function to transform the (coerced) value. It may return a bare value, {:ok, value}, or {:error, message}; the error channel fails parsing with that message, giving single-field validation (e.g. a numeric range) the same failure shape as a type or enum error.

Summary

Functions

Parse command-line arguments according to the flag specification.

Types

flag_spec()

@type flag_spec() :: [
  short: String.t(),
  long: String.t(),
  aliases: [String.t()],
  type: flag_type(),
  default: any(),
  required: boolean(),
  values: [any()],
  transform: transform()
]

flag_type()

@type flag_type() :: :boolean | :string | :integer | :float | :accumulator

flags_spec()

@type flags_spec() :: [{atom(), flag_spec()}]

transform()

@type transform() :: (term() -> term() | {:ok, term()} | {:error, String.t()})

Functions

parse(args, flags, opts \\ [])

@spec parse([String.t()], flags_spec(), keyword()) ::
  {:ok, map(), [String.t()]}
  | {:ok, map(), [String.t()], [String.t()]}
  | {:error, String.t()}

Parse command-line arguments according to the flag specification.

Returns {:ok, opts_map, positional_args} or {:error, message}.

Options

  • :command — name included in error messages (e.g. "acme pr review")
  • :allow_unknown — when true, an unrecognized flag is treated as a positional argument instead of an error
  • :collect_unknown — when true, unrecognized flags (and, for the bare --flag value form, a following non-flag token taken as the flag's value) are collected into a separate ordered list and the call returns a 4-tuple {:ok, opts, positional, extra}. Positionals stay out of extra, so a host can forward the raw extra tokens to a backend whose flags aren't known at definition time. --flag=value is forwarded as a single token.
  • :on_unknown_flag — a (flag_name :: String.t() -> String.t() | nil) called with the bare flag (no =value) when it would otherwise be a hard error. A non-nil return is appended to the "unknown option" message, e.g. to point at a sibling command that declares the same flag. Never called in :allow_unknown/:collect_unknown mode, since there the flag isn't an error at all.