From 190c1d4948afb74b539661890e1e652499b29060 Mon Sep 17 00:00:00 2001 From: Eric Myhre Date: Wed, 6 May 2015 16:21:26 -0500 Subject: [PATCH] Additional features for wrapped try errors. Add OriginalError convenience accessor. Rename data key var to make more sense. Add package level documentation pointing out CatchAll's error wrapping behavior. --- try/try.go | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/try/try.go b/try/try.go index 414e8df..ae1acb8 100644 --- a/try/try.go +++ b/try/try.go @@ -33,8 +33,10 @@ (no special treatment; they'll hit `CatchAll` blocks and `Finally` blocks; it would of course be silly for them to hit `Catch` blocks since those use spacemonkey-errors types). Panics with values that are not of golang's - `error` type at all will trigger `Finally` blocks but otherwise - be immediately repanicked. + `error` type at all will be wrapped in a spacemonkey error for the purpose + of handling (as an interface design, `CatchAll(interface{})` is unpleasant). + See `OriginalError` and `Repanic` for more invormation on handling these + wrapped panic objects. A `try.Do(func() {...})` with no attached errors handlers is legal but pointless. A `try.Do(func() {...})` with no `Done()` will never run the @@ -61,7 +63,7 @@ var ( UnknownPanicError = errors.NewClass("Unknown Error") // The spacemonkey error key to get the original data out of an UnknownPanicError. - OriginalPanic = errors.GenSym() + OriginalErrorKey = errors.GenSym() ) type Plan struct { @@ -153,14 +155,14 @@ func (p *Plan) Done() { if catch.match == nil { consumed = true msg := fmt.Sprintf("%v", rec) - pan := UnknownPanicError.NewWith(msg, errors.SetData(OriginalPanic, rec)) + pan := UnknownPanicError.NewWith(msg, errors.SetData(OriginalErrorKey, rec)) catch.anyhandler(pan) return } if UnknownPanicError.Is(catch.match) { consumed = true msg := fmt.Sprintf("%v", rec) - pan := UnknownPanicError.NewWith(msg, errors.SetData(OriginalPanic, rec)) + pan := UnknownPanicError.NewWith(msg, errors.SetData(OriginalErrorKey, rec)) catch.handler(pan.(*errors.Error)) return } @@ -170,9 +172,26 @@ func (p *Plan) Done() { p.main() } +/* + If `err` was originally another value coerced to an error by `CatchAll`, + this will return the original value. Otherwise, it returns the same error + again. + + See also `Repanic()`. +*/ +func OriginalError(err error) interface{} { + data := errors.GetData(err, OriginalErrorKey) + if data == nil { + return err + } + return data +} + /* Panics again with the original error. + Shorthand, equivalent to calling `panic(OriginalError(err))` + If the error is a `UnknownPanicError` (i.e., a `CatchAll` block that's handling something that wasn't originally an `error` type, so it was wrapped), it will unwrap that re-panic with that original error -- in other words, this is a "do the right thing" method in all scenarios. @@ -192,9 +211,9 @@ func Repanic(err error) { if !wrapper.Is(UnknownPanicError) { panic(err) } - data := errors.GetData(err, OriginalPanic) + data := errors.GetData(err, OriginalErrorKey) if data == nil { - panic(errors.ProgrammerError.New("misuse of try internals", errors.SetData(OriginalPanic, err))) + panic(errors.ProgrammerError.New("misuse of try internals", errors.SetData(OriginalErrorKey, err))) } panic(data) }