Current section
Files
Jump to
Current section
Files
src/outcome.gleam
import gleam/result
import gleam/string
import outcome/problem.{type Problem, type Severity, Defect, Failure, Problem}
/// Alias to Result with Problem as error type.
pub type Outcome(t, err) =
Result(t, Problem(err))
/// Convert `Result(a, e)` to `Result(a, Problem(e))`
/// with severity as `Defect`
///
/// ## Example
///
/// ```gleam
/// Error("Something went wrong")
/// |> outcome.as_defect
/// ```
pub fn as_defect(result: Result(t, err)) -> Outcome(t, err) {
result.map_error(result, problem.new_defect)
}
/// Convert `Result(a, e)` to `Result(a, Problem(e))`
/// with severity as `Failure`.
///
/// ## Example
///
/// ```gleam
/// Error("Invalid input")
/// |> outcome.as_failure
/// ```
pub fn as_failure(result: Result(t, err)) -> Outcome(t, err) {
result.map_error(result, problem.new_failure)
}
/// Map the error value
pub fn map_error(
outcome: Outcome(t, err),
mapper: fn(err) -> err,
) -> Outcome(t, err) {
result.map_error(outcome, problem.map_error(_, mapper))
}
// *************************
// Tap
// *************************
/// Use tap functions to log the errors.
/// This yields the `Problem` type.
pub fn tap(
outcome: Outcome(t, err),
fun: fn(Problem(err)) -> any,
) -> Outcome(t, err) {
result.map_error(outcome, fn(problem) {
fun(problem)
problem
})
}
/// This yields your error type.
pub fn tap_error(
outcome: Outcome(t, err),
fun: fn(err) -> any,
) -> Outcome(t, err) {
result.map_error(outcome, problem.tap_error(_, fun))
}
/// Yield your error type.
/// Only called if the severity is Defect.
pub fn tap_defect(
outcome: Outcome(t, err),
fun: fn(err) -> any,
) -> Outcome(t, err) {
result.map_error(outcome, problem.tap_defect(_, fun))
}
/// Yield your error type.
/// Only called if the severity is Failure.
pub fn tap_failure(
outcome: Outcome(t, err),
fun: fn(err) -> any,
) -> Outcome(t, err) {
result.map_error(outcome, problem.tap_failure(_, fun))
}
/// Add context to an Outcome.
/// This will add a Context entry to the stack.
///
/// ## Example
///
/// ```gleam
/// Error("Something went wrong")
/// |> outcome.as_defect
/// |> outcome.context("In find user function")
/// ```
///
pub fn context(
outcome outcome: Outcome(t, err),
context context: String,
) -> Outcome(t, err) {
result.map_error(outcome, problem.add_context(_, context))
}
/// Remove the `Problem` wrapping in the error value
///
/// ## Example
///
/// ```gleam
/// let result = Error("Fail") |> outcome.as_defect
///
/// outcome.to_simple_result(result) == Error("Fail")
/// ```
pub fn to_simple_result(outcome: Outcome(t, err)) -> Result(t, err) {
outcome |> result.map_error(problem.extract_error)
}
// *************************
// Print
// *************************
/// Pretty print a Problem, including the stack.
/// The latest problem appears at the top of the stack.
///
/// ## Example
///
/// ```gleam
/// Error("Something went wrong")
/// |> outcome.as_defect
/// |> outcome.context("In find user function")
/// |> outcome.context("More context")
/// |> outcome.pretty_print(function.identity)
/// ```
///
/// ```
/// Defect: Something went wrong
///
/// stack:
/// In find user function
/// More context
/// ```
pub fn pretty_print(problem: Problem(err), to_s: fn(err) -> String) -> String {
pretty_print_with_joins(problem, "\n\nstack:\n ", "\n ", to_s)
}
/// Print problem in one line
///
/// ## Example
///
/// ```gleam
/// Error("Something went wrong")
/// |> outcome.as_defect
/// |> outcome.context("In find user function")
/// |> outcome.print_line(function.identity)
/// ```
///
/// ```
/// Defect: Something went wrong < In find user function
/// ```
pub fn print_line(problem: Problem(err), to_s: fn(err) -> String) -> String {
pretty_print_with_joins(problem, " < ", " < ", to_s)
}
fn pretty_print_with_joins(
problem: Problem(err),
join_current: String,
join_stack: String,
to_s: fn(err) -> String,
) -> String {
let current =
prettry_print_problem_error(problem.severity, to_s(problem.error))
let stack =
join_current
<> problem.stack
|> problem.stack_to_lines
|> string.join(join_stack)
let stack = case problem.stack {
[] -> ""
_ -> stack
}
current <> stack
}
fn prettry_print_problem_error(severity: Severity, error: String) -> String {
long_suffix(severity) <> error
}
fn long_suffix(severity: Severity) -> String {
case severity {
Defect -> "Defect: "
Failure -> "Failure: "
}
}