Skip to content

Commit

Permalink
feat: modify the builder api, add FlagBuilder, rename some functions
Browse files Browse the repository at this point in the history
  • Loading branch information
TanklesXL committed Jun 2, 2023
1 parent 812bbd6 commit 56f780f
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 144 deletions.
2 changes: 1 addition & 1 deletion .github/actions/test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ inputs:
gleam-version:
description: gleam version
required: false
default: 0.28.1
default: 0.29.0
erlang-version:
description: erlang-otp version
required: false
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
gleam: ["0.28.1"]
gleam: ["0.29.0"]
erlang: ["25.0.2"]
node: ["18.12.1"]
steps:
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
gleam 0.28.3
gleam 0.29.0
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Unreleased

- update to gleam v0.28
- update to gleam v0.20
- `flag` module now provides a getter per flag type instead of a unified one that previously returned the `Value` type.
- `glint` gains the `with_print_output` function to allow printing of command output when calling `run`.
- new builder api for commands and flags:
Expand All @@ -12,6 +12,8 @@
- `flag.new` to create a new flag
- `flag.default` to attach a default value to a flag
- `flag.constraint` to attach a constraint to a flag
- rename `glint.with_global_flags` to `glint.global_flags`
- `glint` gains the `global_flag` and `flag_tuple` functions.

## [0.11.2](https://github.com/TanklesXL/glint/compare/v0.11.1...v0.11.2)

Expand Down
6 changes: 3 additions & 3 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

