error 0.1.0.0 → 0.1.1.0
raw patch · 4 files changed
+85/−32 lines, 4 filesdep +doctestdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: doctest
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Data.Error: exceptionToError :: Exception exc => exc -> Error
+ Data.Error: showToError :: Show a => a -> Error
- Data.Error: expectError :: Text -> Either Error p -> p
+ Data.Error: expectError :: HasCallStack => Text -> Either Error p -> p
- Data.Error: unwrapError :: Either Error p -> p
+ Data.Error: unwrapError :: HasCallStack => Either Error p -> p
Files
- CHANGELOG.md +6/−0
- error.cabal +11/−1
- src/Data/Error.hs +62/−31
- test/DocTest.hs +6/−0
CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for error +## 0.1.1.0 -- 2021-10-28++* Add `HasCallStack` to `expectError` and `unwrapError`.+* Add `showToError` and `exceptionToError`.+* Improved documentation of existing functions.+ ## 0.1.0.0 -- 2021-06-26 * Initial version. More or less feature complete,
error.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: error-version: 0.1.0.0+version: 0.1.1.0 synopsis: The canonical error type @@ -38,6 +38,16 @@ -- LANGUAGE extensions used by modules in this package. -- other-extensions:++test-suite doctest+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: DocTest.hs+ default-language: Haskell2010+ build-depends:+ base+ , doctest+ source-repository head type: git
src/Data/Error.hs view
@@ -1,17 +1,39 @@ {-# LANGUAGE OverloadedStrings #-} module Data.Error ( Error,+ -- * Error creation newError,+ -- *** From 'Show' and 'Exception'++ -- | These two functions can be helpful, but consider that they don’t always provide very user-friendly error messages.+ -- It is recommended that you use `addContext` to improve the messages generated by 'showToError' and 'exceptionToError'.+ showToError,+ exceptionToError,+ -- * Adding context addContext,+ -- * Pretty printing prettyError,- unwrapError,+ -- * Unsafe unwrapping++ -- | Sometimes you want to assure that an 'Error' could not have happened at runtime,+ -- even though there is the possibility in the types.+ -- In that case you can use 'expectError'/'unwrapError'.+ -- They will panic at runtime if there was an error.+ --+ -- 'expectError' should usually be preffered, since it adds a context message.+ --+ -- These are modelled after @<https://doc.rust-lang.org/std/result/enum.Result.html#method.expect Result::expect()>@+ -- and @<https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap Result::unwrap()>@ in the rust stdlib. expectError,+ unwrapError, ) where import Data.Function ((&)) import Data.Text (Text) import qualified Data.Text as Text+import GHC.Stack (HasCallStack)+import Control.Exception (Exception (displayException)) -- | The canonical @Error@ type. --@@ -26,6 +48,23 @@ newError :: Text -> Error newError msg = Error [msg] +-- | Create an error from a `Show` type.+--+-- If your type implements 'Exception', it is usually better to use 'exceptionToError' instead.+-- Strings produced by 'show' are usually not very user-friendly.+--+-- Note: goes via `String`, so not efficient.+showToError :: Show a => a -> Error+showToError = newError . Text.pack . show++-- | Create an error from an 'Exception' type.+--+-- The default implementation of 'displayException' is 'show', so the same user-friendliness problems of 'showToError' apply.+--+-- Note: goes via `String`, so not efficient.+exceptionToError :: Exception exc => exc -> Error+exceptionToError = newError . Text.pack . displayException+ -- | Add a higher-level context to an 'Error'. -- -- For example, your code hits a “file not found” I/O exception.@@ -53,17 +92,15 @@ -- -- Example: ----- @--- prettyError $ newError "file not found: ./foo"------ ==> "file not found: ./foo"------ prettyError--- $ addContext "Trying to open config file"--- $ newError "file not found: ./foo"+-- >>> prettyError $ newError "file not found: ./foo"+-- "file not found: ./foo" ----- ==> "Trying to open config file: file not found: ./foo"--- @+-- >>> :{+-- prettyError+-- $ addContext "Trying to open config file"+-- $ newError "file not found: ./foo"+-- :}+-- "Trying to open config file: file not found: ./foo" prettyError :: Error -> Text prettyError (Error es) = Text.intercalate ": " es @@ -71,20 +108,17 @@ -- -- Abort with the 'Error's message if it was a 'Left'. ----- Panic: if Error+-- __Panics__: if Error -- -- Example: ----- @--- unwrapError $ Left (newError "oh no!")------ ==> *** Exception: oh no!------ unwrapError $ Right 42+-- >>> unwrapError $ Left (newError "oh no!")+-- *** Exception: oh no!+-- ... ----- ==> 42--- @-unwrapError :: Either Error p -> p+-- >>> unwrapError $ Right 42+-- 42+unwrapError :: HasCallStack => Either Error p -> p unwrapError e = case e of Left err -> error (prettyError err & Text.unpack) Right a -> a@@ -95,20 +129,17 @@ -- -- The text message is added to the 'Error' as additional context before aborting. ----- Panic: if Error+-- __Panics__: if Error -- -- Example: ----- @--- exceptError "something bad happened" $ Left (newError "oh no!")------ ==> *** Exception: something bad happened: oh no!------ exceptError $ Right 42+-- >>> expectError "something bad happened" $ Left (newError "oh no!")+-- *** Exception: something bad happened: oh no!+-- ... ----- ==> 42--- @-expectError :: Text -> Either Error p -> p+-- >>> expectError "something bad happened" $ Right 42+-- 42+expectError :: HasCallStack => Text -> Either Error p -> p expectError context e = case e of Left err -> error
+ test/DocTest.hs view
@@ -0,0 +1,6 @@+module Main where++import Test.DocTest++main :: IO ()+main = doctest [ "-XOverloadedStrings", "src" ]