From 0355d557e39a63458c3acbf2a3f5ba93cdd28a06 Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Sat, 10 Jun 2023 18:53:03 +0200 Subject: [PATCH] feat: rename ReturnIfErr to Eh --- README.md | 19 +++++++++++-------- eh.go | 16 ++++++++-------- eh_test.go | 37 ++++++++++++++++--------------------- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 3c7e155..d7bf918 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,12 @@ func example(aFile string) []byte, error { Into this: ```go -func example(aFile string) (res Result[[]byte]) { - defer EscapeHatch(&res) // must have pointer to the named output Result +func example(aFile string) (res eh.Result[[]byte]) { + defer eh.EscapeHatch(&res) // must have pointer to the named output Result buff := make([]byte, 5) - file := NewResult(os.Open(aFile)).ReturnIfErr().Ok - NewResult(file.Read(buff)).ReturnIfErr() - return Result[[]byte]{Ok: buff} + file := eh.NewResult(os.Open(aFile)).Eh() + _ = eh.NewResult(file.Read(buff)).Eh() + return eh.Result[[]byte]{Ok: buff} } ``` @@ -49,8 +49,11 @@ For a successful operation the output is like this: The library provides just a handful or public structs and functions: - `Result` structs to capture an outcome that can potentially result in an error -- `ReturnIfErr` function (`?` was not possible) that will stop the current function from executing - if there is an error and return a `Result` that contains the error. +- `Eh` method (`?` was not possible) that will stop the current function from executing + if there is an error and return a `Result` that contains the error. If there is no error the `Result` + is unwrapped and the `Ok` value is returned. Just like Canadians add "eh" to the end of a sentence + to make it a question, you can call `Eh` on a `Result` to get a similar functionality to the question + mark operator. - `EscapeHatch` function that should be deferred and given access to the enclosing function named `Result` argument so that the error can be recovered and the enclosed function can be interrupted early if an error occurs. @@ -61,5 +64,5 @@ A few simple steps to incorporate in your code: 1. Return a named `Result` from your fuction 2. `defer` the `EscapeHatch` function with pointer to the named `Result` argument 3. Wrap functions that return `any, error` into `eh.NewResult` to get `Result` -4. Call `ReturnIfErr()` on any `Result` to stop the execution if there is an error +4. Call `Eh()` on any `Result` to stop the execution if there is an error and return `Result{Err: Error}` from the enclosing function. diff --git a/eh.go b/eh.go index 252be25..1943ceb 100644 --- a/eh.go +++ b/eh.go @@ -29,25 +29,25 @@ func NewResult[T any](val T, err error) Result[T] { return Result[T]{val, err} } -// ReturnIfErr checks if there is an error in the result and if so then it will -// panic with the error that was encountered. -func (r Result[T]) ReturnIfErr() Result[T] { +// Eh checks if there is an error in the result and if so then it will +// panic with the error that was encountered. If there is no error the Ok value is returned. +func (r Result[T]) Eh() T { if r.Err != nil { panic(ehError{r.Err}) } - return r + return r.Ok } -// Unwrap returns the Ok value or panics if there is an error. -func (r Result[T]) Unwrap() T { +// MustUnwrap returns the Ok value or panics if there is an error. +func (r Result[T]) MustUnwrap() T { if r.Err != nil { panic(r.Err) } return r.Ok } -// UnwrapErr returns the Err value or panics if there is no error. -func (r Result[T]) UnwrapErr() error { +// MustUnwrapErr returns the Err value or panics if there is no error. +func (r Result[T]) MustUnwrapErr() error { if r.Err == nil { panic("expected the result to contain error") } diff --git a/eh_test.go b/eh_test.go index 8acba88..27f8e9a 100644 --- a/eh_test.go +++ b/eh_test.go @@ -30,27 +30,22 @@ func divide(x int, y int) (int, error) { func doDivide(x int, y int) (res Result[int]) { defer EscapeHatch(&res) - res = NewResult(divide(x, y)).ReturnIfErr() - return res + return NewResult(divide(x, y)) } func doDivideMultiple(x int, y int) (res Result[int]) { defer EscapeHatch(&res) - res = NewResult(divide(x, y)).ReturnIfErr() - res = NewResult(divide(x*2, y+2)).ReturnIfErr() - return res + val := NewResult(divide(x, y)).Eh() + return NewResult(divide(val+2, y)) } func doDivideGoRoutine(x int, y int, res *Result[int], wg *sync.WaitGroup) { defer wg.Done() - defer EscapeHatch(res) - *res = NewResult(divide(x, y)).ReturnIfErr() + *res = NewResult(divide(x, y)) } -func doDividePtr(x int, y int) (res *Result[int]) { - defer EscapeHatch(res) - ares := NewResult(divide(x, y)).ReturnIfErr() - return &ares +func doDividePtr(x int, y int) (res Result[int]) { + return NewResult(divide(x, y)) } func TestSimple(t *testing.T) { @@ -131,8 +126,8 @@ func TestSimpleResultMultipleFail(t *testing.T) { func example(aFile string) (res Result[[]byte]) { defer EscapeHatch(&res) buff := make([]byte, 5) - file := NewResult(os.Open(aFile)).ReturnIfErr().Ok - NewResult(file.Read(buff)).ReturnIfErr() + file := NewResult(os.Open(aFile)).Eh() + _ = NewResult(file.Read(buff)).Eh() return Result[[]byte]{Ok: buff} } @@ -150,33 +145,33 @@ func TestExampleFail(t *testing.T) { } } -func TestUnwrap(t *testing.T) { +func TestMustUnwrap(t *testing.T) { res := Result[int]{Ok: 1} - ok := res.Unwrap() + ok := res.MustUnwrap() if ok != 1 { t.Fatal("Unwrap should return 1") } } -func TestUnwrapPanic(t *testing.T) { +func TestMustUnwrapPanic(t *testing.T) { res := Result[int]{Err: fmt.Errorf("error")} defer func() { recover() }() - _ = res.Unwrap() + _ = res.MustUnwrap() t.Fatal("code should have panicked") } -func TestUnwrapErr(t *testing.T) { +func TestMustUnwrapErr(t *testing.T) { aErr := fmt.Errorf("error") res := Result[int]{Err: aErr} - err := res.UnwrapErr() + err := res.MustUnwrapErr() if err != aErr { t.Fatal("UnwrapErr should return error") } } -func TestUnwrapErrPanic(t *testing.T) { +func TestMustUnwrapErrPanic(t *testing.T) { res := Result[int]{Ok: 1} defer func() { recover() }() - _ = res.UnwrapErr() + _ = res.MustUnwrapErr() t.Fatal("code should have panicked") }