warnings

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 15, 2017 License: BSD-2-Clause Imports: 2 Imported by: 31

README

Package warnings implements error handling with non-fatal errors (warnings).

import path:   "gopkg.in/warnings.v0"
package docs:  https://godoc.org/gopkg.in/warnings.v0 
issues:        https://github.com/go-warnings/warnings/issues
pull requests: https://github.com/go-warnings/warnings/pulls

A recurring pattern in Go programming is the following:

 func myfunc(params) error {
     if err := doSomething(...); err != nil {
         return err
     }
     if err := doSomethingElse(...); err != nil {
         return err
     }
     if ok := doAnotherThing(...); !ok {
         return errors.New("my error")
     }
     ...
     return nil
 }

This pattern allows interrupting the flow on any received error. But what if
there are errors that should be noted but still not fatal, for which the flow
should not be interrupted? Implementing such logic at each if statement would
make the code complex and the flow much harder to follow.

Package warnings provides the Collector type and a clean and simple pattern
for achieving such logic. The Collector takes care of deciding when to break
the flow and when to continue, collecting any non-fatal errors (warnings)
along the way. The only requirement is that fatal and non-fatal errors can be
distinguished programmatically; that is a function such as

 IsFatal(error) bool

must be implemented. The following is an example of what the above snippet
could look like using the warnings package:

 import "gopkg.in/warnings.v0"

 func isFatal(err error) bool {
     _, ok := err.(WarningType)
     return !ok
 }

 func myfunc(params) error {
     c := warnings.NewCollector(isFatal)
     c.FatalWithWarnings = true
     if err := c.Collect(doSomething()); err != nil {
         return err
     }
     if err := c.Collect(doSomethingElse(...)); err != nil {
         return err
     }
     if ok := doAnotherThing(...); !ok {
         if err := c.Collect(errors.New("my error")); err != nil {
             return err
         }
     }
     ...
     return c.Done()
 }

For an example of a non-trivial code base using this library, see
gopkg.in/gcfg.v1

Rules for using warnings

 - ensure that warnings are programmatically distinguishable from fatal
   errors (i.e. implement an isFatal function and any necessary error types)
 - ensure that there is a single Collector instance for a call of each
   exported function
 - ensure that all errors (fatal or warning) are fed through Collect
 - ensure that every time an error is returned, it is one returned by a
   Collector (from Collect or Done)
 - ensure that Collect is never called after Done

Documentation

Overview

Package warnings implements error handling with non-fatal errors (warnings).

A recurring pattern in Go programming is the following:

func myfunc(params) error {
    if err := doSomething(...); err != nil {
        return err
    }
    if err := doSomethingElse(...); err != nil {
        return err
    }
    if ok := doAnotherThing(...); !ok {
        return errors.New("my error")
    }
    ...
    return nil
}

This pattern allows interrupting the flow on any received error. But what if there are errors that should be noted but still not fatal, for which the flow should not be interrupted? Implementing such logic at each if statement would make the code complex and the flow much harder to follow.

Package warnings provides the Collector type and a clean and simple pattern for achieving such logic. The Collector takes care of deciding when to break the flow and when to continue, collecting any non-fatal errors (warnings) along the way. The only requirement is that fatal and non-fatal errors can be distinguished programmatically; that is a function such as

IsFatal(error) bool

must be implemented. The following is an example of what the above snippet could look like using the warnings package:

import "gopkg.in/warnings.v0"

func isFatal(err error) bool {
    _, ok := err.(WarningType)
    return !ok
}

func myfunc(params) error {
    c := warnings.NewCollector(isFatal)
    c.FatalWithWarnings = true
    if err := c.Collect(doSomething()); err != nil {
        return err
    }
    if err := c.Collect(doSomethingElse(...)); err != nil {
        return err
    }
    if ok := doAnotherThing(...); !ok {
        if err := c.Collect(errors.New("my error")); err != nil {
            return err
        }
    }
    ...
    return c.Done()
}

For an example of a non-trivial code base using this library, see gopkg.in/gcfg.v1

Rules for using warnings

  • ensure that warnings are programmatically distinguishable from fatal errors (i.e. implement an isFatal function and any necessary error types)
  • ensure that there is a single Collector instance for a call of each exported function
  • ensure that all errors (fatal or warning) are fed through Collect
  • ensure that every time an error is returned, it is one returned by a Collector (from Collect or Done)
  • ensure that Collect is never called after Done

TODO

  • optionally limit the number of warnings (e.g. stop after 20 warnings) (?)
  • consider interaction with contexts
  • go vet-style invocations verifier
  • semi-automatic code converter

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FatalOnly

func FatalOnly(err error) error

FatalOnly returns the fatal error, if any, **in an error returned by a Collector**. It returns nil if and only if err is nil or err is a List with err.Fatal == nil.

func WarningsOnly

func WarningsOnly(err error) []error

WarningsOnly returns the warnings **in an error returned by a Collector**.

Types

type Collector

type Collector struct {
	// IsFatal distinguishes between warnings and fatal errors.
	IsFatal func(error) bool
	// FatalWithWarnings set to true means that a fatal error is returned as
	// a List together with all warnings so far. The default behavior is to
	// only return the fatal error and discard any warnings that have been
	// collected.
	FatalWithWarnings bool
	// contains filtered or unexported fields
}

A Collector collects errors up to the first fatal error.

func NewCollector

func NewCollector(isFatal func(error) bool) *Collector

NewCollector returns a new Collector; it uses isFatal to distinguish between warnings and fatal errors.

func (*Collector) Collect

func (c *Collector) Collect(err error) error

Collect collects a single error (warning or fatal). It returns nil if collection can continue (only warnings so far), or otherwise the errors collected. Collect mustn't be called after the first fatal error or after Done has been called.

func (*Collector) Done

func (c *Collector) Done() error

Done ends collection and returns the collected error(s).

type List

type List struct {
	Warnings []error
	Fatal    error
}

List holds a collection of warnings and optionally one fatal error.

func (List) Error

func (l List) Error() string

Error implements the error interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL