Skip to content

Commit

Permalink
clean up and readme
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanmiville committed Sep 8, 2024
1 parent 093f5b3 commit 9e73124
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 69 deletions.
81 changes: 41 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,72 +24,73 @@ 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/list
import gleam/string
type Args {
Args(name: String, count: Int, scream: Bool)
type Order {
Order(flavors: List(String), scoops: Int, cone: Bool)
}
fn greet(args: Args) {
let greeting = case args.scream {
True -> "HEY " <> string.uppercase(args.name) <> "!"
False -> "Hello, " <> args.name <> "."
}
list.repeat(greeting, args.count) |> list.each(io.println)
}
fn args_decoder() {
use name <- clad.arg(long_name: "name", short_name: "n", of: dynamic.string)
use count <- clad.arg_with_default(
long_name: "count",
short_name: "c",
of: dynamic.int,
default: 1,
)
use scream <- clad.toggle(long_name: "scream", short_name: "s")
clad.decoded(Args(name:, count:, scream:))
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 fn main() {
let args =
args_decoder()
let order =
order_decoder()
|> clad.decode(argv.load().arguments)
case args {
Ok(args) -> greet(args)
case order {
Ok(order) -> take_order(order)
_ ->
io.println(
"
Options:
-n, --name <NAME> Name of the person to greet
-c, --count <COUNT> Number of times to greet [default: 1]
-s, --scream Whether or not to scream greeting
-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
",
)
}
}
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!",
)
}
```

Run the program

```sh
❯ gleam run -m examples/greet -- -n Joe
Hello, Joe.
❯ gleam run -m examples/greet -- --name=Joe
Hello, Joe.
❯ gleam run -m examples/greet -- --name Joe --count 3 --scream
HEY JOE!
HEY JOE!
HEY JOE!
❯ gleam run -m examples/greet
❯ 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:
-n, --name <NAME> Name of the person to greet
-c, --count <COUNT> Number of times to greet [default: 1]
-s, --scream Whether or not to scream greeting
-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
```

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

# Fill out these fields if you intend to generate HTML documentation or publish
# your project to the Hex package manager.
Expand Down
35 changes: 7 additions & 28 deletions src/clad.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,7 @@ pub fn arg_with_default(

type Arg {
Arg(long_name: String, short_name: String)
LongName(String)
ShortName(String)
Name(String)
}

type DecodeResult =
Expand All @@ -307,8 +306,7 @@ type ArgResults {
long_result: DecodeResult,
short_result: DecodeResult,
)
LongNameResults(long_name: String, long_result: DecodeResult)
ShortNameResults(short_name: String, short_result: DecodeResult)
NameResults(name: String, result: DecodeResult)
}

/// Decode an argument by either its long name (`--name`) or short name (`-n`).
Expand Down Expand Up @@ -364,7 +362,7 @@ pub fn short_name(
next: fn(a) -> Decoder(b),
) {
fn(data) {
let first = do_arg(ShortName("-" <> short_name), decoder)
let first = do_arg(Name("-" <> short_name), decoder)
use a <- result.try(first(data))
next(a)(data)
}
Expand All @@ -384,7 +382,7 @@ pub fn long_name(
next: fn(a) -> Decoder(b),
) {
fn(data) {
let first = do_arg(LongName("--" <> long_name), decoder)
let first = do_arg(Name("--" <> long_name), decoder)
use a <- result.try(first(data))
next(a)(data)
}
Expand All @@ -401,14 +399,8 @@ fn do_arg(arg: Arg, using decoder: Decoder(t)) -> Decoder(t) {
dynamic.optional_field(short_name, dynamic.shallow_list)(data),
)
}
LongName(name) -> {
LongNameResults(
name,
dynamic.optional_field(name, dynamic.shallow_list)(data),
)
}
ShortName(name) -> {
ShortNameResults(
Name(name) -> {
NameResults(
name,
dynamic.optional_field(name, dynamic.shallow_list)(data),
)
Expand All @@ -417,8 +409,7 @@ fn do_arg(arg: Arg, using decoder: Decoder(t)) -> Decoder(t) {

case arg_res {
ArgResults(l, s, lr, sr) -> do_arg_results(l, s, lr, sr, decoder)
LongNameResults(n, r) -> do_single_name_results(n, r, decoder)
ShortNameResults(n, r) -> do_single_name_results(n, r, decoder)
NameResults(n, r) -> do_single_name_results(n, r, decoder)
}
}
}
Expand Down Expand Up @@ -533,18 +524,6 @@ fn do_object_list(
}
}

// fn failure(
// expected: String,
// found: String,
// path: List(String),
// ) -> Result(t, DecodeErrors) {
// Error([DecodeError(expected, found, path)])
// }

// fn missing_field_error(long_name: String) {
// failure("field", "nothing", ["--" <> long_name])
// }

fn missing_field(name: String) {
[DecodeError("field", "nothing", [name])]
}
52 changes: 52 additions & 0 deletions test/examples/ice_cream.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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)
}

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 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
",
)
}
}

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!",
)
}

0 comments on commit 9e73124

Please sign in to comment.