Yaap

by hartbit

hartbit / Yaap

Yet Another (Swift) Argument Parser

125 Stars 0 Forks Last release: Not found MIT License 50 Commits 1 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Yaap version 1.0.0 swift 5.1 license MIT

Yaap is Yet Another (Swift) Argument Parser that represents executable commands as types, and arguments as properties of those types. It supports:

  • Strongly-typed argument and option parsing
  • Automatic help and usage message generation
  • Multiple command routing
  • Smart error messages with suggestion on typos

Here's a self-contained example of a

rand
executable that generates random numbers in a configurable interval to standard output, with everything from
--help
documentation, usage generation, and
--version
printing.
class RandomCommand: Command {
    let name = "rand"
    let documentation = "Generates a random number that lies in an interval."

@Argument(documentation: "Exclusive maximum value")
var maximum: Int

@Option(shorthand: "m", documentation: "Inclusive minimum value")
var minimum: Int = 0

let help = Help()
let version = Version("0.1.0")

func run(outputStream: inout TextOutputStream, errorStream: inout TextOutputStream) throws {
    guard maximum > minimum else {
        throw InvalidIntervalError(minimum: minimum, maximum: maximum)
    }

    outputStream.write(Int.random(in: minimum..<maximum outputstream.write struct invalidintervalerror: localizederror let minimum: int maximum: var errordescription: string return interval randomcommand>

Installation

Yaap can be installed as a Swift Package Manager dependency. Here's the declaration for depending on the latest stable version:

let package = Package(
    dependencies: [
        .package(url: "https://github.com/hartbit/Yaap.git", from: "1.0.0")
    ]
)

Usage

Commands

In Yaap, a command is a self-contained operation defined as a class conforming to the

Command
protocol: arguments (if any) are defined as properties and execution logic is defined in a
run(outputStream:errorStream)
function. Simple programs only need one command but can grow more as necessary.

A command must also define a

name
(the executable name), that will appear in the usage description, and an optional
documentation
property, that will appear in the help output.
class HelloWorldCommand: Command {
    let name = "hello-world"
    let description = "My first command"

func run(outputStream: inout TextOutputStream, errorStream: inout TextOutputStream) throws {
    outputStream.write("Hello World")
}

}

Commands can parse command-line arguments and run themselves with the

parseAndRun
function:
let command = HelloWorldCommand()
command.parseAndRun()

Any errors thrown by

run(outputStream:errorStream)
will be caught and reported to the standard error stream.

Arguments

Mandatory arguments are defined using the generic

Argument
type and are parsed in the order they are declared in the command. They can also be configured with an optional
name
and
documentation
that will show in the help output:
class SplitCommand: Command {
    let name = "split"

@Argument(documentation: "The string to split.")
var string: String

@Argument(name: "separator", documentation: "The seperator to split the string with.")
var sep: Character

func run(outputStream: inout TextOutputStream, errorStream: inout TextOutputStream) throws {
    outputStream.write(string.split(separator: sep).joined(separator: "\n"))
    outputStream.write("\n")
}

}

$ split "The Swift Programming Language" " "
The
Swift
Programming
Language

Options

Optional arguments are defined using the generic

Option
type and must provide a
defaultValue
. The are parsed using the
--option value
or
--option=value
syntax where
option
is the name of the property, which can be customized with an optional
name
parameter. There is also an optional
shorthand
parameter to allow parsing them with a single character syntax of
-o value
or
-o=value
. Again,
documentation
can be provided for the help output:
class SplitCommand: Command {
    let name = "split"

@Argument
var string: String

@Option(name: "separator", shorthand: "s", documentation: "The seperator to split the string with.")
var sep: Character = " "

func run(outputStream: inout TextOutputStream, errorStream: inout TextOutputStream) throws {
    outputStream.write(string.split(separator: sep).joined(separator: "\n"))
    outputStream.write("\n")
}

}

$ split a,b,c,d --separator ,
a
b
c
d

Sub-commands

Help

Yaap comes with a built-in

Help
property that parses
--help/-h
arguments and prints the command's detailed documentation to standard output. It can be configured with a different name and shorthand syntax. Using the
RandomCommand
example from above:
class RandomCommand: Command {
    let name = "rand"
    let documentation = "Generates a random number that lies in an interval."
    let help = Help()

@Argument(documentation: "Exclusive maximum value")
var maximum: Int

@Option(shorthand: "m", documentation: "Inclusive minimum value")
var minimum: Int = 0

func run(outputStream: inout TextOutputStream, errorStream: inout TextOutputStream) throws {
    // ...
}

}

$ rand --help
OVERVIEW: Generates a random number that lies in an interval.

USAGE: rand [options] 

ARGUMENTS:
  maximum          Exclusive maximum value

OPTIONS:
  --help, -h       Display available options [default: false]
  --minimum, -m    Inclusive minimum value [default: 0]

Version

Yaap also comes with a built-in

Version
property that allows commands to respond to a
--version/-v
argument by printing their version number to standard output. The property can be customized to respond to a different argument name and optional shorthand syntax:
class MyCommand: Command {
    let name = "program"
    let version = Version("4.2", name: "ver", shorthand: nil)

func run(outputStream: inout TextOutputStream, errorStream: inout TextOutputStream) throws {
    // ...
}

}

$ program --ver
4.2

Thanks

I'd like to thank SwiftCLI for being a major influence in designing Yaap.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.