docs
diff --git a/warnings.go b/warnings.go index 8e9553d..5b57f43 100644 --- a/warnings.go +++ b/warnings.go
@@ -1,5 +1,81 @@ // Package warnings implements error handling with non-fatal errors (warnings). -package 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() +// } +// +// 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 +// +package warnings // import "gopkg.in/warnings.v0" import ( "bytes" @@ -33,8 +109,6 @@ return b.String() } -var _ error = List{} - // A Collector collects errors up to the first fatal error. type Collector struct { // IsFatal distinguishes between warnings and fatal errors. @@ -49,16 +123,16 @@ done bool } -// NewCollector returs a new Collector; it uses isFatal to distinguish between +// NewCollector returns a new Collector; it uses isFatal to distinguish between // warnings and fatal errors. func NewCollector(isFatal func(error) bool) *Collector { return &Collector{IsFatal: isFatal} } -// Collect collects a single error (warning or fatal). It return nil if +// Collect collects a single error (warning or fatal). It returns nil if // collection can continue (only warnings so far), or otherwise the errors -// collected so far. Collect mustn't be called after the first fatal error -// or after Done has been called. +// collected. Collect mustn't be called after the first fatal error or after +// Done has been called. func (c *Collector) Collect(err error) error { if c.done { panic("warnings.Collector already done")
diff --git a/warnings_test.go b/warnings_test.go index 61ee0fb..8d6ad0d 100644 --- a/warnings_test.go +++ b/warnings_test.go
@@ -8,6 +8,8 @@ w "gopkg.in/warnings.v0" ) +var _ error = List{} + type warn string func (w warn) Error() string { return string(w) }