Skip to content

Commit

Permalink
Merge pull request #3 from jaavier/dev
Browse files Browse the repository at this point in the history
Channels, Context, Verbose Output and Documentation
  • Loading branch information
jaavier authored Jul 28, 2023
2 parents 23f8553 + 5633e17 commit afd61b1
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 39 deletions.
177 changes: 150 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,173 @@
# Start using
# Package `geval` - Documentation

Install package: `go get github.com/jaavier/geval`
## Overview

# Handle Error and Success
The `geval` package in Go provides a simple utility to handle the evaluation and execution of tasks with the ability to manage context, error handling, and verbose output. It allows developers to define custom actions for success, failure, and panic scenarios. The core components of the package are the `Params` and `Context` types.

```golang
## Why use `geval`?

The `geval` package offers several advantages that make it useful for various types of software development:

1. **Context Management**: The package provides a `Context` type, allowing developers to manage and pass contextual information across different functions and goroutines. This facilitates sharing data and communication among concurrent tasks.

2. **Error Handling**: It allows users to define custom error handlers, which can be used to perform specific actions based on the success or failure of a task. This helps in handling errors gracefully and taking appropriate actions.

3. **Panic Handling**: Developers can specify a panic handler to gracefully handle unexpected panics and recover from them. This ensures that a panic in one goroutine doesn't crash the entire application.

4. **Verbose Output**: The package supports verbose output, making it easier to debug and understand the execution flow. It provides developers with more insights into the tasks' progress and status.

5. **Concurrency Support**: The package is designed to be concurrency-friendly, enabling developers to create and manage goroutines sharing the same context. This makes it easier to execute tasks concurrently without race conditions.

## Examples

### Basic Use:

#### Example 1: Simple Task Execution

```go
package main

import (
"context"
"fmt"
"github.com/jaavier/geval"
)

func main() {
ctx := geval.CreateContext()

params := &geval.Params{
Context: ctx,
Handler: simpleTask,
}

geval.Run(params)
}

func simpleTask(ctx *geval.Context) error {
// Perform the main task here
fmt.Println("Task executed successfully!")
return nil
}
```

### Intermediate Use:

#### Example 2: Error Handling and Context Management

```go
package main

import (
"context"
"fmt"
"github.com/jaavier/geval"
)

func main() {
var data []byte
var err error
ctx := geval.CreateContext()
ctx.Update("user_id", 123)

data, err = retrieveData(true)
params := &geval.Params{
Context: ctx,
Handler: errorProneTask,
Failed: handleFailure,
}

geval.Run(&geval.Params{
Err: err,
Success: transformData(data),
})
geval.Run(params)
}

_, err = retrieveData(false)
func errorProneTask(ctx *geval.Context) error {
// Simulate an error condition
return fmt.Errorf("something went wrong")
}

geval.Run(&geval.Params{
Err: err,
Failed: func() {
fmt.Println("Catch error:", err.Error())
},
})
func handleFailure(ctx *geval.Context) {
// Custom error handling
fmt.Println("Task failed!")
userId := ctx.Read("user_id")
fmt.Printf("User ID: %v\n", userId)
}
```

### Advanced Use:

#### Example 3: Verbose Output

```go
package main

func transformData(data []byte) func() {
return func() {
fmt.Println("Bytes raw:", data)
fmt.Println("Bytes to string:", string(data))
import (
"context"
"fmt"
"github.com/jaavier/geval"
)

func main() {
ctx := geval.CreateContext()

params := &geval.Params{
Context: ctx,
Handler: verboseTask,
Success: handleSuccess,
Verbose: true,
}

geval.Run(params)
}

func verboseTask(ctx *geval.Context) error {
// Some task execution
return nil
}

func handleSuccess(ctx *geval.Context) {
// Custom success handler with verbose output
fmt.Println("Task executed successfully!")
}
```

#### Example 4: Concurrent Task Execution with Shared Context and Channel

```go
package main

import (
"fmt"
"sync"

"github.com/jaavier/geval"
)

func main() {
ctx := geval.CreateContext()

var wg sync.WaitGroup
wg.Add(2)

go producer(ctx, &wg)
go consumer(ctx, &wg)

wg.Wait()
}

func producer(ctx *geval.Context, wg *sync.WaitGroup) {
defer wg.Done()

// Simulate producing data and sending it through the channel
for i := 1; i <= 5; i++ {
ctx.Channel <- i
fmt.Println("Producer sent:", i)
}
close(ctx.Channel)
}

func retrieveData(isActive bool) ([]byte, error) {
if isActive {
return []byte("hello world"), nil
func consumer(ctx *geval.Context, wg *sync.WaitGroup) {
defer wg.Done()

// Simulate consuming data from the channel
for data := range ctx.Channel {
fmt.Println("Consumer received:", data)
}
return []byte{}, fmt.Errorf("cannot retrieve when isActive = false")
}
```
```
65 changes: 53 additions & 12 deletions geval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,80 @@ package geval

import (
"context"
"log"
"fmt"
"runtime"
)

type Params struct {
Err error
Success func(ctx context.Context)
Failed func(ctx context.Context)
Handler func() (context.Context, error)
Success func(ctx *Context)
Failed func(ctx *Context)
Handler func(ctx *Context) error
Panic func(v any) error
Verbose int
Context context.Context
Context *Context
Verbose bool
}

type Context struct {
Context context.Context
CancelFunc context.CancelFunc
Channel chan interface{}
}

func (cc *Context) Update(key interface{}, val interface{}) {
cc.Context = context.WithValue(cc.Context, key, val)
}

func (cc *Context) Read(key interface{}) interface{} {
return (cc.Context).Value(key)
}

func CreateContext() *Context {
ctx, cancel := context.WithCancel(context.Background())

return &Context{
Context: ctx,
CancelFunc: cancel,
Channel: make(chan interface{}),
}
}

func Run(params *Params) {
var err error
var ctx = context.TODO()
var err error = params.Err
var template string
var ctx = params.Context

if (ctx) == nil {
panic("Cannot Run wihout Context")
}

_, file, line, ok := runtime.Caller(1)
if ok {
template = fmt.Sprintf("%s:%d %%s\n", file, line)
}

if params.Err == nil && params.Handler != nil {
ctx, err = params.Handler()
err = params.Handler(ctx)
}

if err != nil {
if params.Verbose > 0 {
log.Println(err.Error())
}
if params.Panic != nil {
if params.Verbose {
fmt.Printf("[VERBOSE] %s", fmt.Sprintf(template, "(Panic)"))
}
panic(params.Panic(err))
}
if params.Failed != nil {
if params.Verbose {
fmt.Printf("[VERBOSE] %s", fmt.Sprintf(template, "(Failed)"))
}
params.Failed(ctx)
}
} else {
if params.Success != nil {
if params.Verbose {
fmt.Printf("[VERBOSE] %s", fmt.Sprintf(template, "(Success)"))
}
params.Success(ctx)
}
}
Expand Down

0 comments on commit afd61b1

Please sign in to comment.