packages = [
{ name = "gleam_bitwise", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "6064699EFBABB1CA392DCB193D0E8B402FB042B4B46857B01E6875E643B57F54" },
{ name = "gleam_community_ansi", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_community_colour", "gleam_bitwise"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "6E4E0CF2B207C1A7FCD3C21AA43514D67BC7004F21F82045CDCCE6C727A14862" },
{ name = "gleam_community_ansi", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_bitwise", "gleam_community_colour"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "6E4E0CF2B207C1A7FCD3C21AA43514D67BC7004F21F82045CDCCE6C727A14862" },
{ name = "gleam_community_colour", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_bitwise", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "D27CE357ECB343929A8CEC3FBA0B499943A47F0EE1F589EE16AFC2DC21C61E5B" },
{ name = "gleam_erlang", version = "0.18.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "C69F59D086AD50B80DE294FB0963550630971C9DC04E92B1F7AEEDD2C0BE226C" },
{ name = "gleam_stdlib", version = "0.28.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1BB6A3E53F7576B9F5C4E5D4AE16487E526BE383B03CBF4068C7DFC77CF38A1C" },
{ name = "gleam_erlang", version = "0.19.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "720D1E0A0CEBBD51C4AA88501D1D4FBFEF4AA7B3332C994691ED944767A52582" },
{ name = "gleam_stdlib", version = "0.29.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "24581B17879AA903B3E7531869D9460730C2F772A1C02C774ABF75710CCC4CFE" },
{ name = "gleeunit", version = "0.10.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "ECEA2DE4BE6528D36AFE74F42A21CDF99966EC36D7F25DEB34D47DD0F7977BAF" },
{ name = "snag", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "35C63E478782C58236F1050297C2FDF9806A4DD55C6FAF0B6EC5E54BC119342D" },
]
Expand Down
96 changes: 70 additions & 26 deletions src/glint.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type CommandNode(a) {
)
}

/// DEPRECATED: use `glint.cmd` and related builder functions instead to create a Command
/// DEPRECATED: use `glint.cmd` and related new functions instead to create a Command
///
/// Create command stubs to be used in `add_command_from_stub`
///
Expand All @@ -72,7 +72,7 @@ pub type Stub(a) {
)
}

/// DEPRECATED: use `glint.cmd` and related builder functions instead to create a Command
/// DEPRECATED: use `glint.cmd` and related new functions instead to create a Command
///
/// Add a command to the root given a stub
///
Expand All @@ -98,24 +98,6 @@ pub fn with_config(glint: Glint(a), config: Config(a)) -> Glint(a) {
Glint(..glint, config: config)
}

/// Add global flags to the existing command tree
pub fn with_global_flag(
glint: Glint(a),
at key: String,
of flag: Flag,
) -> Glint(a) {
Glint(..glint, global_flags: map.insert(glint.global_flags, key, flag))
}

/// Add global flags to the existing command tree
pub fn with_global_flags(
glint: Glint(a),
flags: List(#(String, Flag)),
) -> Glint(a) {
use acc, #(key, flag) <- list.fold(flags, glint)
with_global_flag(acc, key, flag)
}

/// Helper for initializing empty commands
///
fn empty_command() -> CommandNode(a) {
Expand All @@ -124,14 +106,14 @@ fn empty_command() -> CommandNode(a) {

/// Enable custom colours for help text headers
/// For a pre-made colouring use `default_pretty_help()`
///
///
pub fn with_pretty_help(glint: Glint(a), pretty: PrettyHelp) -> Glint(a) {
Config(pretty_help: Some(pretty))
|> with_config(glint, _)
}

/// Disable custom colours for help text headers
///
///
pub fn without_pretty_help(glint: Glint(a)) -> Glint(a) {
Config(pretty_help: None)
|> with_config(glint, _)
Expand Down Expand Up @@ -238,7 +220,7 @@ fn execute_root(
) -> CmdResult(a) {
case cmd.contents {
Some(contents) -> {
use new_flags <- result.then(list.try_fold(
use new_flags <- result.try(list.try_fold(
over: flag_inputs,
from: map.merge(global_flags, contents.flags),
with: flag.update_flags,
Expand Down Expand Up @@ -514,13 +496,75 @@ fn heading_style(heading: String, colour: Colour) -> String {
|> ansi.reset
}

// ******** WIP ************
// ***** Add flags to commands ******

pub fn flag(cmd: Command(a), at key: String, of flag: Flag) -> Command(a) {
Command(..cmd, flags: map.insert(cmd.flags, key, flag))
/// add a `flag.Flag` to a `Command`
///
pub fn flag(
cmd: Command(a),
at key: String,
of flag: flag.FlagBuilder(_),
) -> Command(a) {
Command(..cmd, flags: map.insert(cmd.flags, key, flag.build(flag)))
}

/// Add a `flag.Flag to a `Command` when the flag name and builder are bundled as a #(String, flag.FlagBuilder(a)).
///
/// This is merely a convenience function and calls `glint.flag` under the hood.
///
pub fn flag_tuple(
cmd: Command(a),
with tup: #(String, flag.FlagBuilder(_)),
) -> Command(a) {
flag(cmd, tup.0, tup.1)
}

/// Add multiple `Flag`s to a `Command`, note that this function uses `Flag` and not `FlagBuilder(_)`, so the user will need to call `flag.build` before providing the flags here.
///
/// It is recommended to call `glint.flag` instead.
///
pub fn flags(cmd: Command(a), with flags: List(#(String, Flag))) -> Command(a) {
use cmd, #(key, flag) <- list.fold(flags, cmd)
Command(..cmd, flags: map.insert(cmd.flags, key, flag))
}

/// Add global flags to the existing command tree
///
pub fn global_flag(
glint: Glint(a),
at key: String,
of flag: flag.FlagBuilder(_),
) -> Glint(a) {
Glint(
..glint,
global_flags: map.insert(glint.global_flags, key, flag.build(flag)),
)
}

/// Add global flags to the existing command tree.
///
pub fn global_flag_tuple(
glint: Glint(a),
with tup: #(String, flag.FlagBuilder(_)),
) -> Glint(a) {
global_flag(glint, tup.0, tup.1)
}

/// Add global flags to the existing command tree.
///
/// Like `glint.flags`, this function requires `Flag`s insead of `FlagBuilder(_)`.
///
/// It is recommended to use `glint.global_flag` instead.
///
pub fn global_flags(glint: Glint(a), flags: List(#(String, Flag))) -> Glint(a) {
Glint(
..glint,
global_flags: {
list.fold(
flags,
glint.global_flags,
fn(acc, tup) { map.insert(acc, tup.0, tup.1) },
)
},
)
}
67 changes: 41 additions & 26 deletions src/glint/flag.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,16 @@ pub type Value {
LS(Internal(List(String)))
}

/// A type that facilitates the usage of builder functions for creating `Value`s
/// ValueBuilder is a conveniency type to describe the constructors of the Value type.
///
pub type ValueBuilder(a) =
fn(Internal(a)) -> Value

/// A type that facilitates the usage of new functions for creating `Flag`s
///
pub type FlagBuilder(a) =
fn(Internal(a)) -> Flag

/// An internal representation of flag contents
///
pub opaque type Internal(a) {
Expand All @@ -73,33 +78,43 @@ pub type Flag {
Flag(value: Value, description: Description)
}

/// create a new `Flag`
/// create a new FlagBuilder from the provided ValueBuilder
///
pub fn new(of new: ValueBuilder(a)) -> FlagBuilder(a) {
fn(internal) { Flag(new(internal), "") }
}

/// create a new `Flag` from a `FlagBuilder(a)`
///
pub fn new(of val: ValueBuilder(a)) -> Flag {
let value = val(Internal(None, []))
Flag(value: value, description: "")
pub fn build(of new: FlagBuilder(a)) -> Flag {
new(Internal(None, []))
}

/// attach a description to a `Flag`
///
pub fn description(for flag: Flag, of description: Description) -> Flag {
Flag(..flag, description: description)
pub fn description(
for flag: FlagBuilder(a),
of description: Description,
) -> FlagBuilder(a) {
fn(internal) { Flag(..flag(internal), description: description) }
}

/// attach a constraint to a `Value`
/// attach a constraint to a `Flag`
///
pub fn constraint(
for val: ValueBuilder(a),
for flag: FlagBuilder(a),
of constraint: Constraint(a),
) -> ValueBuilder(a) {
) -> FlagBuilder(a) {
fn(internal) {
val(Internal(..internal, constraints: [constraint, ..internal.constraints]))
flag(
Internal(..internal, constraints: [constraint, ..internal.constraints]),
)
}
}

/// Set the default value for a flag `Value`
///
pub fn default(for val: ValueBuilder(a), of default: a) -> ValueBuilder(a) {
pub fn default(for val: FlagBuilder(a), of default: a) -> FlagBuilder(a) {
fn(internal) { val(Internal(..internal, value: Some(default))) }
}

Expand Down Expand Up @@ -129,7 +144,7 @@ pub fn update_flags(in flags: Map, with flag_input: String) -> Result(Map) {

fn update_flag_value(in flags: Map, with data: #(String, String)) -> Result(Map) {
let #(key, input) = data
use contents <- result.then(access(flags, key))
use contents <- result.try(access(flags, key))
use value <- result.map(compute_flag(
for: key,
with: input,
Expand All @@ -139,7 +154,7 @@ fn update_flag_value(in flags: Map, with data: #(String, String)) -> Result(Map)
}

fn attempt_toggle_flag(in flags: Map, at key: String) -> Result(Map) {
use contents <- result.then(access(flags, key))
use contents <- result.try(access(flags, key))
case contents.value {
B(Internal(None, ..) as internal) ->
Internal(..internal, value: Some(True))
Expand Down Expand Up @@ -198,7 +213,7 @@ fn compute_flag(

// Parser functions
fn parse_int(key, value, internal: Internal(Int)) {
use i <- result.then(
use i <- result.try(
int.parse(value)
|> result.replace_error(cannot_parse(key, value, "int")),
)
Expand All @@ -208,7 +223,7 @@ fn parse_int(key, value, internal: Internal(Int)) {
}

fn parse_int_list(key, value, internal: Internal(List(Int))) {
use li <- result.then(
use li <- result.try(
value
|> string.split(",")
|> list.try_map(int.parse)
Expand All @@ -221,7 +236,7 @@ fn parse_int_list(key, value, internal: Internal(List(Int))) {

// fn xxx(key,val,constraints){apply_constraints(key, li, internal.constraints)|> }
fn parse_float(key, value, internal: Internal(Float)) {
use f <- result.then(
use f <- result.try(
float.parse(value)
|> result.replace_error(cannot_parse(key, value, "float")),
)
Expand All @@ -231,7 +246,7 @@ fn parse_float(key, value, internal: Internal(Float)) {
}

fn parse_float_list(key, value, internal: Internal(List(Float))) {
use lf <- result.then(
use lf <- result.try(
value
|> string.split(",")
|> list.try_map(float.parse)
Expand All @@ -242,7 +257,7 @@ fn parse_float_list(key, value, internal: Internal(List(Float))) {
}

fn parse_bool(key, value, internal: Internal(Bool)) {
use val <- result.then(case string.lowercase(value) {
use val <- result.try(case string.lowercase(value) {
"true" | "t" -> Ok(True)
"false" | "f" -> Ok(False)
_ -> Error(cannot_parse(key, value, "bool"))
Expand Down Expand Up @@ -341,7 +356,7 @@ pub fn get_int_value(from flag: #(String, Flag)) -> Result(Int) {
/// Gets the current value for the associated int flag
///
pub fn get_int(from flags: Map, for name: String) -> Result(Int) {
use value <- result.then(access(flags, name))
use value <- result.try(access(flags, name))
get_int_value(#(name, value))
}

Expand All @@ -358,7 +373,7 @@ pub fn get_ints_value(from flag: #(String, Flag)) -> Result(List(Int)) {
/// Gets the current value for the associated ints flag
///
pub fn get_ints(from flags: Map, for name: String) -> Result(List(Int)) {
use value <- result.then(access(flags, name))
use value <- result.try(access(flags, name))
get_ints_value(#(name, value))
}

Expand All @@ -375,7 +390,7 @@ pub fn get_bool_value(from flag: #(String, Flag)) -> Result(Bool) {
/// Gets the current value for the associated bool flag
///
pub fn get_bool(from flags: Map, for name: String) -> Result(Bool) {
use value <- result.then(access(flags, name))
use value <- result.try(access(flags, name))
get_bool_value(#(name, value))
}

Expand All @@ -392,7 +407,7 @@ pub fn get_string_value(from flag: #(String, Flag)) -> Result(String) {
/// Gets the current value for the associated string flag
///
pub fn get_string(from flags: Map, for name: String) -> Result(String) {
use value <- result.then(access(flags, name))
use value <- result.try(access(flags, name))
get_string_value(#(name, value))
}

Expand All @@ -409,7 +424,7 @@ pub fn get_strings_value(from flag: #(String, Flag)) -> Result(List(String)) {
/// Gets the current value for the associated strings flag
///
pub fn get_strings(from flags: Map, for name: String) -> Result(List(String)) {
use value <- result.then(access(flags, name))
use value <- result.try(access(flags, name))
get_strings_value(#(name, value))
}

Expand All @@ -426,7 +441,7 @@ pub fn get_float_value(from flag: #(String, Flag)) -> Result(Float) {
/// Gets the current value for the associated float flag
///
pub fn get_float(from flags: Map, for name: String) -> Result(Float) {
use value <- result.then(access(flags, name))
use value <- result.try(access(flags, name))
get_float_value(#(name, value))
}

Expand All @@ -443,6 +458,6 @@ pub fn get_floats_value(from flag: #(String, Flag)) -> Result(List(Float)) {
/// Gets the current value for the associated floats flag
///
pub fn get_floats(from flags: Map, for name: String) -> Result(List(Float)) {
use value <- result.then(access(flags, name))
use value <- result.try(access(flags, name))
get_floats_value(#(name, value))
}
Loading

0 comments on commit 56f780f

Please sign in to comment.