safe-exceptions 0.1.3.0 → 0.1.4.0
raw patch · 4 files changed
+45/−1 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Control.Exception.Safe: catchJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> (b -> m a) -> m a
+ Control.Exception.Safe: handleJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a
+ Control.Exception.Safe: tryJust :: (MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a)
Files
- ChangeLog.md +4/−0
- safe-exceptions.cabal +1/−1
- src/Control/Exception/Safe.hs +24/−0
- test/Control/Exception/SafeSpec.hs +16/−0
ChangeLog.md view
@@ -1,3 +1,7 @@+## 0.1.4.0++* Add `catchJust`, `handleJust`, and `tryJust`+ ## 0.1.3.0 * Add `catchIO`, `handleIO`, and `tryIO`
safe-exceptions.cabal view
@@ -1,5 +1,5 @@ name: safe-exceptions-version: 0.1.3.0+version: 0.1.4.0 synopsis: Safe, consistent, and easy exception handling description: Please see README.md homepage: https://github.com/fpco/safe-exceptions#readme
src/Control/Exception/Safe.hs view
@@ -22,6 +22,7 @@ , catchDeep , catchAnyDeep , catchAsync+ , catchJust , handle , handleIO@@ -29,6 +30,7 @@ , handleDeep , handleAnyDeep , handleAsync+ , handleJust , try , tryIO@@ -36,6 +38,7 @@ , tryDeep , tryAnyDeep , tryAsync+ , tryJust , Handler(..) , catches@@ -179,6 +182,14 @@ catchAsync :: (C.MonadCatch m, Exception e) => m a -> (e -> m a) -> m a catchAsync = C.catch +-- | 'catchJust' is like 'catch' but it takes an extra argument which+-- is an exception predicate, a function which selects which type of+-- exceptions we're interested in.+--+-- @since 0.1.4.0+catchJust :: (C.MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> (b -> m a) -> m a+catchJust f a b = a `catch` \e -> maybe (throwM e) b $ f e+ -- | Flipped version of 'catch' -- -- @since 0.1.0.0@@ -220,6 +231,12 @@ handleAsync :: (C.MonadCatch m, Exception e) => (e -> m a) -> m a -> m a handleAsync = C.handle +-- | Flipped 'catchJust'.+--+-- @since 0.1.4.0+handleJust :: (C.MonadCatch m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a+handleJust f = flip (catchJust f)+ -- | Same as upstream 'C.try', but will not catch asynchronous -- exceptions --@@ -261,6 +278,13 @@ -- @since 0.1.0.0 tryAsync :: (C.MonadCatch m, E.Exception e) => m a -> m (Either e a) tryAsync = C.try++-- | A variant of 'try' that takes an exception predicate to select+-- which exceptions are caught.+--+-- @since 0.1.4.0+tryJust :: (C.MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a)+tryJust f a = catch (Right `liftM` a) (\e -> maybe (throwM e) (return . Left) (f e)) -- | Async safe version of 'E.onException' --
test/Control/Exception/SafeSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ScopedTypeVariables #-} module Control.Exception.SafeSpec (spec) where @@ -6,11 +7,16 @@ import qualified Control.Exception as E import Control.Exception.Safe import Control.Monad (forever)+import Data.Typeable (Typeable) import Data.Void (Void, absurd) import System.IO.Unsafe (unsafePerformIO) import System.Timeout (timeout) import Test.Hspec +newtype ExceptionPred = ExceptionPred { getExceptionPred :: Maybe () } deriving (Show, Eq, Typeable)++instance Exception ExceptionPred+ -- | Ugly hack needed because the underlying type is not exported timeoutException :: SomeException timeoutException =@@ -108,3 +114,13 @@ describe "catchesDeep" $ withAll $ \e _ -> do res <- return (impureThrow e) `catchesDeep` [Handler (\(_ :: SomeException) -> return ())] res `shouldBe` ()++ describe "catchJust" $ do+ it "catches a selected exception" $ do+ res <- catchJust getExceptionPred (throw (ExceptionPred (Just ()))) (return . Just)+ res `shouldBe` Just ()++ it "re-raises a selection that is passed on" $ do+ let ex = ExceptionPred Nothing+ res <- try (catchJust getExceptionPred (throw ex) (return . Just))+ res `shouldBe` Left ex