Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minimist #3

Merged
merged 2 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 39 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@

Command line argument decoders for Gleam.

- Clad provides primitives to build a `dynamic.Decoder` for command line arguments.
- Arguments can be specified with long names (`--name`) or short names (`-n`).
- Values are decoded in the form `--name value` or `--name=value`.
- Boolean flags do not an explicit value. If the flag exists it is `True`, and if it is missing it is `False`. (i.e. `--verbose`)
Clad aims to make it as easy as possible to parse command line arguments in
Gleam. The goal is to support simple to medium complexity command line
interfaces while staying as minimal as possible. It is inspired by
[minimist](https://github.com/minimistjs/minimist) and
[gleam/json](https://hexdocs.pm/gleam_json/)


## Usage
Expand All @@ -24,80 +25,51 @@ This program is in the [examples directory](https://github.com/ryanmiville/clad/
```gleam
import argv
import clad
import gleam/bool
import gleam/dynamic
import gleam/int
import gleam/io
import gleam/string

type Order {
Order(flavors: List(String), scoops: Int, cone: Bool)
}
import decode/zero

fn order_decoder() {
use flavors <- clad.arg("flavor", "f", dynamic.list(dynamic.string))
use scoops <- clad.arg_with_default("scoops", "s", dynamic.int, default: 1)
use cone <- clad.toggle("cone", "c")
clad.decoded(Order(flavors:, scoops:, cone:))
pub type Student {
Student(name: String, age: Int, enrolled: Bool, classes: List(String))
}

pub fn main() {
let order =
order_decoder()
|> clad.decode(argv.load().arguments)

case order {
Ok(order) -> take_order(order)
_ ->
io.println(
"
Options:
-f, --flavor <FLAVOR> Flavors of ice cream
-s, --scoops <SCOOPS> Number of scoops per flavor [default: 1]
-c, --cone Put ice cream in a cone
",
)
let decoder = {
use name <- zero.field("name", zero.string)
use age <- zero.field("age", zero.int)
use enrolled <- zero.field("enrolled", zero.bool)
use classes <- clad.positional_arguments()
zero.success(Student(name:, age:, enrolled:, classes:))
}
}

fn take_order(order: Order) {
let scoops = bool.guard(order.scoops == 1, " scoop", fn() { " scoops" })
let container = bool.guard(order.cone, "cone", fn() { "cup" })
let flavs = string.join(order.flavors, " and ")
io.println(
int.to_string(order.scoops)
<> scoops
<> " of "
<> flavs
<> " in a "
<> container
<> ", coming right up!",
)
// args: --name Lucy --age 8 --enrolled true math science art
let result = clad.decode(argv.load().arguments, decoder)
let assert Ok(Student("Lucy", 8, True, ["math", "science", "art"])) = result
}
```

Run the program
Or, for more flexibility:

```sh
❯ gleam run -m examples/ice_cream -- -f vanilla
1 scoop of vanilla in a cup, coming right up!
❯ gleam run -m examples/ice_cream -- --flavor vanilla --flavor chocolate
1 scoop of vanilla and chocolate in a cup, coming right up!
❯ gleam run -m examples/ice_cream -- --flavor vanilla --flavor chocolate --scoops 2 --cone
2 scoops of vanilla and chocolate in a cone, coming right up!
❯ gleam run -m examples/ice_cream --

Options:
-f, --flavor <FLAVOR> Flavors of ice cream
-s, --scoops <SCOOPS> Number of scoops per flavor [default: 1]
-c, --cone Put ice cream in a cone
```
```gleam
import argv
import clad
import decode/zero

## Roadmap
pub type Student {
Student(name: String, age: Int, enrolled: Bool, classes: List(String))
}

pub fn main() {
let decoder = {
use name <- clad.opt("name", "n", zero.string)
use age <- clad.opt("age", "a", zero.int)
use enrolled <- clad.opt("enrolled", "e", clad.flag())
use classes <- clad.positional_arguments()
zero.success(Student(name:, age:, enrolled:, classes:))
}

- [ ] Settle on general API
- [ ] Add support for positional arguments
- [ ] Add support for subcommands
- [ ] Add support for environment variables
// args: --name=Lucy -ea8 math science art
let result = clad.decode(argv.load().arguments, decoder)
let assert Ok(Student("Lucy", 8, True, ["math", "science", "art"])) = result
}
```

Further documentation can be found at <https://hexdocs.pm/clad>.
4 changes: 3 additions & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "clad"
version = "0.1.5"
version = "0.2.0"

# Fill out these fields if you intend to generate HTML documentation or publish
# your project to the Hex package manager.
Expand All @@ -14,7 +14,9 @@ repository = { type = "github", user = "ryanmiville", repo = "clad" }

[dependencies]
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
decode = ">= 0.4.1 and < 1.0.0"

[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
argv = ">= 1.0.2 and < 2.0.0"
gleam_json = ">= 2.0.0 and < 3.0.0"
4 changes: 4 additions & 0 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@

packages = [
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
{ name = "decode", version = "0.4.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "90C83E830B380EAF64A0A20D0116C4C173AD753594AF1A37E692C1A699244244" },
{ name = "gleam_json", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "CB10B0E7BF44282FB25162F1A24C1A025F6B93E777CCF238C4017E4EEF2CDE97" },
{ name = "gleam_stdlib", version = "0.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" },
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
]

[requirements]
argv = { version = ">= 1.0.2 and < 2.0.0" }
decode = { version = ">= 0.4.1 and < 1.0.0" }
gleam_json = { version = ">= 2.0.0 and < 3.0.0" }
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
Loading