123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- package gott
- import (
- "fmt"
- "log"
- "reflect"
- "runtime"
- )
- type LogLevel int
- // LogLevel specifies what to log:
- // Quiet logs nothing,
- // Error logs only errors,
- // Debug logs functions that run,
- // Info logs run and skipped functions
- const (
- Quiet LogLevel = iota
- Error
- Debug
- Info
- )
- func logErr(e error, fn interface{}) {
- fnName := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
- log.Printf("Function %s returned error: %v", fnName, e)
- }
- func logMsg(msg string, fn interface{}) {
- fnName := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
- log.Printf("%s %s", msg, fnName)
- }
- // Exception is a type encapsulating anything contained in panic.
- // It implements Error() and therefore can be used as error.
- type Exception struct {
- E interface{}
- }
- func (e Exception) Error() string {
- return fmt.Sprintf("function panicked")
- }
- // Tuple is a type encapsulating a slice of interface{}.
- type Tuple []interface{}
- // Result is a simplification of Either monad. It’s either successful—and
- // carries an interface{}—or unsuccessful—and carries an error.
- type Result struct {
- s interface{}
- e error
- LogLevel LogLevel
- }
- // NewResult creates initial Result passed to functions.
- func NewResult(s interface{}) *Result {
- return &Result{s, nil, Quiet}
- }
- // Bind performs fn on the receiver’s success value and assigns the returned
- // values to the receiver if the receiver is successful. In either case,
- // Bind returns the receiver.
- // Bind operates on functions that return value and error.
- func (r *Result) Bind(fn func(...interface{}) (interface{}, error)) *Result {
- if r.e == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", fn)
- }
- if s, ok := r.s.(Tuple); ok {
- r.s, r.e = fn(s...)
- } else {
- r.s, r.e = fn(r.s)
- }
- if r.e != nil && r.LogLevel >= Error {
- logErr(r.e, fn)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", fn)
- }
- }
- return r
- }
- // Map performs fn on the receiver’s success value and assigns the returned
- // value to the it if the receiver is successful. In either case, Map returns
- // the receiver.
- // Map operates on functions that are always successful and return only one
- // value
- func (r *Result) Map(fn func(...interface{}) interface{}) *Result {
- if r.e == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", fn)
- }
- if s, ok := r.s.(Tuple); ok {
- r.s = fn(s...)
- } else {
- r.s = fn(r.s)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", fn)
- }
- }
- return r
- }
- // Tee performs fn on the receiver’s success value and assigns the returned
- // error to the receiver if the receiver is successful. In either case, Tee
- // returns the receiver.
- // Tee operates on functions that perform side effects and might return an
- // error
- func (r *Result) Tee(fn func(...interface{}) error) *Result {
- if r.e == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", fn)
- }
- if s, ok := r.s.(Tuple); ok {
- r.e = fn(s...)
- } else {
- r.e = fn(r.s)
- }
- if r.e != nil && r.LogLevel >= Error {
- logErr(r.e, fn)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", fn)
- }
- }
- return r
- }
- // SafeTee performs fn on the receiver’s success value if the receiver is
- // successful. In either case, SafeTee returns the receiver.
- // SafeTee operates on functions that perform side effects and are always
- // successful.
- func (r *Result) SafeTee(fn func(...interface{})) *Result {
- if r.e == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", fn)
- }
- if s, ok := r.s.(Tuple); ok {
- fn(s...)
- } else {
- fn(r.s)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", fn)
- }
- }
- return r
- }
- // Catch performs fn on the receiver’s success value and assigns the returned
- // vale to it if the receiver is successful. If fn panics, Catch recovers and
- // stores the value passed to panic in receiver’s error as Exception. In either
- // case, Catch returns the receiver.
- func (r *Result) Catch(fn func(...interface{}) interface{}) (result *Result) {
- if r.e == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", fn)
- }
- defer func() {
- if err := recover(); err != nil {
- r.e = Exception{err}
- result = r
- if r.e != nil && r.LogLevel >= Error {
- logErr(r.e, fn)
- }
- }
- }()
- if s, ok := r.s.(Tuple); ok {
- r.s = fn(s...)
- } else {
- r.s = fn(r.s)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", fn)
- }
- }
- return r
- }
- // Revover tries to put processing back on the happy track.
- // If receiver is not successful, Recover calls the passed function and
- // assignes the returned values to the receiver. In either case, Recover
- // returns the receiver.
- func (r *Result) Recover(fn func(...interface{}) (interface{}, error)) *Result {
- if r.e != nil {
- if r.LogLevel >= Debug {
- logMsg("running:", fn)
- }
- if s, ok := r.s.(Tuple); ok {
- r.s, r.e = fn(s...)
- } else {
- r.s, r.e = fn(r.s)
- }
- if r.e != nil && r.LogLevel >= Error {
- logErr(r.e, fn)
- }
- } else {
- if r.LogLevel >= Info {
- logMsg("skipping:", fn)
- }
- }
- return r
- }
- // Handle performs onSuccess on the receiver’s success value if the receiver is
- // successful, or onError on the receiver’s error otherwise. In either case,
- // Handle returns the receiver.
- func (r *Result) Handle(onSuccess func(...interface{}), onError func(error)) *Result {
- if r.e == nil {
- if r.LogLevel >= Debug {
- logMsg("running:", onSuccess)
- }
- if s, ok := r.s.(Tuple); ok {
- onSuccess(s...)
- } else {
- onSuccess(r.s)
- }
- } else {
- if r.LogLevel >= Debug {
- logMsg("running:", onError)
- }
- onError(r.e)
- }
- return r
- }
- // Finish returns the values stored in the receiver.
- func (r *Result) Finish() (interface{}, error) {
- if r.e != nil {
- return nil, r.e
- } else {
- return r.s, nil
- }
- }
|