Skip to content

Commit

Permalink
Merge pull request #43 from taman9333/do-notation
Browse files Browse the repository at this point in the history
Do notation
  • Loading branch information
samber authored Jun 22, 2024
2 parents 81dbcaf + bf79005 commit b216a39
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
22 changes: 22 additions & 0 deletions do.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package mo

import (
"errors"
"fmt"
)

// Do executes a function within a monadic context, capturing any errors that occur.
// If the function executes successfully, its result is wrapped in a successful Result.
// If the function panics (indicating a failure), the panic is caught and converted into an error Result.
func Do[T any](fn func() T) (result Result[T]) {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(error); ok {
result = Err[T](err)
} else {
result = Err[T](errors.New(fmt.Sprint(r)))
}
}
}()
return Ok(fn())
}
116 changes: 116 additions & 0 deletions do_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package mo

import (
"errors"
"testing"

"github.com/stretchr/testify/assert"
)

func TestDo_Success(t *testing.T) {
is := assert.New(t)

result := Do(func() string {
return "Hello, World!"
})

is.False(result.IsError())
is.Equal("Hello, World!", result.MustGet())
}

func TestDo_Error(t *testing.T) {
is := assert.New(t)

result := Do(func() string {
panic(errors.New("something went wrong"))
})

is.True(result.IsError())
is.EqualError(result.Error(), "something went wrong")
}

func TestDo_ComplexSuccess(t *testing.T) {
is := assert.New(t)

validateBooking := func(params map[string]string) Result[map[string]string] {
if params["guest"] != "" && params["roomType"] != "" {
return Ok(params)
}
return Err[map[string]string](errors.New("validation failed"))
}

createBooking := func(guest string) Result[string] {
if guest != "" {
return Ok("Booking Created for: " + guest)
}
return Err[string](errors.New("booking creation failed"))
}

assignRoom := func(booking string, roomType string) Result[string] {
if roomType != "" {
return Ok("Room Assigned: " + roomType + " for " + booking)
}
return Err[string](errors.New("room assignment failed"))
}

bookRoom := func(params map[string]string) Result[[]string] {
return Do(func() []string {
values := validateBooking(params).MustGet()
booking := createBooking(values["guest"]).MustGet()
room := assignRoom(booking, values["roomType"]).MustGet()
return []string{booking, room}
})
}

params := map[string]string{
"guest": "Foo Bar",
"roomType": "Suite",
}

result := bookRoom(params)
is.False(result.IsError())
is.Equal([]string{"Booking Created for: Foo Bar", "Room Assigned: Suite for Booking Created for: Foo Bar"}, result.MustGet())
}

func TestDo_ComplexError(t *testing.T) {
is := assert.New(t)

validateBooking := func(params map[string]string) Result[map[string]string] {
if params["guest"] != "" && params["roomType"] != "" {
return Ok(params)
}
return Err[map[string]string](errors.New("validation failed"))
}

createBooking := func(guest string) Result[string] {
if guest != "" {
return Ok("Booking Created for: " + guest)
}
return Err[string](errors.New("booking creation failed"))
}

assignRoom := func(booking string, roomType string) Result[string] {
if roomType != "" {
return Ok("Room Assigned: " + roomType + " for " + booking)
}
return Err[string](errors.New("room assignment failed"))
}

bookRoom := func(params map[string]string) Result[[]string] {
return Do(func() []string {
values := validateBooking(params).MustGet()
booking := createBooking(values["guest"]).MustGet()
room := assignRoom(booking, values["roomType"]).MustGet()
return []string{booking, room}
})
}

params := map[string]string{
"guest": "",
"roomType": "Suite",
}

result := bookRoom(params)
is.True(result.IsError())
is.EqualError(result.Error(), "validation failed")
}

0 comments on commit b216a39

Please sign in to comment.