packages feed

throwable-exceptions 0.1.0.2 → 0.1.0.3

raw patch · 4 files changed

+126/−16 lines, 4 files

Files

README.md view
@@ -1,9 +1,16 @@ # :diamonds: throwable-exceptions :diamonds:+[![Build Status](https://travis-ci.org/aiya000/hs-throwable-exceptions.svg?branch=master)](https://travis-ci.org/aiya000/hs-throwable-exceptions) [![Hackage](https://img.shields.io/hackage/v/lens.svg)](https://hackage.haskell.org/package/throwable-exceptions)  throwable-exceptions gives the exception's value constructors for your haskell project :dog:  +## Document is available in here++- [throwable-exceptions - Hackage](https://hackage.haskell.org/package/throwable-exceptions)+- [the simulation of the use case](https://github.com/aiya000/hs-throwable-exceptions/blob/master/test/Control/Exception/ThrowableTest.hs)++ # :muscle: Why we should use this ? :muscle: The situation that we want to throw the specific exception is happened frequently, but many general exceptions are not given by base.@@ -35,3 +42,7 @@  But you have not to define a specific exception yourself if you use this :muscle:+++# :+1:+PR is welcome !
src/Control/Exception/Throwable.hs view
@@ -1,21 +1,71 @@ module Control.Exception.Throwable   ( IOException' (..)+  , ioException'   , IllegalArgumentException (..)+  , illegalArgumentException+  , GeneralException (..)+  , generalException+  , IndexOutOfBoundsException (..)+  , indexOutOfBoundsException   ) where  import Control.Exception.Safe (Exception)+import Data.Typeable (Typeable)   -- | Simular to @Control.Exception.IOException@-data IOException' = IOException' { ioExceptionCause :: String }-                  | FileNotFoundException { fileNotFoundCause :: String }-  deriving (Read, Show)+data IOException' a = IOException' { ioExceptionCause :: String, ioExceptionClue :: a }+                    | FileNotFoundException { fileNotFoundCause :: String, fileNotFoundClue :: a } -instance Exception IOException'+instance Show a => Show (IOException' a) where+  show (IOException' cause _) = "IOException': " ++ show cause+  show (FileNotFoundException cause _) = "FileNotFoundException: " ++ show cause +instance (Typeable a, Show a) => Exception (IOException' a) --- Like java.lang.IllegalArgumentException-data IllegalArgumentException = IllegalArgumentException { illegalArgumentCause :: String }-  deriving (Read, Show)+-- | A constructor for IOException' but doesn't take the clue+ioException' :: String -> IOException' ()+ioException' = flip IOException' () -instance Exception IllegalArgumentException++-- | Like java.lang.IllegalArgumentException+data IllegalArgumentException a = IllegalArgumentException { illegalArgumentCause :: String, illegalArgumentClue :: a }++instance Show a => Show (IllegalArgumentException a) where+  show (IllegalArgumentException cause  _) = "IllegalArgumentException: " ++ show cause++instance (Typeable a, Show a) => Exception (IllegalArgumentException a)++-- | A constructor for IllegalArgumentException but doesn't take the clue+illegalArgumentException :: String -> IllegalArgumentException ()+illegalArgumentException = flip IllegalArgumentException ()+++-- | Like java.lang.IndexOutOfBoundsException+data IndexOutOfBoundsException a = IndexOutOfBoundsException { indexOutOfBoundsCause :: String, indexOutOfBoundsArgumentClue :: a }++instance Show a => Show (IndexOutOfBoundsException a) where+  show (IndexOutOfBoundsException cause  _) = "IndexOutOfBoundsException: " ++ show cause++instance (Typeable a, Show a) => Exception (IndexOutOfBoundsException a)++-- | A constructor for IndexOutOfBoundsException but doesn't take the clue+indexOutOfBoundsException :: String -> IndexOutOfBoundsException ()+indexOutOfBoundsException = flip IndexOutOfBoundsException ()+++-- | An other of these exceptions+data GeneralException a = GeneralException+  { exceptionName  :: String -- ^ This should be named by 'PascalCase' for show, for example: "MyOperation", "Database"+  , exceptionCause :: String -- ^ The message for the cause of the exception+  , exceptionClue  :: a      -- ^ The clue of the exception. This can be anything of Show instance+  }++instance Show a => Show (GeneralException a) where+  show (GeneralException name cause _) = name ++ "Exception: " ++ cause++instance (Typeable a, Show a) => Exception (GeneralException a)++-- | A constructor for GeneralException but doesn't take the clue+generalException :: String -> String -> GeneralException ()+generalException name cause = GeneralException name cause () 
test/Control/Exception/ThrowableTest.hs view
@@ -1,11 +1,60 @@ module Control.Exception.ThrowableTest where -import Control.Exception.Safe (MonadThrow, throwM)-import Control.Monad.Trans.Either (runEitherT)+import Control.Exception.Safe (Exception)+import Control.Exception.Safe (MonadThrow, throwM, fromException, SomeException)+import Data.Either (isLeft) import Test.Tasty (TestTree)-import Test.Tasty.HUnit (testCase, assertFailure, (@?=), Assertion)+import Test.Tasty.HUnit (testCase, Assertion, assertBool, (@?=)) import qualified Control.Exception.Throwable as ET  -test_ioexception_prim :: [TestTree]-test_ioexception_prim = []+-- The message is never used in tasty-hunit+assertBool' :: Bool -> Assertion+assertBool' = assertBool "" ++canBeShown :: Exception e => e -> Assertion+canBeShown = assertBool' . not . null . show++canBeThrown :: Exception e => e -> Assertion+canBeThrown e = assertBool' . isLeft $ throwM e+++test_io_exception_prim :: [TestTree]+test_io_exception_prim =+  [ testCase "can be shown in most cases" $+      canBeShown $ ET.ioException' "honoka-chan!" -- IOException' can be shown, because IOException' is an Exception instance+  , testCase "can be thrown in all case" $+      canBeThrown $ ET.ioException' "kotori-chan ga!" -- IOException' can be thrown by throwM, because IOException' is an Exception instance !+  ]+++test_index_out_of_bounds_exception :: [TestTree]+test_index_out_of_bounds_exception =+  [ testCase "finds the perpetrator with the clue" $+      program -- You can find the perpetrator of some bug if you see the message ('.. looks like bad')+  ]+  where+    program :: IO ()+    program = do+      case someCalculation of +        Right _ -> putStrLn "the calculation is succeed"+        Left e -> case fromException' e of+          Nothing -> putStrLn "!? I don't know !"+          Just (ET.IndexOutOfBoundsException _ clue) -> putStrLn $ show clue ++ " looks like bad"++    -- monomorphic function+    fromException' :: SomeException -> Maybe (ET.IndexOutOfBoundsException ([Int], Int))+    fromException' = fromException++    at :: MonadThrow m => [Int] -> Int -> m Int+    xs `at` i | length xs <= i = throwM $ ET.IndexOutOfBoundsException "mmm..?" (xs, i)+              | otherwise      = return $ xs !! i++    someCalculation = [10..13] `at` 4+++test_general_exception :: [TestTree]+test_general_exception =+  [ testCase "looks like other exception when GeneralException is executed `show`" $+      show (ET.generalException "MyTest" "nico-chan")  @?= "MyTestException: nico-chan"+  ]
throwable-exceptions.cabal view
@@ -1,5 +1,5 @@ name:                throwable-exceptions-version:             0.1.0.2+version:             0.1.0.3 synopsis:            throwable-exceptions gives the exception's value constructors description:         throwable-exceptions gives the exception's value constructors homepage:            https://github.com/aiya000/hs-throwable-exceptions#README.md@@ -16,7 +16,7 @@ library   hs-source-dirs:      src   default-language:    Haskell2010-  ghc-options:         -Wall -Wno-name-shadowing -Wno-unused-do-bind -Wunused-top-binds+  ghc-options:         -Wall -Wno-name-shadowing -Wno-unused-do-bind -Wno-unused-top-binds   exposed-modules:     Control.Exception.Throwable   build-depends:       base >= 4.7 && < 5                      , safe-exceptions@@ -27,7 +27,7 @@   hs-source-dirs:      test   main-is:             Tasty.hs   default-language:    Haskell2010-  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall -Wunused-top-binds+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall -Wno-unused-top-binds   other-modules:       Control.Exception.ThrowableTest   build-depends:       base                      , either