annotated-exception 0.1.0.0 → 0.1.1.0
raw patch · 4 files changed
+82/−15 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Control.Exception.Annotated: Handler :: (e -> m a) -> Handler (m :: Type -> Type) a
+ Control.Exception.Annotated: data Handler (m :: Type -> Type) a
- Control.Exception.Annotated: try :: (MonadCatch m, Exception e) => m a -> m (Either e a)
+ Control.Exception.Annotated: try :: (Exception e, MonadCatch m) => m a -> m (Either e a)
Files
- ChangeLog.md +7/−0
- annotated-exception.cabal +1/−1
- src/Control/Exception/Annotated.hs +43/−7
- test/Control/Exception/AnnotatedSpec.hs +31/−7
ChangeLog.md view
@@ -2,6 +2,13 @@ ## Unreleased changes +## 0.1.1.0++- [#4](https://github.com/parsonsmatt/annotated-exception/pull/4)+ - Add `catches`+ - Replace `Control.Exception.Safe.try` with `try` that can get an+ `AnnotatedException e` or a regular, un-`Annotated` `e`.+ ## 0.1.0.0 - Initial Release
annotated-exception.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: annotated-exception-version: 0.1.0.0+version: 0.1.1.0 synopsis: Exceptions, with checkpoints and context. description: Please see the README on Github at <https://github.com/parsonsmatt/annotated-exception#readme> category: Control
src/Control/Exception/Annotated.hs view
@@ -38,6 +38,7 @@ -- * Handling Exceptions , catch , tryAnnotated+ , try -- * Manipulating Annotated Exceptions , check@@ -52,11 +53,11 @@ , Exception(..) , Safe.SomeException(..) , Safe.throw- , Safe.try+ , Handler (..) ) where import Control.Exception.Safe- (Exception, MonadCatch, MonadThrow, SomeException(..))+ (Exception, Handler(..), MonadCatch, MonadThrow, SomeException(..)) import qualified Control.Exception.Safe as Safe import Data.Annotation import Data.Maybe@@ -177,11 +178,26 @@ -- @since 0.1.0.0 catch :: (Exception e, MonadCatch m) => m a -> (e -> m a) -> m a catch action handler =- Safe.catches- action- [ Safe.Handler handler- , Safe.Handler $ \(AnnotatedException anns e) ->- checkpointMany anns $ handler e+ catches action [Handler handler]++-- | Like 'Safe.catches', but this function enhance the provided 'Handler's+-- to "see through" any 'AnnotatedException's.+--+-- @since 0.1.1.0+catches :: (MonadCatch m) => m a -> [Handler m a] -> m a+catches action handlers =+ Safe.catches action (mkAnnotatedHandlers handlers)++-- | Extends each 'Handler' in the list with a variant that sees through+-- the 'AnnotatedException' and re-annotates any rethrown exceptions.+--+-- @since 0.1.1.0+mkAnnotatedHandlers :: MonadCatch m => [Handler m a] -> [Handler m a]+mkAnnotatedHandlers xs =+ xs >>= \(Handler hndlr) ->+ [ Handler hndlr+ , Handler $ \(AnnotatedException anns e) ->+ checkpointMany anns $ hndlr e ] -- | Like 'catch', but always returns a 'AnnotatedException'.@@ -190,6 +206,26 @@ tryAnnotated :: (Exception e, MonadCatch m) => m a -> m (Either (AnnotatedException e) a) tryAnnotated action = (Right <$> action) `catch` (pure . Left)++-- | Like 'Safe.try', but can also handle an 'AnnotatedException' or the+-- underlying value. Useful when you want to 'try' to catch a type of+-- exception, but you may not care about the 'Annotation's that it may or+-- may not have.+--+-- Example:+--+-- > Left exn <- try $ throw (AnnotatedException [] TestException)+-- > exn == TestException+--+-- > Left exn <- try $ throw TestException+-- > exn == AnnotatedException [] TestException+--+-- @since 0.1.0.1+try :: (Exception e, MonadCatch m) => m a -> m (Either e a)+try action = do+ (Right <$> action)+ `catches`+ mkAnnotatedHandlers [Handler (\exn -> pure $ Left exn)] -- | Attaches the 'CallStack' to the 'AnnotatedException' that is thrown. --
test/Control/Exception/AnnotatedSpec.hs view
@@ -71,20 +71,44 @@ pass describe "try" $ do- it "always adds a location" $ do- Left exn <- try (throw TestException)- exn `shouldBe` AnnotatedException [] TestException+ let subject :: (Exception e, Exception e') => e -> IO e'+ subject exn = do+ Left exn' <- try (throw exn)+ pure exn' - it "does not nest locations" $ do- Left exn <- try $ throw $ new $ new $ new TestException- exn `shouldBe` new TestException+ describe "when throwing non-Annotated" $ do+ it "can add an empty annotation for a non-Annotated exception" $ do+ exn <- subject TestException+ exn `shouldBe` AnnotatedException [] TestException + it "can catch a usual exception" $ do+ exn <- subject TestException+ exn `shouldBe` TestException++ describe "when throwing Annotated" $ do+ it "can catch a non-Annotated exception" $ do+ exn <- subject $ new TestException+ exn `shouldBe` TestException++ it "can catch an Annotated exception" $ do+ exn <- subject TestException+ exn `shouldBe` new TestException++ describe "nesting behavior" $ do+ it "can catch at any level of nesting" $ do+ subject TestException+ >>= (`shouldBe` new TestException)+ subject TestException+ >>= (`shouldBe` new (new TestException))+ subject TestException+ >>= (`shouldBe` new (new (new TestException)))+ describe "Safe.try" $ do it "can catch a located exception" $ do Left exn <- Safe.try (Safe.throw TestException) exn `shouldBe` new TestException - it "does not catch a AnnotatedException" $ do+ it "does not catch an AnnotatedException" $ do let action = do Left exn <- Safe.try (Safe.throw $ new TestException) exn `shouldBe` TestException