From 907146cae131dae99636013c8653abd7c2b1d2e3 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 01:51:31 +0100 Subject: [PATCH 01/15] changes --- CHANGELOG.md | 29 ++++ gleam.toml | 2 +- src/given.gleam | 367 +++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 330 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index daf2bea..df011ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,35 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +## [5.0.0] - 2025-01-16 + +- Removed duplicate functions: + - `given.given` + use qualified `given.that(...` or + unqualified import `given` instead. + - `given.not_given` + use qualified `given.not(in:...` or + unqualified import `not_given` instead. + - `given.ok_in` + use qualified `given.ok(in:...` or + unqualified import `given_ok_in` instead. + - `given.error_in`, + use qualified `given.error(in:...` or + unqualified import `given_error_in` instead. +- Added: + - `given.all` + - `given.any` + - `given.not_all` + - `given.not_any` + - `given.all_ok` + - `given.any_ok` + - `given.all_error` + - `given.any_error` + - `given.all_some` + - `given.any_some` + - `given.all_none` + - `given.any_none` + ## [4.1.1] - 2025-01-01 - Improved examples. diff --git a/gleam.toml b/gleam.toml index 63edf5c..0ad41fe 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,5 +1,5 @@ name = "given" -version = "4.1.1" +version = "5.0.0" # Fill out these fields if you intend to generate HTML documentation or publish # your project to the Hex package manager. diff --git a/src/given.gleam b/src/given.gleam index 0677452..02dff73 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -8,12 +8,27 @@ //// `bool.lazy_guard`. //// +import gleam/list import gleam/option.{type Option, None, Some} +import gleam/result /// ## Examples /// /// ```gleam -/// import given.{given} +/// import given +/// import gleam/int +/// let user_understood = case int.random(1) { +/// 1 -> True +/// _ -> False +/// } +/// +/// use <- given.that(user_understood, return: fn() { "Great!" }) +/// // …else handle case where user did not understand here… +/// "Woof!" +/// ``` +/// +/// ```gleam +/// import given.{that as given} /// import gleam/int /// let user_understood = case int.random(1) { /// 1 -> True @@ -25,8 +40,8 @@ import gleam/option.{type Option, None, Some} /// "Woof!" /// ``` /// -pub fn given( - requirement: Bool, +pub fn that( + the_case requirement: Bool, return consequence: fn() -> a, else_return alternative: fn() -> a, ) -> a { @@ -39,20 +54,78 @@ pub fn given( /// ## Examples /// /// ```gleam -/// import given.{not_given} +/// import given +/// let is_admin = False +/// let is_editor = True +/// +/// use <- given.any(true_of: [is_admin, is_editor], return: fn() { "Great!" }) +/// // …else handle case where user has no special role… +/// "Woof!" +/// ``` +/// +pub fn any( + true_of requirements: List(Bool), + return consequence: fn() -> a, + else_return alternative: fn() -> a, +) -> a { + case requirements |> list.any(fn(v) { v == True }) { + True -> consequence() + False -> alternative() + } +} + +/// ## Examples +/// +/// ```gleam +/// import given +/// let is_active = True +/// let is_confirmed = True +/// +/// use <- given.all([is_active, is_confirmed], return: fn() { "Great!" }) +/// // …else handle case where user is not both active and confirmed… +/// "Woof!" +/// ``` +/// +pub fn all( + true_of requirements: List(Bool), + return consequence: fn() -> a, + else_return alternative: fn() -> a, +) -> a { + case requirements |> list.all(fn(v) { v == True }) { + True -> consequence() + False -> alternative() + } +} + +/// ## Examples +/// +/// ```gleam +/// import given /// import gleam/int /// let user_understood = case int.random(1) { /// 1 -> True /// _ -> False /// } /// -/// use <- not_given(user_understood, return: fn() { "Woof!" }) +/// use <- given.not(user_understood, return: fn() { "Woof!" }) /// // …else handle case where user understood here… /// "Great!" /// ``` /// -pub fn not_given( - requirement: Bool, +/// ```gleam +/// import given.{not as not_given} +/// import gleam/int +/// let user_understood = case int.random(1) { +/// 1 -> True +/// _ -> False +/// } +/// +/// use <- not_given(user_understood, return: fn() { "Woof!" }) +/// // …else handle case where user understood here… +/// "Great!" +/// ``` +pub fn not( + the_case requirement: Bool, return consequence: fn() -> a, else_return alternative: fn() -> a, ) -> a { @@ -66,21 +139,64 @@ pub fn not_given( /// /// ```gleam /// import given -/// let result = Ok("Great") +/// let is_admin = False +/// let is_editor = True /// -/// use ok_value <- given.ok_in(result, else_return: fn(error_value) { "Error" }) -/// // …handle Ok value here… -/// "Ok" +/// use <- given.not_any([is_admin, is_editor], return: fn() { "At least either Admin or Editor!" }) +/// // …else handle case where user no special role… +/// "Woof!" /// ``` /// -pub fn ok_in( - result rslt: Result(a, e), - else_return alternative: fn(e) -> c, - return consequence: fn(a) -> c, -) -> c { - case rslt { - Ok(val) -> consequence(val) - Error(err) -> alternative(err) +/// ```gleam +/// import given +/// let is_admin = False +/// let is_editor = True +/// +/// use <- given.not_any(true_of: [is_admin, is_editor], return: fn() { "At least either Admin or Editor!" }) +/// // …else handle case where user no special role… +/// "Woof!" +/// ``` +/// +pub fn not_any( + true_of requirements: List(Bool), + return consequence: fn() -> a, + else_return alternative: fn() -> a, +) -> a { + case requirements |> list.any(fn(v) { v == True }) { + False -> consequence() + True -> alternative() + } +} + +/// ## Examples +/// +/// ```gleam +/// import given.{given_all} +/// let is_active = True +/// let is_confirmed = True +/// +/// use <- given.not_all([is_active, is_confirmed], return: fn() { "Cylone Sleeper Agent!" }) +/// // …else handle case where user is neither active nor confirmed… +/// "Woof!" +/// ``` +/// +/// ```gleam +/// import given.{given_all} +/// let is_active = True +/// let is_confirmed = True +/// +/// use <- given.not_all(true_of: [is_active, is_confirmed], return: fn() { "Cylone Sleeper Agent!" }) +/// // …else handle case where user is neither active nor confirmed… +/// "Woof!" +/// +pub fn not_all( + true_of requirements: List(Bool), + return consequence: fn() -> a, + else_return alternative: fn() -> a, +) -> a { + case requirements |> list.all(fn(v) { v == True }) { + False -> consequence() + True -> alternative() } } @@ -95,6 +211,14 @@ pub fn ok_in( /// "Ok" /// ``` /// +/// ```gleam +/// import given.{ok as given_ok_in} +/// let result = Ok("Great") +/// +/// use ok_value <- given_ok_in(result, else_return: fn(error_value) { "Error" }) +/// // …handle Ok value here… +/// "Ok" +/// ``` pub fn ok( in rslt: Result(a, e), else_return alternative: fn(e) -> c, @@ -106,35 +230,52 @@ pub fn ok( } } +// TODO: Examples +// +pub fn all_ok( + of rslts: List(Result(a, e)), + else_return alternative: fn(List(a), List(e)) -> c, + return consequence: fn(List(a)) -> c, +) -> c { + let #(oks, errors) = rslts |> result.partition + + case errors { + [] -> consequence(oks) + _some_errors -> alternative(oks, errors) + } +} + +// TODO: Examples +// +pub fn any_ok( + of rslts: List(Result(a, e)), + else_return alternative: fn(List(e)) -> c, + return consequence: fn(List(a), List(e)) -> c, +) -> c { + let #(oks, errors) = rslts |> result.partition + + case oks { + [] -> alternative(errors) + _some_errors -> consequence(oks, errors) + } +} + /// ## Examples /// /// ```gleam /// import given /// let result = Error(Nil) /// -/// use error_value <- given.error_in(result, else_return: fn(ok_value) { "Ok" }) +/// use error_value <- given.error(in: result, else_return: fn(ok_value) { "Ok" }) /// // …handle Error value here… /// "Error" /// ``` /// -pub fn error_in( - result rslt: Result(a, e), - else_return alternative: fn(a) -> c, - return consequence: fn(e) -> c, -) -> c { - case rslt { - Error(err) -> consequence(err) - Ok(val) -> alternative(val) - } -} - -/// ## Examples -/// /// ```gleam -/// import given +/// import given.{error as given_error_in} /// let result = Error(Nil) /// -/// use error_value <- given.error(in: result, else_return: fn(ok_value) { "Ok" }) +/// use error_value <- given_error_in(result, else_return: fn(ok_value) { "Ok" }) /// // …handle Error value here… /// "Error" /// ``` @@ -150,6 +291,36 @@ pub fn error( } } +// TODO: Examples +// +pub fn all_error( + of rslts: List(Result(a, e)), + else_return alternative: fn(List(a), List(e)) -> c, + return consequence: fn(List(e)) -> c, +) -> c { + let #(oks, errors) = rslts |> result.partition + + case oks { + [] -> alternative(oks, errors) + _some_errors -> consequence(errors) + } +} + +// TODO: Examples +// +pub fn any_error( + of rslts: List(Result(a, e)), + else_return alternative: fn(List(a), List(e)) -> c, + return consequence: fn(List(e)) -> c, +) -> c { + let #(oks, errors) = rslts |> result.partition + + case errors { + [] -> alternative(oks, errors) + _some_errors -> consequence(errors) + } +} + /// ## Examples /// /// ```gleam @@ -157,30 +328,17 @@ pub fn error( /// import gleam/option.{Some} /// let option = Some("One") /// -/// use some_value <- given.some_in(option, else_return: fn() { "None" }) +/// use some_value <- given.some(in: option, else_return: fn() { "None" }) /// // …handle Some value here… /// "Some value" /// ``` /// -pub fn some_in( - option optn: Option(a), - else_return alternative: fn() -> c, - return consequence: fn(a) -> c, -) -> c { - case optn { - Some(val) -> consequence(val) - None -> alternative() - } -} - -/// ## Examples -/// /// ```gleam -/// import given +/// import given.{some as given_some_in} /// import gleam/option.{Some} /// let option = Some("One") /// -/// use some_value <- given.some(in: option, else_return: fn() { "None" }) +/// use some_value <- given_some_in(option, else_return: fn() { "None" }) /// // …handle Some value here… /// "Some value" /// ``` @@ -196,6 +354,36 @@ pub fn some( } } +// TODO: Examples +// +pub fn all_some( + of optns: List(Option(a)), + else_return alternative: fn(List(a), Int) -> c, + return consequence: fn(List(a)) -> c, +) -> c { + let #(somes, nones) = optns |> option_partition + + case nones { + [] -> consequence(somes) + _nones -> alternative(somes, nones |> list.length) + } +} + +// TODO: Examples +// +pub fn any_some( + of optns: List(Option(a)), + else_return alternative: fn(List(a), Int) -> c, + return consequence: fn(List(a)) -> c, +) -> c { + let #(somes, nones) = optns |> option_partition + + case somes { + [] -> alternative(somes, nones |> list.length) + _somes -> consequence(somes) + } +} + /// ## Examples /// /// ```gleam @@ -203,30 +391,17 @@ pub fn some( /// import gleam/option.{None} /// let option = None /// -/// use <- given.none_in(option, else_return: fn(some_value) { "Some value" }) +/// use <- given.none(in: option, else_return: fn(some_value) { "Some value" }) /// // …handle None here… /// "None" /// ``` /// -pub fn none_in( - option optn: Option(a), - else_return alternative: fn(a) -> c, - return consequence: fn() -> c, -) -> c { - case optn { - None -> consequence() - Some(val) -> alternative(val) - } -} - -/// ## Examples -/// /// ```gleam -/// import given +/// import given.{none as given_none_in} /// import gleam/option.{None} /// let option = None /// -/// use <- given.none(in: option, else_return: fn(some_value) { "Some value" }) +/// use <- given_none_in(option, else_return: fn(some_value) { "Some value" }) /// // …handle None here… /// "None" /// ``` @@ -241,3 +416,61 @@ pub fn none( Some(val) -> alternative(val) } } + +// TODO: Examples +// +pub fn all_none( + of optns: List(Option(a)), + else_return alternative: fn(List(a), Int) -> c, + return consequence: fn() -> c, +) -> c { + let #(somes, nones) = optns |> option_partition + + case somes { + [] -> consequence() + _somes -> alternative(somes, nones |> list.length) + } +} + +// TODO: Examples +// +pub fn any_none( + of optns: List(Option(a)), + else_return alternative: fn(List(a), Int) -> c, + return consequence: fn() -> c, +) -> c { + let #(somes, nones) = optns |> option_partition + + case nones { + [] -> alternative(somes, nones |> list.length) + _nones -> consequence() + } +} + +/// Given a list of options, returns a pair where the first element is a list +/// of all the values inside `Some` and the second element is a list with all +/// the values None values. The values in both lists appear in reverse order +/// with respect to their position in the original list of options. +/// +/// ## Examples +/// +/// ```gleam +/// option_partition([Some(1), None, None, Some(2)]) +/// // -> #([2, 1], [None, None]) +/// ``` +/// +fn option_partition(options: List(Option(a))) -> #(List(a), List(e)) { + option_partition_loop(options, [], []) +} + +fn option_partition_loop( + options: List(Option(a)), + oks: List(a), + errors: List(e), +) { + case options { + [] -> #(oks, errors) + [Some(a), ..rest] -> option_partition_loop(rest, [a, ..oks], errors) + [None, ..rest] -> option_partition_loop(rest, oks, [e, ..errors]) + } +} From 9ac2a418dffd9c77fa64467122c94a45e28fe597 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 02:00:00 +0100 Subject: [PATCH 02/15] fixes --- README.md | 118 +-------------------------- src/given.gleam | 28 +++---- src/given/internal/examples.gleam | 46 +---------- test/given_test.gleam | 128 ++---------------------------- 4 files changed, 19 insertions(+), 301 deletions(-) diff --git a/README.md b/README.md index 590b746..f612de3 100644 --- a/README.md +++ b/README.md @@ -34,123 +34,7 @@ gleam add given ## Usage ```gleam -import given.{given, not_given} - -pub fn given_example() { - let user_understood = False - - use <- given(user_understood, return: fn() { "💡 Bright!" }) - // …else handle case where user did not understand here… - "🤯 Woof!" -} - -pub fn not_given_example() { - // Fetch this from some database - let has_admin_role = True - - use <- not_given(has_admin_role, return: fn() { "✋ Denied!" }) - // …else handle case where they are admin here… - "👌 Access granted..." -} - -pub fn given_ok_in_example() { - let a_result = Ok("Hello Joe!") - - use ok_value <- given.ok_in(result: a_result, else_return: fn(_error_value) { - "Error value" - }) - // …handle Ok value here… - ok_value -} - -pub fn given_ok_example() { - let a_result = Ok("Hello Joe, again!") - - use ok_value <- given.ok(in: a_result, else_return: fn(_error_value) { - "Error value" - }) - // …handle Ok value here… - ok_value -} - -pub fn given_error_in_example() { - let a_result = Error("Memory exhausted!") - - use error_value <- given.error_in(a_result, else_return: fn(_ok_value) { - "Ok value" - }) - // …handle Error value here… - error_value -} - -pub fn given_error_example() { - let a_result = Error("Memory exhausted, again!") - - use error_value <- given.error(in: a_result, else_return: fn(_ok_value) { - "Ok value" - }) - // …handle Error value here… - error_value -} - -import gleam/option.{None, Some} - -pub fn given_some_in_example() { - let an_option = Some("One Penny") - - use some_value <- given.some_in(an_option, else_return: fn() { "Woof!" }) - // …handle Some value here… - some_value -} - -pub fn given_some_example() { - let an_option = Some("One More Penny") - - use some_value <- given.some(in: an_option, else_return: fn() { "Woof!" }) - // …handle Some value here… - some_value -} - -pub fn given_none_in_example() { - let an_option = None - - use <- given.none_in(an_option, else_return: fn(_some_value) { "Some value" }) - // …handle None here… - "None, e.g. Nothing at all" -} - -pub fn given_none_example() { - let an_option = None - - use <- given.none(in: an_option, else_return: fn(_some_value) { "Some value" }) - // …handle None here… - "None, e.g. Still nothing!" -} - -import gleam/io - -pub fn main() { - given_example() |> io.debug - // "🤯 Woof!" - not_given_example() |> io.debug - // "👌 Access granted..." - given_ok_in_example() |> io.debug - // "Hello Joe!" - given_error_in_example() |> io.debug - // "Memory exhausted!" - given_some_in_example() |> io.debug - // "One Penny" - given_none_in_example() |> io.debug - // "None, e.g. Nothing at all" - given_ok_example() |> io.debug - // "Hello Joe, again!" - given_error_example() |> io.debug - // "Memory exhausted, again!" - given_some_example() |> io.debug - // "One More Penny" - given_none_example() |> io.debug - // "None, e.g. Still nothing" -} +# TODO: Copy src/given/internal/examples.gleam ``` ### Run usage examples diff --git a/src/given.gleam b/src/given.gleam index 02dff73..e8b8fcf 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -364,8 +364,8 @@ pub fn all_some( let #(somes, nones) = optns |> option_partition case nones { - [] -> consequence(somes) - _nones -> alternative(somes, nones |> list.length) + 0 -> consequence(somes) + _plus_1_nones -> alternative(somes, nones) } } @@ -379,7 +379,7 @@ pub fn any_some( let #(somes, nones) = optns |> option_partition case somes { - [] -> alternative(somes, nones |> list.length) + [] -> alternative(somes, nones) _somes -> consequence(somes) } } @@ -428,7 +428,7 @@ pub fn all_none( case somes { [] -> consequence() - _somes -> alternative(somes, nones |> list.length) + _somes -> alternative(somes, nones) } } @@ -442,8 +442,8 @@ pub fn any_none( let #(somes, nones) = optns |> option_partition case nones { - [] -> alternative(somes, nones |> list.length) - _nones -> consequence() + 0 -> alternative(somes, nones) + _plus_1_nones -> consequence() } } @@ -459,18 +459,14 @@ pub fn any_none( /// // -> #([2, 1], [None, None]) /// ``` /// -fn option_partition(options: List(Option(a))) -> #(List(a), List(e)) { - option_partition_loop(options, [], []) +fn option_partition(options: List(Option(a))) -> #(List(a), Int) { + option_partition_loop(options, [], 0) } -fn option_partition_loop( - options: List(Option(a)), - oks: List(a), - errors: List(e), -) { +fn option_partition_loop(options: List(Option(a)), somes: List(a), nones: Int) { case options { - [] -> #(oks, errors) - [Some(a), ..rest] -> option_partition_loop(rest, [a, ..oks], errors) - [None, ..rest] -> option_partition_loop(rest, oks, [e, ..errors]) + [] -> #(somes, nones) + [Some(a), ..rest] -> option_partition_loop(rest, [a, ..somes], nones) + [None, ..rest] -> option_partition_loop(rest, somes, nones + 1) } } diff --git a/src/given/internal/examples.gleam b/src/given/internal/examples.gleam index 6864fd4..acbc3bb 100644 --- a/src/given/internal/examples.gleam +++ b/src/given/internal/examples.gleam @@ -1,4 +1,4 @@ -import given.{given, not_given} +import given.{not as not_given, that as given} pub fn given_example() { let user_understood = False @@ -17,16 +17,6 @@ pub fn not_given_example() { "👌 Access granted..." } -pub fn given_ok_in_example() { - let a_result = Ok("Hello Joe!") - - use ok_value <- given.ok_in(result: a_result, else_return: fn(_error_value) { - "Error value" - }) - // …handle Ok value here… - ok_value -} - pub fn given_ok_example() { let a_result = Ok("Hello Joe, again!") @@ -37,16 +27,6 @@ pub fn given_ok_example() { ok_value } -pub fn given_error_in_example() { - let a_result = Error("Memory exhausted!") - - use error_value <- given.error_in(a_result, else_return: fn(_ok_value) { - "Ok value" - }) - // …handle Error value here… - error_value -} - pub fn given_error_example() { let a_result = Error("Memory exhausted, again!") @@ -59,14 +39,6 @@ pub fn given_error_example() { import gleam/option.{None, Some} -pub fn given_some_in_example() { - let an_option = Some("One Penny") - - use some_value <- given.some_in(an_option, else_return: fn() { "Woof!" }) - // …handle Some value here… - some_value -} - pub fn given_some_example() { let an_option = Some("One More Penny") @@ -75,14 +47,6 @@ pub fn given_some_example() { some_value } -pub fn given_none_in_example() { - let an_option = None - - use <- given.none_in(an_option, else_return: fn(_some_value) { "Some value" }) - // …handle None here… - "None, e.g. Nothing at all" -} - pub fn given_none_example() { let an_option = None @@ -98,14 +62,6 @@ pub fn main() { // "🤯 Woof!" not_given_example() |> io.debug // "👌 Access granted..." - given_ok_in_example() |> io.debug - // "Hello Joe!" - given_error_in_example() |> io.debug - // "Memory exhausted!" - given_some_in_example() |> io.debug - // "One Penny" - given_none_in_example() |> io.debug - // "None, e.g. Nothing at all" given_ok_example() |> io.debug // "Hello Joe, again!" given_error_example() |> io.debug diff --git a/test/given_test.gleam b/test/given_test.gleam index 1a2e2b6..ee32268 100644 --- a/test/given_test.gleam +++ b/test/given_test.gleam @@ -1,4 +1,4 @@ -import given.{given, not_given} +import given import gleam/option.{None, Some} import gleeunit import gleeunit/should @@ -14,7 +14,7 @@ const error_woof = "Woof! 🐶" pub fn given_test() { { let user_understood = False - use <- given(user_understood, return: fn() { ok_great }) + use <- given.that(user_understood, return: fn() { ok_great }) // …else user handles case where user did not understand here… error_woof } @@ -22,7 +22,7 @@ pub fn given_test() { { let user_understood = True - use <- given(user_understood, return: fn() { ok_great }) + use <- given.that(user_understood, return: fn() { ok_great }) // …else user handles case where user did not understand here… error_woof } @@ -32,7 +32,7 @@ pub fn given_test() { pub fn not_given_test() { { let user_understood = False - use <- not_given(user_understood, return: fn() { ok_great }) + use <- given.not(user_understood, return: fn() { ok_great }) // …else user handles case where user understood here… error_woof } @@ -40,53 +40,13 @@ pub fn not_given_test() { { let user_understood = True - use <- not_given(user_understood, return: fn() { ok_great }) + use <- given.not(user_understood, return: fn() { ok_great }) // …else user handles case where user understood here… error_woof } |> should.equal(error_woof) } -pub fn given_ok_in_test() { - { - let result = Ok(ok_great) - use ok_value <- given.ok_in(result, else_return: fn(error_value) { - error_value - }) - // …user handles Ok value here… - ok_value - } - |> should.equal(ok_great) - - { - let result = Error(error_woof) - use ok_value <- given.ok_in(result, else_return: fn(error_value) { - error_value - }) - // …user handles Ok value here… - ok_value - } - |> should.equal(error_woof) -} - -pub fn given_ok_in_unusual_usage_test() { - { - let result = Ok(ok_great) - use _error_value <- given.ok_in(result, return: fn(_ok_value) { ok_great }) - // …user handles Error value here… - error_woof - } - |> should.equal(ok_great) - - { - let result = Error(error_woof) - use _error_value <- given.ok_in(result, return: fn(_ok_value) { ok_great }) - // …user handles Error value here… - error_woof - } - |> should.equal(error_woof) -} - pub fn given_ok_test() { { let result = Ok(ok_great) @@ -127,28 +87,6 @@ pub fn given_ok_unusual_usage_test() { |> should.equal(error_woof) } -pub fn given_error_in_test() { - { - let result = Error(error_woof) - use _error_value <- given.error_in(result, else_return: fn(_ok_value) { - ok_great - }) - // …user handles Error value here… - error_woof - } - |> should.equal(error_woof) - - { - let result = Ok(ok_great) - use _error_value <- given.error_in(result, else_return: fn(_ok_value) { - ok_great - }) - // …user handles Error value here… - error_woof - } - |> should.equal(ok_great) -} - pub fn given_error_test() { { let result = Error(error_woof) @@ -171,24 +109,6 @@ pub fn given_error_test() { |> should.equal(ok_great) } -pub fn given_some_in_test() { - { - let option = Some(ok_great) - use _some_value <- given.some_in(option, else_return: fn() { error_woof }) - // …user handles Some value here… - ok_great - } - |> should.equal(ok_great) - - { - let option = Some(ok_great) - use _some_value <- given.some_in(option, else_return: fn() { error_woof }) - // …user handles Some value here… - ok_great - } - |> should.equal(ok_great) -} - pub fn given_some_test() { { let option = Some(ok_great) @@ -207,24 +127,6 @@ pub fn given_some_test() { |> should.equal(ok_great) } -pub fn given_none_in_test() { - { - let option = Some(ok_great) - use <- given.none_in(option, else_return: fn(_some_value) { ok_great }) - // …user handles None here… - error_woof - } - |> should.equal(ok_great) - - { - let option = None - use <- given.none_in(option, else_return: fn(_some_value) { ok_great }) - // …user handles None here… - "None encountered!" - } - |> should.equal("None encountered!") -} - pub fn given_none_test() { { let option = Some(ok_great) @@ -243,26 +145,6 @@ pub fn given_none_test() { |> should.equal("None encountered!") } -pub fn given_none_in_unusual_test() { - { - let option = Some(ok_great) - use some_value <- given.none_in(option, return: fn() { "None encountered!" }) - // …user handles Some value here… - some_value - } - |> should.equal(ok_great) - - { - let option = None - use else_some_value <- given.none_in(option, return: fn() { - "None encountered!" - }) - // …user handles Some value here… - else_some_value - } - |> should.equal("None encountered!") -} - pub fn given_none_unusual_test() { { let option = Some(ok_great) From 359742ecc3a93c162b6330f44b5cab4aaeb7208b Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 02:08:09 +0100 Subject: [PATCH 03/15] fix --- src/given.gleam | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/given.gleam b/src/given.gleam index e8b8fcf..e7fe81d 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -455,8 +455,8 @@ pub fn any_none( /// ## Examples /// /// ```gleam -/// option_partition([Some(1), None, None, Some(2)]) -/// // -> #([2, 1], [None, None]) +/// option_partition([Some("Wibble"), None, None, Some("Wobble")]) +/// // -> #(["Wibble", "Wobble"], 2) /// ``` /// fn option_partition(options: List(Option(a))) -> #(List(a), Int) { From fc731580cb578ec9bbf53039393cf03905636c31 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 02:16:04 +0100 Subject: [PATCH 04/15] fix --- src/given.gleam | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/given.gleam b/src/given.gleam index e7fe81d..e3a1941 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -361,11 +361,11 @@ pub fn all_some( else_return alternative: fn(List(a), Int) -> c, return consequence: fn(List(a)) -> c, ) -> c { - let #(somes, nones) = optns |> option_partition + let #(somes, nones_count) = optns |> option_partition - case nones { + case nones_count { 0 -> consequence(somes) - _plus_1_nones -> alternative(somes, nones) + _plus_1_nones -> alternative(somes, nones_count) } } @@ -373,14 +373,14 @@ pub fn all_some( // pub fn any_some( of optns: List(Option(a)), - else_return alternative: fn(List(a), Int) -> c, - return consequence: fn(List(a)) -> c, + else_return alternative: fn(Int) -> c, + return consequence: fn(List(a), Int) -> c, ) -> c { - let #(somes, nones) = optns |> option_partition + let #(somes, nones_count) = optns |> option_partition case somes { - [] -> alternative(somes, nones) - _somes -> consequence(somes) + [] -> alternative(nones_count) + _somes -> consequence(somes, nones_count) } } @@ -424,11 +424,11 @@ pub fn all_none( else_return alternative: fn(List(a), Int) -> c, return consequence: fn() -> c, ) -> c { - let #(somes, nones) = optns |> option_partition + let #(somes, nones_count) = optns |> option_partition case somes { [] -> consequence() - _somes -> alternative(somes, nones) + _somes -> alternative(somes, nones_count) } } @@ -436,14 +436,14 @@ pub fn all_none( // pub fn any_none( of optns: List(Option(a)), - else_return alternative: fn(List(a), Int) -> c, - return consequence: fn() -> c, + else_return alternative: fn(List(a)) -> c, + return consequence: fn(List(a), Int) -> c, ) -> c { - let #(somes, nones) = optns |> option_partition + let #(somes, nones_count) = optns |> option_partition - case nones { - 0 -> alternative(somes, nones) - _plus_1_nones -> consequence() + case nones_count { + 0 -> alternative(somes) + _plus_1_nones -> consequence(somes, nones_count) } } From 0e4f4e54f497ae288f4ec92a67cecaf0ab61bc7a Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 02:18:54 +0100 Subject: [PATCH 05/15] renames --- src/given.gleam | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/given.gleam b/src/given.gleam index e3a1941..f9dc309 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -241,7 +241,7 @@ pub fn all_ok( case errors { [] -> consequence(oks) - _some_errors -> alternative(oks, errors) + _non_zero_errors -> alternative(oks, errors) } } @@ -256,7 +256,7 @@ pub fn any_ok( case oks { [] -> alternative(errors) - _some_errors -> consequence(oks, errors) + _non_zero_oks -> consequence(oks, errors) } } @@ -302,7 +302,7 @@ pub fn all_error( case oks { [] -> alternative(oks, errors) - _some_errors -> consequence(errors) + _non_zero_oks -> consequence(errors) } } @@ -317,7 +317,7 @@ pub fn any_error( case errors { [] -> alternative(oks, errors) - _some_errors -> consequence(errors) + _non_zero_errors -> consequence(errors) } } @@ -365,7 +365,7 @@ pub fn all_some( case nones_count { 0 -> consequence(somes) - _plus_1_nones -> alternative(somes, nones_count) + _positive_none_count -> alternative(somes, nones_count) } } @@ -380,7 +380,7 @@ pub fn any_some( case somes { [] -> alternative(nones_count) - _somes -> consequence(somes, nones_count) + _non_zero_somes -> consequence(somes, nones_count) } } @@ -428,7 +428,7 @@ pub fn all_none( case somes { [] -> consequence() - _somes -> alternative(somes, nones_count) + _non_zero_somes -> alternative(somes, nones_count) } } @@ -443,7 +443,7 @@ pub fn any_none( case nones_count { 0 -> alternative(somes) - _plus_1_nones -> consequence(somes, nones_count) + _positive_none_count -> consequence(somes, nones_count) } } From cb91e9493fc63b10440b7a180638d45d4c156c57 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 02:24:15 +0100 Subject: [PATCH 06/15] deps --- gleam.toml | 2 +- manifest.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gleam.toml b/gleam.toml index 0ad41fe..31e9451 100644 --- a/gleam.toml +++ b/gleam.toml @@ -13,7 +13,7 @@ repository = { type = "github", user = "inoas", repo = "gleam-given" } # https://gleam.run/writing-gleam/gleam-toml/. [dependencies] -gleam_stdlib = ">= 0.44.0 and < 2.0.0" +gleam_stdlib = ">= 0.50.0 and <= 2.0.0" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index 8ee3130..c863f79 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,10 +2,10 @@ # You typically do not need to edit this file packages = [ - { name = "gleam_stdlib", version = "0.47.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "3B22D46743C46498C8355365243327AC731ECD3959216344FA9CF9AD348620AC" }, + { name = "gleam_stdlib", version = "0.52.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "50703862DF26453B277688FFCDBE9DD4AC45B3BD9742C0B370DB62BC1629A07D" }, { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, ] [requirements] -gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } +gleam_stdlib = { version = ">= 0.50.0 and <= 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } From c25746370f2cd2d891ade4076381efe6550bd9fa Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 02:26:13 +0100 Subject: [PATCH 07/15] fix --- manifest.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.toml b/manifest.toml index c863f79..a0ada2a 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,7 +2,7 @@ # You typically do not need to edit this file packages = [ - { name = "gleam_stdlib", version = "0.52.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "50703862DF26453B277688FFCDBE9DD4AC45B3BD9742C0B370DB62BC1629A07D" }, + { name = "gleam_stdlib", version = "0.50.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "489AFCEE829FADE57F20F4C69AD67C59D80610D8A3C7DB5A7E12BE75946AAF55" }, { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, ] From b3afd172e1593c78152e8c9890e6ceead2377e32 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 14:59:24 +0100 Subject: [PATCH 08/15] fixes --- src/given.gleam | 180 ++++++++++++++++++++---------------- src/given/lib/optionx.gleam | 25 +++++ 2 files changed, 123 insertions(+), 82 deletions(-) create mode 100644 src/given/lib/optionx.gleam diff --git a/src/given.gleam b/src/given.gleam index f9dc309..1d76e1e 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -8,6 +8,7 @@ //// `bool.lazy_guard`. //// +import given/lib/optionx import gleam/list import gleam/option.{type Option, None, Some} import gleam/result @@ -42,9 +43,9 @@ import gleam/result /// pub fn that( the_case requirement: Bool, - return consequence: fn() -> a, - else_return alternative: fn() -> a, -) -> a { + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { case requirement { True -> consequence() False -> alternative() @@ -65,9 +66,9 @@ pub fn that( /// pub fn any( true_of requirements: List(Bool), - return consequence: fn() -> a, - else_return alternative: fn() -> a, -) -> a { + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { case requirements |> list.any(fn(v) { v == True }) { True -> consequence() False -> alternative() @@ -88,9 +89,9 @@ pub fn any( /// pub fn all( true_of requirements: List(Bool), - return consequence: fn() -> a, - else_return alternative: fn() -> a, -) -> a { + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { case requirements |> list.all(fn(v) { v == True }) { True -> consequence() False -> alternative() @@ -126,9 +127,9 @@ pub fn all( /// ``` pub fn not( the_case requirement: Bool, - return consequence: fn() -> a, - else_return alternative: fn() -> a, -) -> a { + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { case requirement { False -> consequence() True -> alternative() @@ -159,9 +160,9 @@ pub fn not( /// pub fn not_any( true_of requirements: List(Bool), - return consequence: fn() -> a, - else_return alternative: fn() -> a, -) -> a { + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { case requirements |> list.any(fn(v) { v == True }) { False -> consequence() True -> alternative() @@ -191,15 +192,54 @@ pub fn not_any( /// pub fn not_all( true_of requirements: List(Bool), - return consequence: fn() -> a, - else_return alternative: fn() -> a, -) -> a { + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { case requirements |> list.all(fn(v) { v == True }) { False -> consequence() True -> alternative() } } +// TODO: Examples +// +pub fn where( + is condition: fn() -> Bool, + else_return alternative: fn() -> b, + return consequence: fn() -> b, +) -> b { + case condition() { + True -> consequence() + False -> alternative() + } +} + +// TODO: Examples +// +pub fn empty( + list list: List(a), + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { + case list { + [] -> consequence() + _not_empty -> alternative() + } +} + +// TODO: Examples +// +pub fn not_empty( + list list: List(a), + return consequence: fn() -> b, + else_return alternative: fn() -> b, +) -> b { + case list { + [] -> alternative() + _not_empty -> consequence() + } +} + /// ## Examples /// /// ```gleam @@ -221,9 +261,9 @@ pub fn not_all( /// ``` pub fn ok( in rslt: Result(a, e), - else_return alternative: fn(e) -> c, - return consequence: fn(a) -> c, -) -> c { + else_return alternative: fn(e) -> b, + return consequence: fn(a) -> b, +) -> b { case rslt { Ok(val) -> consequence(val) Error(err) -> alternative(err) @@ -234,9 +274,9 @@ pub fn ok( // pub fn all_ok( of rslts: List(Result(a, e)), - else_return alternative: fn(List(a), List(e)) -> c, - return consequence: fn(List(a)) -> c, -) -> c { + else_return alternative: fn(List(a), List(e)) -> b, + return consequence: fn(List(a)) -> b, +) -> b { let #(oks, errors) = rslts |> result.partition case errors { @@ -249,9 +289,9 @@ pub fn all_ok( // pub fn any_ok( of rslts: List(Result(a, e)), - else_return alternative: fn(List(e)) -> c, - return consequence: fn(List(a), List(e)) -> c, -) -> c { + else_return alternative: fn(List(e)) -> b, + return consequence: fn(List(a), List(e)) -> b, +) -> b { let #(oks, errors) = rslts |> result.partition case oks { @@ -282,9 +322,9 @@ pub fn any_ok( /// pub fn error( in rslt: Result(a, e), - else_return alternative: fn(a) -> c, - return consequence: fn(e) -> c, -) -> c { + else_return alternative: fn(a) -> b, + return consequence: fn(e) -> b, +) -> b { case rslt { Error(err) -> consequence(err) Ok(val) -> alternative(val) @@ -295,9 +335,9 @@ pub fn error( // pub fn all_error( of rslts: List(Result(a, e)), - else_return alternative: fn(List(a), List(e)) -> c, - return consequence: fn(List(e)) -> c, -) -> c { + else_return alternative: fn(List(a), List(e)) -> b, + return consequence: fn(List(e)) -> b, +) -> b { let #(oks, errors) = rslts |> result.partition case oks { @@ -310,9 +350,9 @@ pub fn all_error( // pub fn any_error( of rslts: List(Result(a, e)), - else_return alternative: fn(List(a), List(e)) -> c, - return consequence: fn(List(e)) -> c, -) -> c { + else_return alternative: fn(List(a), List(e)) -> b, + return consequence: fn(List(e)) -> b, +) -> b { let #(oks, errors) = rslts |> result.partition case errors { @@ -345,9 +385,9 @@ pub fn any_error( /// pub fn some( in optn: Option(a), - else_return alternative: fn() -> c, - return consequence: fn(a) -> c, -) -> c { + else_return alternative: fn() -> b, + return consequence: fn(a) -> b, +) -> b { case optn { Some(val) -> consequence(val) None -> alternative() @@ -358,10 +398,10 @@ pub fn some( // pub fn all_some( of optns: List(Option(a)), - else_return alternative: fn(List(a), Int) -> c, - return consequence: fn(List(a)) -> c, -) -> c { - let #(somes, nones_count) = optns |> option_partition + else_return alternative: fn(List(a), Int) -> b, + return consequence: fn(List(a)) -> b, +) -> b { + let #(somes, nones_count) = optns |> optionx.partition case nones_count { 0 -> consequence(somes) @@ -373,10 +413,10 @@ pub fn all_some( // pub fn any_some( of optns: List(Option(a)), - else_return alternative: fn(Int) -> c, - return consequence: fn(List(a), Int) -> c, -) -> c { - let #(somes, nones_count) = optns |> option_partition + else_return alternative: fn(Int) -> b, + return consequence: fn(List(a), Int) -> b, +) -> b { + let #(somes, nones_count) = optns |> optionx.partition case somes { [] -> alternative(nones_count) @@ -408,9 +448,9 @@ pub fn any_some( /// pub fn none( in optn: Option(a), - else_return alternative: fn(a) -> c, - return consequence: fn() -> c, -) -> c { + else_return alternative: fn(a) -> b, + return consequence: fn() -> b, +) -> b { case optn { None -> consequence() Some(val) -> alternative(val) @@ -421,10 +461,10 @@ pub fn none( // pub fn all_none( of optns: List(Option(a)), - else_return alternative: fn(List(a), Int) -> c, - return consequence: fn() -> c, -) -> c { - let #(somes, nones_count) = optns |> option_partition + else_return alternative: fn(List(a), Int) -> b, + return consequence: fn() -> b, +) -> b { + let #(somes, nones_count) = optns |> optionx.partition case somes { [] -> consequence() @@ -436,37 +476,13 @@ pub fn all_none( // pub fn any_none( of optns: List(Option(a)), - else_return alternative: fn(List(a)) -> c, - return consequence: fn(List(a), Int) -> c, -) -> c { - let #(somes, nones_count) = optns |> option_partition + else_return alternative: fn(List(a)) -> b, + return consequence: fn(List(a), Int) -> b, +) -> b { + let #(somes, nones_count) = optns |> optionx.partition case nones_count { 0 -> alternative(somes) _positive_none_count -> consequence(somes, nones_count) } } - -/// Given a list of options, returns a pair where the first element is a list -/// of all the values inside `Some` and the second element is a list with all -/// the values None values. The values in both lists appear in reverse order -/// with respect to their position in the original list of options. -/// -/// ## Examples -/// -/// ```gleam -/// option_partition([Some("Wibble"), None, None, Some("Wobble")]) -/// // -> #(["Wibble", "Wobble"], 2) -/// ``` -/// -fn option_partition(options: List(Option(a))) -> #(List(a), Int) { - option_partition_loop(options, [], 0) -} - -fn option_partition_loop(options: List(Option(a)), somes: List(a), nones: Int) { - case options { - [] -> #(somes, nones) - [Some(a), ..rest] -> option_partition_loop(rest, [a, ..somes], nones) - [None, ..rest] -> option_partition_loop(rest, somes, nones + 1) - } -} diff --git a/src/given/lib/optionx.gleam b/src/given/lib/optionx.gleam new file mode 100644 index 0000000..40a6765 --- /dev/null +++ b/src/given/lib/optionx.gleam @@ -0,0 +1,25 @@ +import gleam/option.{type Option, None, Some} + +/// Given a list of options, returns a pair where the first element is a list +/// of all the values inside `Some` and the second element is a count of all +/// `None` values. The values in the returning list appear in reverse order +/// with respect to their position in the original list of options. +/// +/// ## Examples +/// +/// ```gleam +/// partition([Some("Wibble"), None, None, Some("Wobble")]) +/// // -> #(["Wibble", "Wobble"], 2) +/// ``` +/// +pub fn partition(options: List(Option(a))) -> #(List(a), Int) { + partition_loop(options, [], 0) +} + +fn partition_loop(options: List(Option(a)), somes: List(a), nones: Int) { + case options { + [] -> #(somes, nones) + [Some(a), ..rest] -> partition_loop(rest, [a, ..somes], nones) + [None, ..rest] -> partition_loop(rest, somes, nones + 1) + } +} From 7df0373e937b1bf795bee49068d4b91db820326b Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 15:00:59 +0100 Subject: [PATCH 09/15] name --- src/given/lib/optionx.gleam | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/given/lib/optionx.gleam b/src/given/lib/optionx.gleam index 40a6765..8ae16e3 100644 --- a/src/given/lib/optionx.gleam +++ b/src/given/lib/optionx.gleam @@ -16,10 +16,10 @@ pub fn partition(options: List(Option(a))) -> #(List(a), Int) { partition_loop(options, [], 0) } -fn partition_loop(options: List(Option(a)), somes: List(a), nones: Int) { +fn partition_loop(options: List(Option(a)), somes: List(a), none_count: Int) { case options { - [] -> #(somes, nones) - [Some(a), ..rest] -> partition_loop(rest, [a, ..somes], nones) - [None, ..rest] -> partition_loop(rest, somes, nones + 1) + [] -> #(somes, none_count) + [Some(a), ..rest] -> partition_loop(rest, [a, ..somes], none_count) + [None, ..rest] -> partition_loop(rest, somes, none_count + 1) } } From 49d18a4c6c1ba7d59313f12dcf197d195e34ddc5 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 15:02:36 +0100 Subject: [PATCH 10/15] changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df011ce..68da443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), use qualified `given.error(in:...` or unqualified import `given_error_in` instead. - Added: + - `given.where` + - `given.empty` + - `given.not_empty` - `given.all` - `given.any` - `given.not_all` From eb8b568fc9e9ad44d234df6617f5c3525800fe7c Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 16:21:15 +0100 Subject: [PATCH 11/15] wip --- CHANGELOG.md | 31 ++-- src/given.gleam | 417 +++++++++++++++++++++++++++++++++++------- test/given_test.gleam | 249 ++++++++++++++++--------- 3 files changed, 534 insertions(+), 163 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68da443..b1e05f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,21 +21,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), use qualified `given.error(in:...` or unqualified import `given_error_in` instead. - Added: - - `given.where` - - `given.empty` - - `given.not_empty` - - `given.all` - - `given.any` - - `given.not_all` - - `given.not_any` - - `given.all_ok` - - `given.any_ok` - - `given.all_error` - - `given.any_error` - - `given.all_some` - - `given.any_some` - - `given.all_none` - - `given.any_none` + - `given.all` to check if all elements in a list are true. + - `given.any` to check if any elements in a list are true. + - `given.not_all` to check if all elements in a list are false. + - `given.not_any` to check if any elements in a list are false. + - `given.when` to allow for more complex lazy conditions. + - `given.when_not` to allow for more complex lazy conditions. + - `given.empty` to check if a list is empty. + - `given.not_empty` to check if a list is not empty. + - `given.all_ok` to check if all results are ok. + - `given.any_ok` to check if any results are ok. + - `given.all_error` to check if all results are errors. + - `given.any_error` to check if any results are errors. + - `given.all_some` to check if all options are some. + - `given.any_some` to check if any options are some. + - `given.all_none` to check if all options are none. + - `given.any_none` to check if any options are none. ## [4.1.1] - 2025-01-01 diff --git a/src/given.gleam b/src/given.gleam index 1d76e1e..7040921 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -1,6 +1,6 @@ //// This library attempts to make guards: //// -//// - Applicable to `Bool`, `Result` and `Option` types. +//// - Applicable to `Bool`, `Result`, `Option` and `List` types. //// - Ergonomic to use by providing ways to handle both branches early. //// - Expressive by making it easy to read through function names and labels. //// - Comprehendable by not having to negate the conditions. @@ -13,15 +13,15 @@ import gleam/list import gleam/option.{type Option, None, Some} import gleam/result +/// Checks if the condition is true and runs the consequence if it is, else +/// runs the alternative. +/// /// ## Examples /// /// ```gleam /// import given -/// import gleam/int -/// let user_understood = case int.random(1) { -/// 1 -> True -/// _ -> False -/// } +/// +/// let user_understood = True /// /// use <- given.that(user_understood, return: fn() { "Great!" }) /// // …else handle case where user did not understand here… @@ -30,11 +30,8 @@ import gleam/result /// /// ```gleam /// import given.{that as given} -/// import gleam/int -/// let user_understood = case int.random(1) { -/// 1 -> True -/// _ -> False -/// } +/// +/// let user_understood = True /// /// use <- given(user_understood, return: fn() { "Great!" }) /// // …else handle case where user did not understand here… @@ -52,20 +49,37 @@ pub fn that( } } +/// Checks if any of the conditions are true and runs the consequence if any +/// are, else runs the alternative. +/// /// ## Examples /// /// ```gleam /// import given +/// +/// let is_admin = False +/// let is_editor = True +/// +/// use <- given.any([is_admin, is_editor], return: fn() { "Great!" }) +/// +/// // …else handle case where user has no special role… +/// "Woof!" +/// ``` +/// +/// ```gleam +/// import given +/// /// let is_admin = False /// let is_editor = True /// -/// use <- given.any(true_of: [is_admin, is_editor], return: fn() { "Great!" }) +/// use <- given.any(are_true_in: [is_admin, is_editor], return: fn() { "Great!" }) +/// /// // …else handle case where user has no special role… /// "Woof!" /// ``` /// pub fn any( - true_of requirements: List(Bool), + are_true_in requirements: List(Bool), return consequence: fn() -> b, else_return alternative: fn() -> b, ) -> b { @@ -75,20 +89,36 @@ pub fn any( } } +/// Checks if all of the conditions are true and runs the consequence if all +/// are, else runs the alternative. +/// /// ## Examples /// /// ```gleam /// import given +/// /// let is_active = True /// let is_confirmed = True /// /// use <- given.all([is_active, is_confirmed], return: fn() { "Great!" }) +/// /// // …else handle case where user is not both active and confirmed… /// "Woof!" /// ``` /// +/// ```gleam +/// import given +/// +/// let is_active = True +/// let is_confirmed = True +/// +/// use <- given.all(are_true_in: [is_active, is_confirmed], return: fn() { "Great!" }) +/// +/// // …else handle case where user is not both active and confirmed… +/// "Woof!" +/// ``` pub fn all( - true_of requirements: List(Bool), + are_true_in requirements: List(Bool), return consequence: fn() -> b, else_return alternative: fn() -> b, ) -> b { @@ -98,33 +128,44 @@ pub fn all( } } +/// Checks if the condition is false and runs the consequence if it is, else +/// runs the alternative. +/// /// ## Examples /// /// ```gleam /// import given -/// import gleam/int -/// let user_understood = case int.random(1) { -/// 1 -> True -/// _ -> False -/// } +/// +/// let user_understood = True /// /// use <- given.not(user_understood, return: fn() { "Woof!" }) +/// +/// // …else handle case where user understood here… +/// "Great!" +/// ``` +/// +/// ```gleam +/// import given +/// +/// let user_understood = True +/// +/// use <- given.not(the_case: user_understood, return: fn() { "Woof!" }) +/// /// // …else handle case where user understood here… /// "Great!" /// ``` /// /// ```gleam /// import given.{not as not_given} -/// import gleam/int -/// let user_understood = case int.random(1) { -/// 1 -> True -/// _ -> False -/// } +/// +/// let user_understood = True /// /// use <- not_given(user_understood, return: fn() { "Woof!" }) +/// /// // …else handle case where user understood here… /// "Great!" /// ``` +/// pub fn not( the_case requirement: Bool, return consequence: fn() -> b, @@ -136,30 +177,37 @@ pub fn not( } } +/// Checks if any of the conditions are false and runs the consequence if any +/// are, else runs the alternative. +/// /// ## Examples /// /// ```gleam /// import given +/// /// let is_admin = False /// let is_editor = True /// /// use <- given.not_any([is_admin, is_editor], return: fn() { "At least either Admin or Editor!" }) +/// /// // …else handle case where user no special role… /// "Woof!" /// ``` /// /// ```gleam /// import given +/// /// let is_admin = False /// let is_editor = True /// -/// use <- given.not_any(true_of: [is_admin, is_editor], return: fn() { "At least either Admin or Editor!" }) +/// use <- given.not_any(are_true_in: [is_admin, is_editor], return: fn() { "At least either Admin or Editor!" }) +/// /// // …else handle case where user no special role… /// "Woof!" /// ``` /// pub fn not_any( - true_of requirements: List(Bool), + are_true_in requirements: List(Bool), return consequence: fn() -> b, else_return alternative: fn() -> b, ) -> b { @@ -169,29 +217,36 @@ pub fn not_any( } } +/// Checks if all of the conditions are false and runs the consequence if all +/// are, else runs the alternative. +/// /// ## Examples /// /// ```gleam -/// import given.{given_all} +/// import given +/// /// let is_active = True /// let is_confirmed = True /// /// use <- given.not_all([is_active, is_confirmed], return: fn() { "Cylone Sleeper Agent!" }) +/// /// // …else handle case where user is neither active nor confirmed… /// "Woof!" /// ``` /// /// ```gleam -/// import given.{given_all} +/// import given +/// /// let is_active = True /// let is_confirmed = True /// -/// use <- given.not_all(true_of: [is_active, is_confirmed], return: fn() { "Cylone Sleeper Agent!" }) +/// use <- given.not_all(are_true_in: [is_active, is_confirmed], return: fn() { "Cylone Sleeper Agent!" }) +/// /// // …else handle case where user is neither active nor confirmed… /// "Woof!" /// pub fn not_all( - true_of requirements: List(Bool), + are_true_in requirements: List(Bool), return consequence: fn() -> b, else_return alternative: fn() -> b, ) -> b { @@ -201,10 +256,37 @@ pub fn not_all( } } -// TODO: Examples -// -pub fn where( - is condition: fn() -> Bool, +/// Checks if the condition function returns `True` and runs the consequence if +/// it is, else runs the alternative. +/// +/// Use to lazily evaluate a complex condition and return early if they fail. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let enabled = fn() { False } +/// +/// use <- given.when(enabled, else_return: fn() { "Not an Admin" }) +/// +/// // …handle case where user is an Admin… +/// "Indeed an Admin" +/// ``` +/// +/// ```gleam +/// import given +/// +/// let enabled = fn() { False } +/// +/// use <- given.when(enabled, return: fn() { "Indeed an Admin" }) +/// +/// // …handle case where user is not an Admin… +/// "Not an Admin" +/// ``` +/// +pub fn when( + the_case condition: fn() -> Bool, else_return alternative: fn() -> b, return consequence: fn() -> b, ) -> b { @@ -214,12 +296,66 @@ pub fn where( } } -// TODO: Examples -// +/// Checks if the condition function returns `False` and runs the consequence if +/// it is, else runs the alternative. +/// +/// Use to lazily evaluate a complex condition and return early if they fail. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let enabled = fn() { False } +/// +/// use <- given.when_not(enabled, else_return: fn() { "Indeed an Admin" }) +/// +/// // …handle case where user is not an Admin… +/// "Not an Admin" +/// ``` +/// +/// ```gleam +/// import given +/// +/// let enabled = fn() { False } +/// +/// use <- given.when_not(enabled, return: fn() { "Not an Admin" }) +/// +/// // …handle case where user is an Admin… +/// "Indeed an Admin" +/// ``` +/// +pub fn when_not( + the_case condition: fn() -> Bool, + else_return alternative: fn() -> b, + return consequence: fn() -> b, +) -> b { + case condition() { + False -> consequence() + True -> alternative() + } +} + +/// Checks if the list is empty and runs the consequence if it is, else runs +/// the alternative. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let list = [] +/// +/// use <- given.empty(list, else_return: fn() { "Not empty" }) +/// +/// // …handle empty list here… +/// "Empty" +/// ``` +/// pub fn empty( list list: List(a), - return consequence: fn() -> b, else_return alternative: fn() -> b, + return consequence: fn() -> b, ) -> b { case list { [] -> consequence() @@ -227,12 +363,26 @@ pub fn empty( } } -// TODO: Examples -// +/// Checks if the list is not empty and runs the consequence if it is, else +/// runs the alternative. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let list = [] +/// +/// use <- given.not_empty(list, else_return: fn() { "Empty" }) +/// +/// // …handle non-empty list here… +/// "Not empty" +/// ``` +/// pub fn not_empty( list list: List(a), - return consequence: fn() -> b, else_return alternative: fn() -> b, + return consequence: fn() -> b, ) -> b { case list { [] -> alternative() @@ -240,25 +390,33 @@ pub fn not_empty( } } +/// Checks if the result is an `Ok` and runs the consequence if it is, else +/// runs the alternative. +/// /// ## Examples /// /// ```gleam /// import given +/// /// let result = Ok("Great") /// /// use ok_value <- given.ok(in: result, else_return: fn(error_value) { "Error" }) +/// /// // …handle Ok value here… /// "Ok" /// ``` /// /// ```gleam /// import given.{ok as given_ok_in} +/// /// let result = Ok("Great") /// /// use ok_value <- given_ok_in(result, else_return: fn(error_value) { "Error" }) +/// /// // …handle Ok value here… /// "Ok" /// ``` +/// pub fn ok( in rslt: Result(a, e), else_return alternative: fn(e) -> b, @@ -270,10 +428,25 @@ pub fn ok( } } -// TODO: Examples -// +/// Checks if all of the results are `Ok` and runs the consequence - passing in +/// the `Ok` values - if they are, else runs the alternative passing in all +/// `Ok` and `Error` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let results = [Ok("Great"), Error("Bad")] +/// +/// use oks <- given.all_ok(in: results, else_return: fn(_oks, _errors) { "Some Errors" }) +/// +/// // …handle all OKs here… +/// "All OKs" +/// ``` +/// pub fn all_ok( - of rslts: List(Result(a, e)), + in rslts: List(Result(a, e)), else_return alternative: fn(List(a), List(e)) -> b, return consequence: fn(List(a)) -> b, ) -> b { @@ -285,10 +458,25 @@ pub fn all_ok( } } -// TODO: Examples -// +/// Checks if any of the results are `Ok` and runs the consequence - passing in +/// the `Ok` and `Error` values - if they are, else runs the alternative passing +/// in all `Error` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let results = [Ok("Great"), Error("Bad")] +/// +/// use <- given.any_ok(in: results, else_return: fn(errors) { "All Errors" }) +/// +/// // …handle at least some OKs here… +/// "At least some OKs" +/// ``` +/// pub fn any_ok( - of rslts: List(Result(a, e)), + in rslts: List(Result(a, e)), else_return alternative: fn(List(e)) -> b, return consequence: fn(List(a), List(e)) -> b, ) -> b { @@ -300,22 +488,29 @@ pub fn any_ok( } } +/// Checks if the result is an `Error` and runs the consequence if it is, else +/// runs the alternative. +/// /// ## Examples /// /// ```gleam /// import given +/// /// let result = Error(Nil) /// /// use error_value <- given.error(in: result, else_return: fn(ok_value) { "Ok" }) +/// /// // …handle Error value here… /// "Error" /// ``` /// /// ```gleam /// import given.{error as given_error_in} +/// /// let result = Error(Nil) /// /// use error_value <- given_error_in(result, else_return: fn(ok_value) { "Ok" }) +/// /// // …handle Error value here… /// "Error" /// ``` @@ -331,10 +526,25 @@ pub fn error( } } -// TODO: Examples -// +/// Checks if all of the results are `Error` and runs the consequence - passing +/// in the `Error` values - if they are, else runs the alternative passing in +/// all `Ok` and `Error` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let results = [Ok("Great"), Error("Bad")] +/// +/// use errors <- given.all_error(in: results, else_return: fn(_oks, _errors) { "Only some Errors" }) +/// +/// // …handle all errors here… +/// "All Errors" +/// ``` +/// pub fn all_error( - of rslts: List(Result(a, e)), + in rslts: List(Result(a, e)), else_return alternative: fn(List(a), List(e)) -> b, return consequence: fn(List(e)) -> b, ) -> b { @@ -346,10 +556,22 @@ pub fn all_error( } } -// TODO: Examples -// +/// Checks if any of the results are `Error` and runs the consequence - passing +/// in the `Ok` and `Error` values - if they are, else runs the alternative +/// passing in all `Ok` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let results = [Ok("Great"), Error("Bad")] +/// +/// use oks, errors <- given.any_error(in: results, else_return: fn(_oks) { "Only OKs" }) +/// ``` +/// pub fn any_error( - of rslts: List(Result(a, e)), + in rslts: List(Result(a, e)), else_return alternative: fn(List(a), List(e)) -> b, return consequence: fn(List(e)) -> b, ) -> b { @@ -366,9 +588,11 @@ pub fn any_error( /// ```gleam /// import given /// import gleam/option.{Some} +/// /// let option = Some("One") /// /// use some_value <- given.some(in: option, else_return: fn() { "None" }) +/// /// // …handle Some value here… /// "Some value" /// ``` @@ -376,9 +600,11 @@ pub fn any_error( /// ```gleam /// import given.{some as given_some_in} /// import gleam/option.{Some} +/// /// let option = Some("One") /// /// use some_value <- given_some_in(option, else_return: fn() { "None" }) +/// /// // …handle Some value here… /// "Some value" /// ``` @@ -394,10 +620,25 @@ pub fn some( } } -// TODO: Examples -// +/// Checks if all of the options are `Some` and runs the consequence - passing +/// in the `Some` values - if they are, else runs the alternative passing in +/// the `Some` and a count of the `None` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let options = [Some("One"), None] +/// +/// use <- given.all_some(in: options, else_return: fn(_somes, _nones_count) { "Some are None" }) +/// +/// // …handle all Some values here… +/// "All are Some" +/// ``` +/// pub fn all_some( - of optns: List(Option(a)), + in optns: List(Option(a)), else_return alternative: fn(List(a), Int) -> b, return consequence: fn(List(a)) -> b, ) -> b { @@ -409,10 +650,25 @@ pub fn all_some( } } -// TODO: Examples -// +/// Checks if any of the options are `Some` and runs the consequence - passing +/// in the `Some` values and a count of the `None` values - if they are, else +/// runs the alternative passing in the count of `None` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let options = [Some("One"), None] +/// +/// use <- given.any_some(in: options, else_return: fn(_somes, _nones_count) { "All are None" }) +/// +/// // …handle at least some None values here… +/// "At least some are None" +/// ``` +/// pub fn any_some( - of optns: List(Option(a)), + in optns: List(Option(a)), else_return alternative: fn(Int) -> b, return consequence: fn(List(a), Int) -> b, ) -> b { @@ -429,9 +685,11 @@ pub fn any_some( /// ```gleam /// import given /// import gleam/option.{None} +/// /// let option = None /// /// use <- given.none(in: option, else_return: fn(some_value) { "Some value" }) +/// /// // …handle None here… /// "None" /// ``` @@ -439,10 +697,12 @@ pub fn any_some( /// ```gleam /// import given.{none as given_none_in} /// import gleam/option.{None} +/// /// let option = None /// /// use <- given_none_in(option, else_return: fn(some_value) { "Some value" }) /// // …handle None here… +/// /// "None" /// ``` /// @@ -457,10 +717,24 @@ pub fn none( } } -// TODO: Examples -// +/// Checks if all of the options are `None` and runs the consequence if they +/// are, else runs the alternative passing in the `Some` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let options = [Some("One"), None] +/// +/// use <- given.all_none(in: options, else_return: fn(_somes, _nones_count) { "Some are Some" }) +/// +/// // …handle all None values here… +/// "All are None" +/// ``` +/// pub fn all_none( - of optns: List(Option(a)), + in optns: List(Option(a)), else_return alternative: fn(List(a), Int) -> b, return consequence: fn() -> b, ) -> b { @@ -472,10 +746,25 @@ pub fn all_none( } } -// TODO: Examples -// +/// Checks if any of the options are `None` and runs the consequence if they +/// are, else runs the alternative passing in the `Some` values and the count +/// of `None` values. +/// +/// ## Examples +/// +/// ```gleam +/// import given +/// +/// let options = [Some("One"), None] +/// +/// use <- given.any_none(in: options, else_return: fn(_somes) { "All are Some" }) +/// +/// // …handle at least some None values here… +/// "At least some are None" +/// ``` +/// pub fn any_none( - of optns: List(Option(a)), + in optns: List(Option(a)), else_return alternative: fn(List(a)) -> b, return consequence: fn(List(a), Int) -> b, ) -> b { diff --git a/test/given_test.gleam b/test/given_test.gleam index ee32268..24e6b8f 100644 --- a/test/given_test.gleam +++ b/test/given_test.gleam @@ -7,162 +7,243 @@ pub fn main() { gleeunit.main() } -const ok_great = "Great! ✨" +const great = "Great! ✨" -const error_woof = "Woof! 🐶" +const woof = "Woof! 🐶" -pub fn given_test() { +pub fn that_test() { { let user_understood = False - use <- given.that(user_understood, return: fn() { ok_great }) + + use <- given.that(user_understood, return: fn() { great }) + // …else user handles case where user did not understand here… - error_woof + woof } - |> should.equal(error_woof) + |> should.equal(woof) { let user_understood = True - use <- given.that(user_understood, return: fn() { ok_great }) + + use <- given.that(user_understood, return: fn() { great }) + // …else user handles case where user did not understand here… - error_woof + woof + } + |> should.equal(great) +} + +pub fn any_test() { + { + let is_admin = False + let is_editor = True + + use <- given.any([is_admin, is_editor], return: fn() { great }) + + // …else handle case where user has no special role… + woof + } + |> should.equal(great) +} + +pub fn all_test() { + { + let is_active = True + let is_confirmed = True + + use <- given.all([is_active, is_confirmed], return: fn() { great }) + + // …else handle case where user is not both active and confirmed… + woof } - |> should.equal(ok_great) + |> should.equal(great) } -pub fn not_given_test() { +pub fn not_test() { { let user_understood = False - use <- given.not(user_understood, return: fn() { ok_great }) + + use <- given.not(user_understood, return: fn() { great }) + // …else user handles case where user understood here… - error_woof + woof } - |> should.equal(ok_great) + |> should.equal(great) { let user_understood = True - use <- given.not(user_understood, return: fn() { ok_great }) + + use <- given.not(user_understood, return: fn() { great }) + // …else user handles case where user understood here… - error_woof + woof + } + |> should.equal(woof) +} + +pub fn not_any_test() { + { + let is_admin = False + let is_editor = True + + use <- given.not_any([is_admin, is_editor], return: fn() { + "At least either Admin or Editor!" + }) + + // …else handle case where user no special role… + "User has no special role!" + } + |> should.equal("User has no special role!") +} + +pub fn not_all_test() { + { + let is_human = False + let is_robot = False + + use <- given.not_all([is_human, is_robot], return: fn() { + "Obsolete model detected." + }) + + // …else handle case where user is neither active nor confirmed… + "I am a Cylon!" } - |> should.equal(error_woof) + |> should.equal("Obsolete model detected.") } -pub fn given_ok_test() { +pub fn when_test() { + { + let enabled = fn() { False } + + use <- given.when(enabled, else_return: fn() { "Not an Admin" }) + + // …handle case where user is an Admin… + "Indeed an Admin" + } + |> should.equal("Not an Admin") + { - let result = Ok(ok_great) + let enabled = fn() { False } + + use <- given.when(enabled, return: fn() { "Indeed an Admin" }) + + // …handle case where user is not an Admin… + "Not an Admin" + } + |> should.equal("Not an Admin") +} + +pub fn when_not_test() { + { + let enabled = fn() { False } + + use <- given.when_not(enabled, else_return: fn() { "Indeed an Admin" }) + + // …handle case where user is an Admin… + "Not an Admin" + } + |> should.equal("Not an Admin") + // { + // let enabled = fn() { False } + + // use <- given.when_not(enabled, return: fn() { "Not an Admin" }) + + // // …handle case where user is not an Admin… + // "Indeed an Admin" + // } + // |> should.equal("Not an Admin") +} + +pub fn ok_test() { + { + let result = Ok(great) use ok_value <- given.ok(in: result, else_return: fn(error_value) { error_value }) + // …user handles Ok value here… ok_value } - |> should.equal(ok_great) + |> should.equal(great) { - let result = Error(error_woof) + let result = Error(woof) use ok_value <- given.ok(in: result, else_return: fn(error_value) { error_value }) + // …user handles Ok value here… ok_value } - |> should.equal(error_woof) + |> should.equal(woof) } -pub fn given_ok_unusual_usage_test() { +pub fn error_test() { { - let result = Ok(ok_great) - use _error_value <- given.ok(in: result, return: fn(_ok_value) { ok_great }) - // …user handles Error value here… - error_woof - } - |> should.equal(ok_great) + let result = Error(woof) - { - let result = Error(error_woof) - use _error_value <- given.ok(in: result, return: fn(_ok_value) { ok_great }) - // …user handles Error value here… - error_woof - } - |> should.equal(error_woof) -} - -pub fn given_error_test() { - { - let result = Error(error_woof) use _error_value <- given.error(in: result, else_return: fn(_ok_value) { - ok_great + great }) + // …user handles Error value here… - error_woof + woof } - |> should.equal(error_woof) + |> should.equal(woof) { - let result = Ok(ok_great) + let result = Ok(great) + use _error_value <- given.error(in: result, else_return: fn(_ok_value) { - ok_great + great }) + // …user handles Error value here… - error_woof + woof } - |> should.equal(ok_great) + |> should.equal(great) } -pub fn given_some_test() { +pub fn some_test() { { - let option = Some(ok_great) - use _some_value <- given.some(in: option, else_return: fn() { error_woof }) + let option = Some(great) + + use _some_value <- given.some(in: option, else_return: fn() { woof }) + // …user handles Some value here… - ok_great + great } - |> should.equal(ok_great) + |> should.equal(great) { - let option = Some(ok_great) - use _some_value <- given.some(in: option, else_return: fn() { error_woof }) + let option = Some(great) + + use _some_value <- given.some(in: option, else_return: fn() { woof }) + // …user handles Some value here… - ok_great + great } - |> should.equal(ok_great) + |> should.equal(great) } -pub fn given_none_test() { +pub fn none_test() { { - let option = Some(ok_great) - use <- given.none(in: option, else_return: fn(_some_value) { ok_great }) + let option = Some(great) + + use <- given.none(in: option, else_return: fn(_some_value) { great }) + // …user handles None here… - error_woof + woof } - |> should.equal(ok_great) + |> should.equal(great) { let option = None - use <- given.none(in: option, else_return: fn(_some_value) { ok_great }) - // …user handles None here… - "None encountered!" - } - |> should.equal("None encountered!") -} -pub fn given_none_unusual_test() { - { - let option = Some(ok_great) - use some_value <- given.none(in: option, return: fn() { - "None encountered!" - }) - // …user handles Some value here… - some_value - } - |> should.equal(ok_great) + use <- given.none(in: option, else_return: fn(_some_value) { great }) - { - let option = None - use else_some_value <- given.none(in: option, return: fn() { - "None encountered!" - }) - // …user handles Some value here… - else_some_value + // …user handles None here… + "None encountered!" } |> should.equal("None encountered!") } From 2d6eb798d84ddc9271479f43155d82cbab1912b3 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 16:24:40 +0100 Subject: [PATCH 12/15] wip --- CHANGELOG.md | 2 +- src/given.gleam | 4 ++-- src/given/internal/examples.gleam | 2 ++ test/given_test.gleam | 40 +++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e05f3..bd5d7b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), - `given.when` to allow for more complex lazy conditions. - `given.when_not` to allow for more complex lazy conditions. - `given.empty` to check if a list is empty. - - `given.not_empty` to check if a list is not empty. + - `given.non_empty` to check if a list is not empty. - `given.all_ok` to check if all results are ok. - `given.any_ok` to check if any results are ok. - `given.all_error` to check if all results are errors. diff --git a/src/given.gleam b/src/given.gleam index 7040921..f0d508f 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -373,13 +373,13 @@ pub fn empty( /// /// let list = [] /// -/// use <- given.not_empty(list, else_return: fn() { "Empty" }) +/// use <- given.non_empty(list, else_return: fn() { "Empty" }) /// /// // …handle non-empty list here… /// "Not empty" /// ``` /// -pub fn not_empty( +pub fn non_empty( list list: List(a), else_return alternative: fn() -> b, return consequence: fn() -> b, diff --git a/src/given/internal/examples.gleam b/src/given/internal/examples.gleam index acbc3bb..a1a4c57 100644 --- a/src/given/internal/examples.gleam +++ b/src/given/internal/examples.gleam @@ -1,5 +1,7 @@ import given.{not as not_given, that as given} +// TODO: add new examples + pub fn given_example() { let user_understood = False diff --git a/test/given_test.gleam b/test/given_test.gleam index 24e6b8f..7b1cf8e 100644 --- a/test/given_test.gleam +++ b/test/given_test.gleam @@ -154,6 +154,14 @@ pub fn when_not_test() { // |> should.equal("Not an Admin") } +pub fn empty_test() { + todo +} + +pub fn non_empty_test() { + todo +} + pub fn ok_test() { { let result = Ok(great) @@ -178,6 +186,14 @@ pub fn ok_test() { |> should.equal(woof) } +pub fn any_ok_test() { + todo +} + +pub fn all_ok_test() { + todo +} + pub fn error_test() { { let result = Error(woof) @@ -204,6 +220,14 @@ pub fn error_test() { |> should.equal(great) } +pub fn any_error_test() { + todo +} + +pub fn all_error_test() { + todo +} + pub fn some_test() { { let option = Some(great) @@ -226,6 +250,14 @@ pub fn some_test() { |> should.equal(great) } +pub fn any_some_test() { + todo +} + +pub fn all_some_test() { + todo +} + pub fn none_test() { { let option = Some(great) @@ -247,3 +279,11 @@ pub fn none_test() { } |> should.equal("None encountered!") } + +pub fn any_none_test() { + todo +} + +pub fn all_none_test() { + todo +} From df55fb8192e8d4faaa36bbbcbca7f41f1ad6b733 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 19:27:11 +0100 Subject: [PATCH 13/15] fix-impl-tests --- src/given.gleam | 187 +++++++++++---------- src/given/{ => internal}/lib/optionx.gleam | 14 +- test/given_test.gleam | 113 +++++++++++-- test/internal/lib/optionx_test.gleam | 11 ++ 4 files changed, 220 insertions(+), 105 deletions(-) rename src/given/{ => internal}/lib/optionx.gleam (64%) create mode 100644 test/internal/lib/optionx_test.gleam diff --git a/src/given.gleam b/src/given.gleam index f0d508f..4a7afdc 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -8,7 +8,7 @@ //// `bool.lazy_guard`. //// -import given/lib/optionx +import given/internal/lib/optionx import gleam/list import gleam/option.{type Option, None, Some} import gleam/result @@ -428,9 +428,9 @@ pub fn ok( } } -/// Checks if all of the results are `Ok` and runs the consequence - passing in -/// the `Ok` values - if they are, else runs the alternative passing in all -/// `Ok` and `Error` values. +/// Checks if any of the results are `Ok` and runs the consequence - passing in +/// the `Ok` and `Error` values - if they are, else runs the alternative passing +/// in all `Error` values. /// /// ## Examples /// @@ -439,28 +439,28 @@ pub fn ok( /// /// let results = [Ok("Great"), Error("Bad")] /// -/// use oks <- given.all_ok(in: results, else_return: fn(_oks, _errors) { "Some Errors" }) +/// use _oks, _errors <- given.any_ok(in: results, else_return: fn(_errors) { "All Errors" }) /// -/// // …handle all OKs here… -/// "All OKs" +/// // …handle at least some OKs here… +/// "At least some OKs" /// ``` /// -pub fn all_ok( +pub fn any_ok( in rslts: List(Result(a, e)), - else_return alternative: fn(List(a), List(e)) -> b, - return consequence: fn(List(a)) -> b, + else_return alternative: fn(List(e)) -> b, + return consequence: fn(List(a), List(e)) -> b, ) -> b { let #(oks, errors) = rslts |> result.partition - case errors { - [] -> consequence(oks) - _non_zero_errors -> alternative(oks, errors) + case oks { + [] -> alternative(errors) + _non_zero_oks -> consequence(oks, errors) } } -/// Checks if any of the results are `Ok` and runs the consequence - passing in -/// the `Ok` and `Error` values - if they are, else runs the alternative passing -/// in all `Error` values. +/// Checks if all of the results are `Ok` and runs the consequence - passing in +/// the `Ok` values - if they are, else runs the alternative passing in all +/// `Ok` and `Error` values. /// /// ## Examples /// @@ -469,22 +469,22 @@ pub fn all_ok( /// /// let results = [Ok("Great"), Error("Bad")] /// -/// use <- given.any_ok(in: results, else_return: fn(errors) { "All Errors" }) +/// use oks <- given.all_ok(in: results, else_return: fn(_oks, _errors) { "Some Errors" }) /// -/// // …handle at least some OKs here… -/// "At least some OKs" +/// // …handle all OKs here… +/// "All OKs" /// ``` /// -pub fn any_ok( +pub fn all_ok( in rslts: List(Result(a, e)), - else_return alternative: fn(List(e)) -> b, - return consequence: fn(List(a), List(e)) -> b, + else_return alternative: fn(List(a), List(e)) -> b, + return consequence: fn(List(a)) -> b, ) -> b { let #(oks, errors) = rslts |> result.partition - case oks { - [] -> alternative(errors) - _non_zero_oks -> consequence(oks, errors) + case errors { + [] -> consequence(oks) + _non_zero_errors -> alternative(oks, errors) } } @@ -526,9 +526,9 @@ pub fn error( } } -/// Checks if all of the results are `Error` and runs the consequence - passing -/// in the `Error` values - if they are, else runs the alternative passing in -/// all `Ok` and `Error` values. +/// Checks if any of the results are `Error` and runs the consequence - passing +/// in the `Ok` and `Error` values - if they are, else runs the alternative +/// passing in all `Ok` values. /// /// ## Examples /// @@ -537,28 +537,28 @@ pub fn error( /// /// let results = [Ok("Great"), Error("Bad")] /// -/// use errors <- given.all_error(in: results, else_return: fn(_oks, _errors) { "Only some Errors" }) +/// use _oks, _errors <- given.any_error(in: results, else_return: fn(_oks) { "Only OKs" }) /// -/// // …handle all errors here… -/// "All Errors" +/// // …handle at least some Errors here… +/// "At least some Errors" /// ``` /// -pub fn all_error( +pub fn any_error( in rslts: List(Result(a, e)), - else_return alternative: fn(List(a), List(e)) -> b, - return consequence: fn(List(e)) -> b, + else_return alternative: fn(List(a)) -> b, + return consequence: fn(List(a), List(e)) -> b, ) -> b { let #(oks, errors) = rslts |> result.partition - case oks { - [] -> alternative(oks, errors) - _non_zero_oks -> consequence(errors) + case errors { + [] -> alternative(oks) + _non_zero_errors -> consequence(oks, errors) } } -/// Checks if any of the results are `Error` and runs the consequence - passing -/// in the `Ok` and `Error` values - if they are, else runs the alternative -/// passing in all `Ok` values. +/// Checks if all of the results are `Error` and runs the consequence - passing +/// in the `Error` values - if they are, else runs the alternative passing in +/// all `Ok` and `Error` values. /// /// ## Examples /// @@ -567,19 +567,22 @@ pub fn all_error( /// /// let results = [Ok("Great"), Error("Bad")] /// -/// use oks, errors <- given.any_error(in: results, else_return: fn(_oks) { "Only OKs" }) +/// use _errors <- given.all_error(in: results, else_return: fn(_oks, _errors) { "Only some Errors" }) +/// +/// // …handle all errors here… +/// "All Errors" /// ``` /// -pub fn any_error( +pub fn all_error( in rslts: List(Result(a, e)), else_return alternative: fn(List(a), List(e)) -> b, return consequence: fn(List(e)) -> b, ) -> b { let #(oks, errors) = rslts |> result.partition - case errors { - [] -> alternative(oks, errors) - _non_zero_errors -> consequence(errors) + case oks { + [] -> consequence(errors) + _non_zero_oks -> alternative(oks, errors) } } @@ -620,9 +623,9 @@ pub fn some( } } -/// Checks if all of the options are `Some` and runs the consequence - passing -/// in the `Some` values - if they are, else runs the alternative passing in -/// the `Some` and a count of the `None` values. +/// Checks if any of the options are `Some` and runs the consequence - passing +/// in the `Some` values and a count of the `None` values - if they are, else +/// runs the alternative passing in the count of `None` values. /// /// ## Examples /// @@ -631,28 +634,28 @@ pub fn some( /// /// let options = [Some("One"), None] /// -/// use <- given.all_some(in: options, else_return: fn(_somes, _nones_count) { "Some are None" }) +/// use _somes, _nones_count <- given.any_some(in: options, else_return: fn(_nones_count) { "All are None" }) /// -/// // …handle all Some values here… -/// "All are Some" +/// // …handle at least some None values here… +/// "At least some are None" /// ``` /// -pub fn all_some( +pub fn any_some( in optns: List(Option(a)), - else_return alternative: fn(List(a), Int) -> b, - return consequence: fn(List(a)) -> b, + else_return alternative: fn(Int) -> b, + return consequence: fn(List(a), Int) -> b, ) -> b { let #(somes, nones_count) = optns |> optionx.partition - case nones_count { - 0 -> consequence(somes) - _positive_none_count -> alternative(somes, nones_count) + case somes { + [] -> alternative(nones_count) + _non_zero_somes -> consequence(somes, nones_count) } } -/// Checks if any of the options are `Some` and runs the consequence - passing -/// in the `Some` values and a count of the `None` values - if they are, else -/// runs the alternative passing in the count of `None` values. +/// Checks if all of the options are `Some` and runs the consequence - passing +/// in the `Some` values - if they are, else runs the alternative passing in +/// the `Some` and a count of the `None` values. /// /// ## Examples /// @@ -661,22 +664,22 @@ pub fn all_some( /// /// let options = [Some("One"), None] /// -/// use <- given.any_some(in: options, else_return: fn(_somes, _nones_count) { "All are None" }) +/// use _somes <- given.all_some(in: options, else_return: fn(_somes, _nones_count) { "Some are None" }) /// -/// // …handle at least some None values here… -/// "At least some are None" +/// // …handle all Some values here… +/// "All are Some" /// ``` /// -pub fn any_some( +pub fn all_some( in optns: List(Option(a)), - else_return alternative: fn(Int) -> b, - return consequence: fn(List(a), Int) -> b, + else_return alternative: fn(List(a), Int) -> b, + return consequence: fn(List(a)) -> b, ) -> b { let #(somes, nones_count) = optns |> optionx.partition - case somes { - [] -> alternative(nones_count) - _non_zero_somes -> consequence(somes, nones_count) + case nones_count { + 0 -> consequence(somes) + _positive_none_count -> alternative(somes, nones_count) } } @@ -717,8 +720,9 @@ pub fn none( } } -/// Checks if all of the options are `None` and runs the consequence if they -/// are, else runs the alternative passing in the `Some` values. +/// Checks if any of the options are `None` and runs the consequence if they +/// are, else runs the alternative passing in the `Some` values and the count +/// of `None` values. /// /// ## Examples /// @@ -727,28 +731,27 @@ pub fn none( /// /// let options = [Some("One"), None] /// -/// use <- given.all_none(in: options, else_return: fn(_somes, _nones_count) { "Some are Some" }) +/// use <- given.any_none(in: options, else_return: fn(_somes) { "All are Some" }) /// -/// // …handle all None values here… -/// "All are None" +/// // …handle at least some None values here… +/// "At least some are None" /// ``` /// -pub fn all_none( +pub fn any_none( in optns: List(Option(a)), - else_return alternative: fn(List(a), Int) -> b, - return consequence: fn() -> b, + else_return alternative: fn(List(a)) -> b, + return consequence: fn(List(a), Int) -> b, ) -> b { let #(somes, nones_count) = optns |> optionx.partition - case somes { - [] -> consequence() - _non_zero_somes -> alternative(somes, nones_count) + case nones_count { + 0 -> alternative(somes) + _positive_none_count -> consequence(somes, nones_count) } } -/// Checks if any of the options are `None` and runs the consequence if they -/// are, else runs the alternative passing in the `Some` values and the count -/// of `None` values. +/// Checks if all of the options are `None` and runs the consequence if they +/// are, else runs the alternative passing in the `Some` values. /// /// ## Examples /// @@ -757,21 +760,21 @@ pub fn all_none( /// /// let options = [Some("One"), None] /// -/// use <- given.any_none(in: options, else_return: fn(_somes) { "All are Some" }) +/// use <- given.all_none(in: options, else_return: fn(_somes, _nones_count) { "Some are Some" }) /// -/// // …handle at least some None values here… -/// "At least some are None" +/// // …handle all None values here… +/// "All are None" /// ``` /// -pub fn any_none( +pub fn all_none( in optns: List(Option(a)), - else_return alternative: fn(List(a)) -> b, - return consequence: fn(List(a), Int) -> b, + else_return alternative: fn(List(a), Int) -> b, + return consequence: fn() -> b, ) -> b { let #(somes, nones_count) = optns |> optionx.partition - case nones_count { - 0 -> alternative(somes) - _positive_none_count -> consequence(somes, nones_count) + case somes { + [] -> consequence() + _non_zero_somes -> alternative(somes, nones_count) } } diff --git a/src/given/lib/optionx.gleam b/src/given/internal/lib/optionx.gleam similarity index 64% rename from src/given/lib/optionx.gleam rename to src/given/internal/lib/optionx.gleam index 8ae16e3..f8a77b6 100644 --- a/src/given/lib/optionx.gleam +++ b/src/given/internal/lib/optionx.gleam @@ -1,9 +1,15 @@ +import gleam/list import gleam/option.{type Option, None, Some} +/// Similar to stdlib's result.partition, but for `Option` instead of `Result`. +/// /// Given a list of options, returns a pair where the first element is a list /// of all the values inside `Some` and the second element is a count of all -/// `None` values. The values in the returning list appear in reverse order -/// with respect to their position in the original list of options. +/// `None` values. +/// +/// In contrast to stdlib's result.partition the values in the returning list +/// DO NOT appear in reverse order with respect to their position in the +/// original list of options. /// /// ## Examples /// @@ -17,9 +23,11 @@ pub fn partition(options: List(Option(a))) -> #(List(a), Int) { } fn partition_loop(options: List(Option(a)), somes: List(a), none_count: Int) { - case options { + let #(somes, nones_count) = case options { [] -> #(somes, none_count) [Some(a), ..rest] -> partition_loop(rest, [a, ..somes], none_count) [None, ..rest] -> partition_loop(rest, somes, none_count + 1) } + + #(somes |> list.reverse, nones_count) } diff --git a/test/given_test.gleam b/test/given_test.gleam index 7b1cf8e..7d60de3 100644 --- a/test/given_test.gleam +++ b/test/given_test.gleam @@ -155,11 +155,27 @@ pub fn when_not_test() { } pub fn empty_test() { - todo + { + let list = [] + + use <- given.empty(list, else_return: fn() { "Non-empty" }) + + // …handle empty list here… + "Empty" + } + |> should.equal("Empty") } pub fn non_empty_test() { - todo + { + let list = [] + + use <- given.non_empty(list, else_return: fn() { "Empty" }) + + // …handle non-empty list here… + "Non-empty" + } + |> should.equal("Empty") } pub fn ok_test() { @@ -187,11 +203,29 @@ pub fn ok_test() { } pub fn any_ok_test() { - todo + { + let results = [Ok("Great"), Error("Bad")] + + use _oks, _errors <- given.any_ok(in: results, else_return: fn(_errors) { + "All Errors" + }) + + // …handle at least some OKs here… + "At least some OKs" + } } pub fn all_ok_test() { - todo + { + let results = [Ok("Great"), Error("Bad")] + + use _oks <- given.all_ok(in: results, else_return: fn(_oks, _errors) { + "Some Errors" + }) + + // …handle all OKs here… + "All OKs" + } } pub fn error_test() { @@ -221,11 +255,31 @@ pub fn error_test() { } pub fn any_error_test() { - todo + { + let results = [Ok("Great"), Error("Bad")] + + use _oks, _errors <- given.any_error(in: results, else_return: fn(_oks) { + "Only OKs" + }) + + // …handle at least some Errors here… + "At least some Errors" + } + |> should.equal("At least some Errors") } pub fn all_error_test() { - todo + { + let results = [Ok("Great"), Error("Bad")] + + use _errors <- given.all_error(in: results, else_return: fn(_oks, _errors) { + "Only some Errors" + }) + + // …handle all errors here… + "All Errors" + } + |> should.equal("Only some Errors") } pub fn some_test() { @@ -251,11 +305,31 @@ pub fn some_test() { } pub fn any_some_test() { - todo + { + let options = [Some("One"), None] + + use _somes, _nones_count <- given.any_some( + in: options, + else_return: fn(_nones_count) { "All are None" }, + ) + + // …handle at least some None values here… + "At least some are None" + } } pub fn all_some_test() { - todo + { + let options = [Some("One"), None] + + use _somes <- given.all_some( + in: options, + else_return: fn(_somes, _nones_count) { "Some are None" }, + ) + + // …handle all Some values here… + "All are Some" + } } pub fn none_test() { @@ -281,9 +355,28 @@ pub fn none_test() { } pub fn any_none_test() { - todo + { + let options = [Some("One"), None] + + use _somes, _none_count <- given.any_none( + in: options, + else_return: fn(_somes) { "All are Somes" }, + ) + + // …handle at least some None values here… + "At least some are None" + } } pub fn all_none_test() { - todo + { + let options = [Some("One"), None] + + use <- given.all_none(in: options, else_return: fn(_somes, _nones_count) { + "Some are Some" + }) + + // …handle all None values here… + "All are None" + } } diff --git a/test/internal/lib/optionx_test.gleam b/test/internal/lib/optionx_test.gleam new file mode 100644 index 0000000..aebb8cb --- /dev/null +++ b/test/internal/lib/optionx_test.gleam @@ -0,0 +1,11 @@ +import given/internal/lib/optionx +import gleam/option.{None, Some} +import gleeunit/should + +pub fn partition_test() { + { + [Some("Wibble"), None, None, Some("Wobble")] + |> optionx.partition + |> should.equal(#(["Wibble", "Wobble"], 2)) + } +} From 7ca1d2798643c1df0e5ae560217050addf33521c Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 20:10:54 +0100 Subject: [PATCH 14/15] fix examples --- CHANGELOG.md | 2 +- src/given.gleam | 6 +- src/given/internal/examples.gleam | 75 ------ src/given/internal/usage_examples.gleam | 314 ++++++++++++++++++++++++ test/given_test.gleam | 119 ++++----- 5 files changed, 379 insertions(+), 137 deletions(-) delete mode 100644 src/given/internal/examples.gleam create mode 100644 src/given/internal/usage_examples.gleam diff --git a/CHANGELOG.md b/CHANGELOG.md index bd5d7b1..9331f2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), - `given.when` to allow for more complex lazy conditions. - `given.when_not` to allow for more complex lazy conditions. - `given.empty` to check if a list is empty. - - `given.non_empty` to check if a list is not empty. + - `given.non_empty` to check if a list is non-empty. - `given.all_ok` to check if all results are ok. - `given.any_ok` to check if any results are ok. - `given.all_error` to check if all results are errors. diff --git a/src/given.gleam b/src/given.gleam index 4a7afdc..4c0ce42 100644 --- a/src/given.gleam +++ b/src/given.gleam @@ -346,7 +346,7 @@ pub fn when_not( /// /// let list = [] /// -/// use <- given.empty(list, else_return: fn() { "Not empty" }) +/// use <- given.empty(list, else_return: fn() { "Non-empty" }) /// /// // …handle empty list here… /// "Empty" @@ -363,7 +363,7 @@ pub fn empty( } } -/// Checks if the list is not empty and runs the consequence if it is, else +/// Checks if the list is non-empty and runs the consequence if it is, else /// runs the alternative. /// /// ## Examples @@ -376,7 +376,7 @@ pub fn empty( /// use <- given.non_empty(list, else_return: fn() { "Empty" }) /// /// // …handle non-empty list here… -/// "Not empty" +/// "Non-empty" /// ``` /// pub fn non_empty( diff --git a/src/given/internal/examples.gleam b/src/given/internal/examples.gleam deleted file mode 100644 index a1a4c57..0000000 --- a/src/given/internal/examples.gleam +++ /dev/null @@ -1,75 +0,0 @@ -import given.{not as not_given, that as given} - -// TODO: add new examples - -pub fn given_example() { - let user_understood = False - - use <- given(user_understood, return: fn() { "💡 Bright!" }) - // …else handle case where user did not understand here… - "🤯 Woof!" -} - -pub fn not_given_example() { - // Fetch this from some database - let has_admin_role = True - - use <- not_given(has_admin_role, return: fn() { "✋ Denied!" }) - // …else handle case where they are admin here… - "👌 Access granted..." -} - -pub fn given_ok_example() { - let a_result = Ok("Hello Joe, again!") - - use ok_value <- given.ok(in: a_result, else_return: fn(_error_value) { - "Error value" - }) - // …handle Ok value here… - ok_value -} - -pub fn given_error_example() { - let a_result = Error("Memory exhausted, again!") - - use error_value <- given.error(in: a_result, else_return: fn(_ok_value) { - "Ok value" - }) - // …handle Error value here… - error_value -} - -import gleam/option.{None, Some} - -pub fn given_some_example() { - let an_option = Some("One More Penny") - - use some_value <- given.some(in: an_option, else_return: fn() { "Woof!" }) - // …handle Some value here… - some_value -} - -pub fn given_none_example() { - let an_option = None - - use <- given.none(in: an_option, else_return: fn(_some_value) { "Some value" }) - // …handle None here… - "None, e.g. Still nothing!" -} - -import gleam/io - -pub fn main() { - given_example() |> io.debug - // "🤯 Woof!" - not_given_example() |> io.debug - // "👌 Access granted..." - given_ok_example() |> io.debug - // "Hello Joe, again!" - given_error_example() |> io.debug - // "Memory exhausted, again!" - given_some_example() |> io.debug - // "One More Penny" - given_none_example() |> io.debug - // "None, e.g. Still nothing" -} diff --git a/src/given/internal/usage_examples.gleam b/src/given/internal/usage_examples.gleam new file mode 100644 index 0000000..605fc5f --- /dev/null +++ b/src/given/internal/usage_examples.gleam @@ -0,0 +1,314 @@ +import given.{that as given} + +pub fn given_example() { + let user_understood = False + + use <- given(user_understood, return: fn() { "💡 Bright!" }) + // …else handle case where user did not understand here… + "🤯 Woof!" +} + +pub fn given_that_example() { + let user_understood = True + + use <- given.that(user_understood, return: fn() { "💡 Bright!" }) + // …else handle case where user did not understand here… + "🤯 Woof!" +} + +pub fn given_not_example() { + // Fetch this from some database + let has_admin_role = True + + use <- given.not(has_admin_role, return: fn() { "✋ Denied!" }) + // …else handle case where they are admin here… + "👌 Access granted..." +} + +pub fn given_any_example() { + let is_admin = False + let is_editor = True + + use <- given.any([is_admin, is_editor], return: fn() { + "At least admin or editor" + }) + + // …else handle case where user has no special role… + "Got nothing to say 🤷‍♂️" +} + +pub fn given_all_example() { + let is_active = True + let is_confirmed = False + + use <- given.all([is_active, is_confirmed], return: fn() { + "Ready, steady, go!" + }) + + // …else handle case where user is not both active and confirmed… + "Not both active and confirmed" +} + +pub fn given_not_any_example() { + let is_admin = False + let is_editor = True + + use <- given.not_any([is_admin, is_editor], return: fn() { + "At least either Admin or Editor!" + }) + + // …else handle case where user no special role… + "User has no special role!" +} + +pub fn given_not_all_example() { + let is_human = False + let is_robot = False + + use <- given.not_all([is_human, is_robot], return: fn() { + "Obsolete model detected." + }) + + // …else handle case where user is neither active nor confirmed… + "I am a Cylon!" +} + +pub fn given_when_example() { + let enabled = fn() { True } + + use <- given.when(enabled, else_return: fn() { "Not an Admin" }) + + // …handle case where user is an Admin… + "Indeed an Admin" +} + +pub fn given_when_not_example() { + let enabled = fn() { False } + + use <- given.when_not(enabled, else_return: fn() { "Indeed an Admin" }) + + // …handle case where user is not an Admin… + "Not an Admin" +} + +pub fn given_empty_example() { + let list = [] + + use <- given.empty(list, return: fn() { "Empty!" }) + + // …handle case where user is non-empty… + "Non-empty!" +} + +pub fn given_non_empty_example() { + let list = [1] + + use <- given.non_empty(list, return: fn() { "Non-empty!" }) + + // …handle case where user is empty… + "Empty!" +} + +pub fn given_ok_example() { + let a_result = Ok("Hello Joe, again!") + + use ok_value <- given.ok(in: a_result, else_return: fn(_error_value) { + "Error value" + }) + // …handle Ok value here… + ok_value +} + +pub fn given_any_ok_example() { + let results = [Ok("Great"), Error("Bad")] + + use _oks, _errors <- given.any_ok(in: results, else_return: fn(_errors) { + "All Errors" + }) + + // …handle at least some OKs here… + "At least some OKs" +} + +pub fn given_all_ok_example() { + let results = [Ok("Great"), Error("Bad")] + + use _oks <- given.all_ok(in: results, else_return: fn(_oks, _errors) { + "Some Errors" + }) + + // …handle all OKs here… + "All OKs" +} + +pub fn given_error_example() { + let a_result = Error("Memory exhausted, again!") + + use error_value <- given.error(in: a_result, else_return: fn(_ok_value) { + "Ok value" + }) + // …handle Error value here… + error_value +} + +pub fn given_any_error_example() { + let results = [Ok("Good"), Error("Bad")] + + use _oks, _errors <- given.any_error(in: results, else_return: fn(_oks) { + "Bad" + }) + + // …handle at least some Errors here… + "Good" +} + +pub fn given_all_error_example() { + { + let results = [Ok("Nice"), Error("Meh")] + + use _errors <- given.all_error(in: results, else_return: fn(_oks, _errors) { + "Meh" + }) + + // …handle all errors here… + "Nice" + } +} + +import gleam/option.{None, Some} + +pub fn given_some_example() { + let an_option = Some("One More Penny") + + use some_value <- given.some(in: an_option, else_return: fn() { "Woof!" }) + // …handle Some value here… + some_value +} + +pub fn given_any_some_example() { + let options = [Some("One"), None] + + use _somes, _nones_count <- given.any_some( + in: options, + else_return: fn(_nones_count) { "Just rocks here, move on..." }, + ) + + // …handle at least some None values here… + "We found some Gold!" +} + +pub fn given_all_some_example() { + let options = [Some("One"), None] + + use _somes <- given.all_some( + in: options, + else_return: fn(_somes, _nones_count) { "Nothing found..." }, + ) + + // …handle all Some values here… + "There is Gold everywhere!" +} + +pub fn given_none_example() { + let an_option = None + + use <- given.none(in: an_option, else_return: fn(_some_value) { "Some value" }) + // …handle None here… + "None, e.g. Still nothing!" +} + +pub fn given_any_none_example() { + let options = [Some("One"), None] + + use _somes, _none_count <- given.any_none( + in: options, + else_return: fn(_somes) { "Only Nones Here!" }, + ) + + // …handle at least some None values here… + "The system detected Some-things." +} + +pub fn given_all_none_example() { + let options = [Some("One"), None] + + use <- given.all_none(in: options, else_return: fn(_somes, _nones_count) { + "There is something out there..." + }) + + // …handle all None values here… + "There is nothing out there..." +} + +import gleam/io + +pub fn main() { + given_example() |> io.debug + // "🤯 Woof!" + + given_that_example() |> io.debug + // "💡 Bright!" + + given_any_example() |> io.debug + // "At least admin or editor" + + given_all_example() |> io.debug + // "Not both active and confirmed" + + given_not_example() |> io.debug + // "👌 Access granted..." + + given_not_any_example() |> io.debug + // "User has no special role!" + + given_not_all_example() |> io.debug + // "Obsolete model detected." + + given_when_example() |> io.debug + // "Indeed an Admin" + + given_when_not_example() |> io.debug + // "Not an Admin" + + given_empty_example() |> io.debug + // "Empty!" + + given_non_empty_example() |> io.debug + // "Non-empty!" + + given_ok_example() |> io.debug + // "Hello Joe, again!" + + given_any_ok_example() |> io.debug + // "At least some OKs" + + given_all_ok_example() |> io.debug + // "Some Errors" + + given_error_example() |> io.debug + // "Memory exhausted, again!" + + given_any_error_example() |> io.debug + // "Good" + + given_all_error_example() |> io.debug + // "Meh" + + given_some_example() |> io.debug + // "One More Penny" + + given_any_some_example() |> io.debug + // "We found some Gold!" + + given_all_some_example() |> io.debug + // "Nothing found..." + + given_none_example() |> io.debug + // "None, e.g. Still nothing" + + given_any_none_example() |> io.debug + // "The system detected Some-things." + + given_all_none_example() |> io.debug + // "There is something out there..." +} diff --git a/test/given_test.gleam b/test/given_test.gleam index 7d60de3..4795a27 100644 --- a/test/given_test.gleam +++ b/test/given_test.gleam @@ -86,14 +86,12 @@ pub fn not_any_test() { let is_admin = False let is_editor = True - use <- given.not_any([is_admin, is_editor], return: fn() { - "At least either Admin or Editor!" - }) + use <- given.not_any([is_admin, is_editor], return: fn() { great }) // …else handle case where user no special role… - "User has no special role!" + woof } - |> should.equal("User has no special role!") + |> should.equal(woof) } pub fn not_all_test() { @@ -101,81 +99,80 @@ pub fn not_all_test() { let is_human = False let is_robot = False - use <- given.not_all([is_human, is_robot], return: fn() { - "Obsolete model detected." - }) + use <- given.not_all([is_human, is_robot], return: fn() { great }) // …else handle case where user is neither active nor confirmed… - "I am a Cylon!" + woof } - |> should.equal("Obsolete model detected.") + |> should.equal(great) } pub fn when_test() { { let enabled = fn() { False } - use <- given.when(enabled, else_return: fn() { "Not an Admin" }) + use <- given.when(enabled, return: fn() { great }) - // …handle case where user is an Admin… - "Indeed an Admin" + // …handle case where user is not an Admin… + woof } - |> should.equal("Not an Admin") + |> should.equal(woof) { let enabled = fn() { False } - use <- given.when(enabled, return: fn() { "Indeed an Admin" }) + use <- given.when(enabled, else_return: fn() { great }) - // …handle case where user is not an Admin… - "Not an Admin" + // …handle case where user is an Admin… + woof } - |> should.equal("Not an Admin") + |> should.equal(great) } pub fn when_not_test() { { let enabled = fn() { False } - use <- given.when_not(enabled, else_return: fn() { "Indeed an Admin" }) + use <- given.when_not(enabled, else_return: fn() { great }) // …handle case where user is an Admin… - "Not an Admin" + woof } - |> should.equal("Not an Admin") - // { - // let enabled = fn() { False } + |> should.equal(woof) + + { + let enabled = fn() { False } - // use <- given.when_not(enabled, return: fn() { "Not an Admin" }) + use <- given.when_not(enabled, return: fn() { great }) - // // …handle case where user is not an Admin… - // "Indeed an Admin" - // } - // |> should.equal("Not an Admin") + // …handle case where user is not an Admin… + woof + } + |> should.equal(great) } pub fn empty_test() { { let list = [] - use <- given.empty(list, else_return: fn() { "Non-empty" }) + use <- given.empty(list, else_return: fn() { woof }) // …handle empty list here… - "Empty" + great } - |> should.equal("Empty") + |> should.equal(great) } pub fn non_empty_test() { { let list = [] - use <- given.non_empty(list, else_return: fn() { "Empty" }) + use <- given.non_empty(list, else_return: fn() { woof }) // …handle non-empty list here… - "Non-empty" + great } - |> should.equal("Empty") + |> should.equal(woof) } pub fn ok_test() { @@ -207,12 +204,13 @@ pub fn any_ok_test() { let results = [Ok("Great"), Error("Bad")] use _oks, _errors <- given.any_ok(in: results, else_return: fn(_errors) { - "All Errors" + woof }) // …handle at least some OKs here… - "At least some OKs" + great } + |> should.equal(great) } pub fn all_ok_test() { @@ -220,12 +218,13 @@ pub fn all_ok_test() { let results = [Ok("Great"), Error("Bad")] use _oks <- given.all_ok(in: results, else_return: fn(_oks, _errors) { - "Some Errors" + woof }) // …handle all OKs here… - "All OKs" + great } + |> should.equal(woof) } pub fn error_test() { @@ -259,13 +258,13 @@ pub fn any_error_test() { let results = [Ok("Great"), Error("Bad")] use _oks, _errors <- given.any_error(in: results, else_return: fn(_oks) { - "Only OKs" + woof }) // …handle at least some Errors here… - "At least some Errors" + great } - |> should.equal("At least some Errors") + |> should.equal(great) } pub fn all_error_test() { @@ -273,13 +272,13 @@ pub fn all_error_test() { let results = [Ok("Great"), Error("Bad")] use _errors <- given.all_error(in: results, else_return: fn(_oks, _errors) { - "Only some Errors" + woof }) // …handle all errors here… - "All Errors" + great } - |> should.equal("Only some Errors") + |> should.equal(woof) } pub fn some_test() { @@ -310,12 +309,13 @@ pub fn any_some_test() { use _somes, _nones_count <- given.any_some( in: options, - else_return: fn(_nones_count) { "All are None" }, + else_return: fn(_nones_count) { woof }, ) // …handle at least some None values here… - "At least some are None" + great } + |> should.equal(great) } pub fn all_some_test() { @@ -324,34 +324,35 @@ pub fn all_some_test() { use _somes <- given.all_some( in: options, - else_return: fn(_somes, _nones_count) { "Some are None" }, + else_return: fn(_somes, _nones_count) { woof }, ) // …handle all Some values here… - "All are Some" + great } + |> should.equal(woof) } pub fn none_test() { { let option = Some(great) - use <- given.none(in: option, else_return: fn(_some_value) { great }) + use <- given.none(in: option, else_return: fn(_some_value) { woof }) // …user handles None here… - woof + great } - |> should.equal(great) + |> should.equal(woof) { let option = None - use <- given.none(in: option, else_return: fn(_some_value) { great }) + use <- given.none(in: option, else_return: fn(_some_value) { woof }) // …user handles None here… - "None encountered!" + great } - |> should.equal("None encountered!") + |> should.equal(great) } pub fn any_none_test() { @@ -360,12 +361,13 @@ pub fn any_none_test() { use _somes, _none_count <- given.any_none( in: options, - else_return: fn(_somes) { "All are Somes" }, + else_return: fn(_somes) { woof }, ) // …handle at least some None values here… - "At least some are None" + great } + |> should.equal(great) } pub fn all_none_test() { @@ -373,10 +375,11 @@ pub fn all_none_test() { let options = [Some("One"), None] use <- given.all_none(in: options, else_return: fn(_somes, _nones_count) { - "Some are Some" + woof }) // …handle all None values here… - "All are None" + great } + |> should.equal(woof) } From aa9019569d254e833c56af5c29214e20d8865523 Mon Sep 17 00:00:00 2001 From: inoas Date: Thu, 16 Jan 2025 20:12:39 +0100 Subject: [PATCH 15/15] examples --- README.md | 304 +++++++++++++++++++++++- src/given/internal/usage_examples.gleam | 13 +- 2 files changed, 304 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f612de3..e261292 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,309 @@ gleam add given ## Usage ```gleam -# TODO: Copy src/given/internal/examples.gleam +import given + +pub fn given_that_example() { + let user_understood = True + + use <- given.that(user_understood, return: fn() { "💡 Bright!" }) + // …else handle case where user did not understand here… + "🤯 Woof!" +} + +pub fn given_not_example() { + // Fetch this from some database + let has_admin_role = True + + use <- given.not(has_admin_role, return: fn() { "✋ Denied!" }) + // …else handle case where they are admin here… + "👌 Access granted..." +} + +pub fn given_any_example() { + let is_admin = False + let is_editor = True + + use <- given.any([is_admin, is_editor], return: fn() { + "At least admin or editor" + }) + + // …else handle case where user has no special role… + "Got nothing to say 🤷‍♂️" +} + +pub fn given_all_example() { + let is_active = True + let is_confirmed = False + + use <- given.all([is_active, is_confirmed], return: fn() { + "Ready, steady, go!" + }) + + // …else handle case where user is not both active and confirmed… + "Not both active and confirmed" +} + +pub fn given_not_any_example() { + let is_admin = False + let is_editor = True + + use <- given.not_any([is_admin, is_editor], return: fn() { + "At least either Admin or Editor!" + }) + + // …else handle case where user no special role… + "User has no special role!" +} + +pub fn given_not_all_example() { + let is_human = False + let is_robot = False + + use <- given.not_all([is_human, is_robot], return: fn() { + "Obsolete model detected." + }) + + // …else handle case where user is neither active nor confirmed… + "I am a Cylon!" +} + +pub fn given_when_example() { + let enabled = fn() { True } + + use <- given.when(enabled, else_return: fn() { "Not an Admin" }) + + // …handle case where user is an Admin… + "Indeed an Admin" +} + +pub fn given_when_not_example() { + let enabled = fn() { False } + + use <- given.when_not(enabled, else_return: fn() { "Indeed an Admin" }) + + // …handle case where user is not an Admin… + "Not an Admin" +} + +pub fn given_empty_example() { + let list = [] + + use <- given.empty(list, return: fn() { "Empty!" }) + + // …handle case where user is non-empty… + "Non-empty!" +} + +pub fn given_non_empty_example() { + let list = [1] + + use <- given.non_empty(list, return: fn() { "Non-empty!" }) + + // …handle case where user is empty… + "Empty!" +} + +pub fn given_ok_example() { + let a_result = Ok("Hello Joe, again!") + + use ok_value <- given.ok(in: a_result, else_return: fn(_error_value) { + "Error value" + }) + // …handle Ok value here… + ok_value +} + +pub fn given_any_ok_example() { + let results = [Ok("Great"), Error("Bad")] + + use _oks, _errors <- given.any_ok(in: results, else_return: fn(_errors) { + "All Errors" + }) + + // …handle at least some OKs here… + "At least some OKs" +} + +pub fn given_all_ok_example() { + let results = [Ok("Great"), Error("Bad")] + + use _oks <- given.all_ok(in: results, else_return: fn(_oks, _errors) { + "Some Errors" + }) + + // …handle all OKs here… + "All OKs" +} + +pub fn given_error_example() { + let a_result = Error("Memory exhausted, again!") + + use error_value <- given.error(in: a_result, else_return: fn(_ok_value) { + "Ok value" + }) + // …handle Error value here… + error_value +} + +pub fn given_any_error_example() { + let results = [Ok("Good"), Error("Bad")] + + use _oks, _errors <- given.any_error(in: results, else_return: fn(_oks) { + "Bad" + }) + + // …handle at least some Errors here… + "Good" +} + +pub fn given_all_error_example() { + { + let results = [Ok("Nice"), Error("Meh")] + + use _errors <- given.all_error(in: results, else_return: fn(_oks, _errors) { + "Meh" + }) + + // …handle all errors here… + "Nice" + } +} + +import gleam/option.{None, Some} + +pub fn given_some_example() { + let an_option = Some("One More Penny") + + use some_value <- given.some(in: an_option, else_return: fn() { "Woof!" }) + // …handle Some value here… + some_value +} + +pub fn given_any_some_example() { + let options = [Some("One"), None] + + use _somes, _nones_count <- given.any_some( + in: options, + else_return: fn(_nones_count) { "Just rocks here, move on..." }, + ) + + // …handle at least some None values here… + "We found some Gold!" +} + +pub fn given_all_some_example() { + let options = [Some("One"), None] + + use _somes <- given.all_some( + in: options, + else_return: fn(_somes, _nones_count) { "Nothing found..." }, + ) + + // …handle all Some values here… + "There is Gold everywhere!" +} + +pub fn given_none_example() { + let an_option = None + + use <- given.none(in: an_option, else_return: fn(_some_value) { "Some value" }) + // …handle None here… + "None, e.g. Still nothing!" +} + +pub fn given_any_none_example() { + let options = [Some("One"), None] + + use _somes, _none_count <- given.any_none( + in: options, + else_return: fn(_somes) { "Only Nones Here!" }, + ) + + // …handle at least some None values here… + "The system detected Some-things." +} + +pub fn given_all_none_example() { + let options = [Some("One"), None] + + use <- given.all_none(in: options, else_return: fn(_somes, _nones_count) { + "There is something out there..." + }) + + // …handle all None values here… + "There is nothing out there..." +} + +import gleam/io + +pub fn main() { + given_that_example() |> io.debug + // "💡 Bright!" + + given_any_example() |> io.debug + // "At least admin or editor" + + given_all_example() |> io.debug + // "Not both active and confirmed" + + given_not_example() |> io.debug + // "👌 Access granted..." + + given_not_any_example() |> io.debug + // "User has no special role!" + + given_not_all_example() |> io.debug + // "Obsolete model detected." + + given_when_example() |> io.debug + // "Indeed an Admin" + + given_when_not_example() |> io.debug + // "Not an Admin" + + given_empty_example() |> io.debug + // "Empty!" + + given_non_empty_example() |> io.debug + // "Non-empty!" + + given_ok_example() |> io.debug + // "Hello Joe, again!" + + given_any_ok_example() |> io.debug + // "At least some OKs" + + given_all_ok_example() |> io.debug + // "Some Errors" + + given_error_example() |> io.debug + // "Memory exhausted, again!" + + given_any_error_example() |> io.debug + // "Good" + + given_all_error_example() |> io.debug + // "Meh" + + given_some_example() |> io.debug + // "One More Penny" + + given_any_some_example() |> io.debug + // "We found some Gold!" + + given_all_some_example() |> io.debug + // "Nothing found..." + + given_none_example() |> io.debug + // "None, e.g. Still nothing" + + given_any_none_example() |> io.debug + // "The system detected Some-things." + + given_all_none_example() |> io.debug + // "There is something out there..." +} ``` ### Run usage examples diff --git a/src/given/internal/usage_examples.gleam b/src/given/internal/usage_examples.gleam index 605fc5f..bb3cb96 100644 --- a/src/given/internal/usage_examples.gleam +++ b/src/given/internal/usage_examples.gleam @@ -1,12 +1,4 @@ -import given.{that as given} - -pub fn given_example() { - let user_understood = False - - use <- given(user_understood, return: fn() { "💡 Bright!" }) - // …else handle case where user did not understand here… - "🤯 Woof!" -} +import given pub fn given_that_example() { let user_understood = True @@ -243,9 +235,6 @@ pub fn given_all_none_example() { import gleam/io pub fn main() { - given_example() |> io.debug - // "🤯 Woof!" - given_that_example() |> io.debug // "💡 Bright!"