packages feed

read-env-var 0.1.0.1 → 1.0.0.0

raw patch · 3 files changed

+272/−36 lines, 3 filesdep +exceptionsdep +transformersdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: exceptions, transformers

Dependency ranges changed: base

API changes (from Hackage documentation)

- System.ReadEnvVar: readEnvVar :: Read a => String -> IO (Maybe a)
- System.ReadEnvVar: readEnvVarDef :: Read a => String -> a -> IO a
+ System.ReadEnvVar: EnvVarCannotBeReadException :: String -> EnvVarCannotBeReadException
+ System.ReadEnvVar: EnvVarDoesNotExistException :: String -> EnvVarDoesNotExistException
+ System.ReadEnvVar: data EnvVarCannotBeReadException
+ System.ReadEnvVar: data EnvVarDoesNotExistException
+ System.ReadEnvVar: instance Data.Data.Data System.ReadEnvVar.EnvVarCannotBeReadException
+ System.ReadEnvVar: instance Data.Data.Data System.ReadEnvVar.EnvVarDoesNotExistException
+ System.ReadEnvVar: instance GHC.Classes.Eq System.ReadEnvVar.EnvVarCannotBeReadException
+ System.ReadEnvVar: instance GHC.Classes.Eq System.ReadEnvVar.EnvVarDoesNotExistException
+ System.ReadEnvVar: instance GHC.Classes.Ord System.ReadEnvVar.EnvVarCannotBeReadException
+ System.ReadEnvVar: instance GHC.Classes.Ord System.ReadEnvVar.EnvVarDoesNotExistException
+ System.ReadEnvVar: instance GHC.Exception.Exception System.ReadEnvVar.EnvVarCannotBeReadException
+ System.ReadEnvVar: instance GHC.Exception.Exception System.ReadEnvVar.EnvVarDoesNotExistException
+ System.ReadEnvVar: instance GHC.Read.Read System.ReadEnvVar.EnvVarCannotBeReadException
+ System.ReadEnvVar: instance GHC.Read.Read System.ReadEnvVar.EnvVarDoesNotExistException
+ System.ReadEnvVar: instance GHC.Show.Show System.ReadEnvVar.EnvVarCannotBeReadException
+ System.ReadEnvVar: instance GHC.Show.Show System.ReadEnvVar.EnvVarDoesNotExistException
+ System.ReadEnvVar: lookupEnv :: (IsString a, MonadIO m) => String -> m (Maybe a)
+ System.ReadEnvVar: lookupEnvEx :: (IsString a, MonadIO m, MonadThrow m) => String -> m a
+ System.ReadEnvVar: readEnv :: (MonadIO m, Read a) => String -> m (Maybe a)
+ System.ReadEnvVar: readEnvDef :: (MonadIO m, Read a) => String -> a -> m a
+ System.ReadEnvVar: readEnvEx :: (MonadIO m, Read a, MonadThrow m) => String -> m (Maybe a)
+ System.ReadEnvVar: readEnvEx' :: (MonadIO m, Read a, MonadThrow m) => String -> m a
+ System.ReadEnvVar: setEnv :: String -> String -> IO ()
- System.ReadEnvVar: lookupEnvDef :: IsString a => String -> a -> IO a
+ System.ReadEnvVar: lookupEnvDef :: (IsString a, MonadIO m) => String -> a -> m a

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright Author name here (c) 2016+Copyright Dennis Gosnell (c) 2016  All rights reserved. 
read-env-var.cabal view
@@ -1,5 +1,5 @@ name:                read-env-var-version:             0.1.0.1+version:             1.0.0.0 synopsis:            Functions for safely reading environment variables. description:         Please see README.md homepage:            https://github.com/cdepillabout/read-env-var#readme@@ -16,7 +16,9 @@ library   hs-source-dirs:      src   exposed-modules:     System.ReadEnvVar-  build-depends:       base >= 4.6 && < 5+  build-depends:       base >= 4.7 && < 5+                     , exceptions+                     , transformers   default-language:    Haskell2010   ghc-options:         -Wall 
src/System/ReadEnvVar.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE CPP #-}  {-|@@ -9,12 +10,37 @@ Portability : POSIX  This Haskell module exports functions for safely reading environment variables.++The @lookupEnv*@ functions are for reading in 'String'-like environment+variables (like hostnames, passwords, etc.), while the @readEnv*@ functions are+for reading in Haskell datatypes (like 'Int', 'Double', etc).++Most of these functions run in 'MonadIO'.  This means that they can be used+from any monad that implements 'MonadIO'.  This makes it easier to run in a+monad transformer stack.  If you're not familiar with 'MonadIO', you can just+think of all the functions as being 'IO' actions.++The 'lookupEnv', 'lookupEnvDef', and 'lookupEnvEx' functions all use 'IsString'+to generalize the return type.  This makes it more general than+"System.Environment"\'s 'Env.lookupEnv'.  It makes it possible to read in+things other than 'String's, like+<https://hackage.haskell.org/package/text/docs/Data-Text.html Text> or+<https://hackage.haskell.org/package/bytestring/docs/Data-ByteString.html ByteString>. -}  module System.ReadEnvVar-    ( readEnvVar-    , readEnvVarDef+    ( lookupEnv     , lookupEnvDef+    , readEnv+    , readEnvDef+      -- * Unsafe functions+    , EnvVarDoesNotExistException(..)+    , lookupEnvEx+    , readEnvEx+    , EnvVarCannotBeReadException(..)+    , readEnvEx'+      -- * Re-exports+    , setEnv     ) where  #if __GLASGOW_HASKELL__ < 710@@ -23,69 +49,277 @@ import Control.Applicative #endif +import Control.Exception (Exception)+import Control.Monad.Catch (MonadThrow(throwM))+import Control.Monad.IO.Class (MonadIO(liftIO))+import Data.Data (Data) import Data.Maybe (fromMaybe) import Data.String (IsString(fromString))-import System.Environment (lookupEnv)+import Data.Typeable (Typeable)+import System.Environment (setEnv)+import qualified System.Environment as Env import Text.Read (readMaybe)  -- | Lookup a value from an environment variable and read it in with -- 'readMaybe'.  If the environment variable doesn't exist, or it can't be--- 'read', use the default value.+-- 'read', return the default value.  Like 'readEnv' but with a default+-- value. ----- Note that this does not read string values as one would expect.+-- Read an environment variable that exists: ----- >>> import System.Environment (setEnv) -- >>> setEnv "TEST_ENV_VAR1" "1000"--- >>> readEnvVarDef "TEST_ENV_VAR1" 5 :: IO Int+-- >>> readEnvDef "TEST_ENV_VAR1" 5 :: IO Int -- 1000--- >>> readEnvVarDef "THIS_ENV_VAR_WILL_NOT_EXIST" 5 :: IO Int+--+-- Try reading an environment variable that does not exist.  Returns the+-- default value:+--+-- >>> readEnvDef "THIS_ENV_VAR_WILL_NOT_EXIST" 5 :: IO Int -- 5+--+-- Try reading an environment variable that cannot be 'read'.  Returns the+-- default value:+--+-- >>> setEnv "BAD_ENV_VAR" "not an int"+-- >>> readEnvDef "BAD_ENV_VAR" 10 :: IO Int+-- 10+--+-- Note that this __DOES NOT__ read string values as one might expect:+-- -- >>> setEnv "TEST_ENV_VAR2" "some string 1"--- >>> readEnvVarDef "TEST_ENV_VAR2" "def val" :: IO String+-- >>> readEnvDef "TEST_ENV_VAR2" "def val" :: IO String -- "def val"+--+-- It will read string values as if they were Haskell strings:+-- -- >>> setEnv "TEST_ENV_VAR3" "\"some string 1\""--- >>> readEnvVarDef "TEST_ENV_VAR3" "def val" :: IO String+-- >>> readEnvDef "TEST_ENV_VAR3" "def val" :: IO String -- "some string 1"-readEnvVarDef :: Read a-              => String -- ^ environment variable to lookup-              -> a      -- ^ default value to use if the environment variable-                        -- either does not exist, or cannot be 'read'-              -> IO a-readEnvVarDef envVar def = fromMaybe def <$> readEnvVar envVar+readEnvDef+  :: (MonadIO m, Read a)+  => String -- ^ environment variable to lookup+  -> a -- ^ default value to return if the environment variable+       -- either does not exist, or cannot be 'read'+  -> m a+readEnvDef envVar def = do+  maybeEnv <- readEnv envVar+  return $ fromMaybe def maybeEnv  -- | Lookup a value from an environment variable and read it in with -- 'readMaybe'. ----- Note that this does not read string values as one would expect.+-- Read an environment variable that exists: ----- >>> import System.Environment (setEnv) -- >>> setEnv "TEST_ENV_VAR" "2000"--- >>> readEnvVar "TEST_ENV_VAR" :: IO (Maybe Int)+-- >>> readEnv "TEST_ENV_VAR" :: IO (Maybe Int) -- Just 2000--- >>> readEnvVar "THIS_ENV_VAR_WILL_NOT_EXIST" :: IO (Maybe Int)+--+-- Try reading an environment variable that does not exist.  Returns 'Nothing':+--+-- >>> readEnv "THIS_ENV_VAR_WILL_NOT_EXIST" :: IO (Maybe Int) -- Nothing+--+-- Try reading an environment variable that cannot be 'read'.  Returns+-- 'Nothing':+--+-- >>> setEnv "BAD_ENV_VAR" "not an int"+-- >>> readEnv "BAD_ENV_VAR" :: IO (Maybe Int)+-- Nothing+--+-- Note that this __DOES NOT__ read string values as one might expect:+-- -- >>> setEnv "TEST_ENV_VAR2" "some string 1"--- >>> readEnvVar "TEST_ENV_VAR2" :: IO (Maybe String)+-- >>> readEnv "TEST_ENV_VAR2" :: IO (Maybe String) -- Nothing+--+-- It will read string values as if they were Haskell strings:+-- -- >>> setEnv "TEST_ENV_VAR3" "\"some string 1\""--- >>> readEnvVar "TEST_ENV_VAR3" :: IO (Maybe String)+-- >>> readEnv "TEST_ENV_VAR3" :: IO (Maybe String) -- Just "some string 1"-readEnvVar :: Read a-           => String       -- ^ environment variable to lookup-           -> IO (Maybe a)-readEnvVar = fmap (>>= readMaybe) . lookupEnv+readEnv+  :: (MonadIO m, Read a)+  => String -- ^ environment variable to lookup+  -> m (Maybe a)+readEnv envVar = do+  maybeEnv <- liftIO (Env.lookupEnv envVar)+  return $ maybeEnv >>= readMaybe  -- | Like 'lookupEnv' but take a default value. ----- >>> import System.Environment (setEnv)+-- Lookup an environment variable that exists:+-- -- >>> setEnv "TEST_ENV_VAR" "foo" -- >>> lookupEnvDef "TEST_ENV_VAR" "bar" :: IO String -- "foo"+--+-- Lookup an environment variable that doesn't exist.  Return the default+-- value:+-- -- >>> lookupEnvDef "THIS_ENV_VAR_WILL_NOT_EXIST" "bar" :: IO String -- "bar"-lookupEnvDef :: IsString a-             => String  -- ^ environment variable to lookup-             -> a       -- ^ default value to use if environment variable not defined-             -> IO a-lookupEnvDef envVar defaultValue =-    pure . maybe defaultValue fromString =<< lookupEnv envVar+lookupEnvDef+  :: (IsString a, MonadIO m)+  => String -- ^ environment variable to lookup+  -> a -- ^ default value to return if environment variable not defined+  -> m a+lookupEnvDef envVar defaultValue = do+  maybeEnv <- liftIO $ Env.lookupEnv envVar+  return $ maybe defaultValue fromString maybeEnv++-- | Like "System.Environment"\'s 'Env.lookupEnv', but using 'IsString' to make+-- it more general.+--+-- Lookup an environment variable that exists:+--+-- >>> setEnv "TEST_ENV_VAR" "foo"+-- >>> lookupEnv "TEST_ENV_VAR" :: IO (Maybe String)+-- Just "foo"+--+-- Lookup an environment variable that doesn't exist.  Return 'Nothing':+--+-- >>> lookupEnv "THIS_ENV_VAR_WILL_NOT_EXIST" :: IO (Maybe String)+-- Nothing+lookupEnv+  :: (IsString a, MonadIO m)+  => String+  -> m (Maybe a)+lookupEnv envVar = do+  maybeEnv <- liftIO $ Env.lookupEnv envVar+  return $ fmap fromString maybeEnv++-- | 'Exception' thrown by 'lookupEnvEx' and 'readEnvEx' when the+-- environment variable being read doesn't exist.+data EnvVarDoesNotExistException =+  -- | The 'String' is the name of the environment variable that does not+  -- exist.+  EnvVarDoesNotExistException String+  deriving (Data, Eq, Ord, Read, Show, Typeable)++instance Exception EnvVarDoesNotExistException++-- | Like 'lookupEnv', but instead of returning a 'Maybe', throw an+-- 'EnvVarDoesNotExistException' if the environment variable does not exist.+-- The exception is thrown with 'throwM' from 'MonadThrow'.+--+-- Lookup an environment variable that exists:+--+-- >>> setEnv "TEST_ENV_VAR" "foo"+-- >>> lookupEnvEx "TEST_ENV_VAR" :: IO String+-- "foo"+--+-- Lookup an environment variable that doesn't exist.  Throws+-- 'EnvVarDoesNotExistException'.+--+-- >>> lookupEnvEx "THIS_ENV_VAR_WILL_NOT_EXIST" :: IO String+-- *** Exception: EnvVarDoesNotExistException "THIS_ENV_VAR_WILL_NOT_EXIST"+lookupEnvEx+  :: (IsString a, MonadIO m, MonadThrow m)+  => String+  -> m a+lookupEnvEx envVar = do+  maybeEnv <- liftIO (Env.lookupEnv envVar)+  case maybeEnv of+    Nothing -> throwM $ EnvVarDoesNotExistException envVar+    Just env -> return $ fromString env++-- | Lookup a value from an environment variable and read it in with+-- 'readMaybe'.  Throw an 'EnvVarDoesNotExistException' if the environment+-- variable does not exist.  The exception is thrown with 'throwM' from+-- 'MonadThrow'.+--+-- Read an environment variable that exists:+--+-- >>> setEnv "TEST_ENV_VAR" "2000"+-- >>> readEnvEx "TEST_ENV_VAR" :: IO (Maybe Int)+-- Just 2000+--+-- Try reading an environment variable that does not exist.  Throws+-- 'EnvVarDoesNotExistException':+--+-- >>> readEnvEx "THIS_ENV_VAR_WILL_NOT_EXIST" :: IO (Maybe Int)+-- *** Exception: EnvVarDoesNotExistException "THIS_ENV_VAR_WILL_NOT_EXIST"+--+-- Try reading an environment variable that cannot be 'read'.  Returns+-- 'Nothing':+--+-- >>> setEnv "BAD_ENV_VAR" "not an int"+-- >>> readEnvEx "BAD_ENV_VAR" :: IO (Maybe Int)+-- Nothing+--+-- Note that this __DOES NOT__ read string values as one might expect:+--+-- >>> setEnv "TEST_ENV_VAR2" "some string 1"+-- >>> readEnvEx "TEST_ENV_VAR2" :: IO (Maybe String)+-- Nothing+--+-- It will read string values as if they were Haskell strings:+--+-- >>> setEnv "TEST_ENV_VAR3" "\"some string 1\""+-- >>> readEnvEx "TEST_ENV_VAR3" :: IO (Maybe String)+-- Just "some string 1"+readEnvEx+  :: (MonadIO m, Read a, MonadThrow m)+  => String -- ^ environment variable to lookup+  -> m (Maybe a)+readEnvEx envVar = do+  maybeEnv <- liftIO (Env.lookupEnv envVar)+  case maybeEnv of+    Nothing -> throwM $ EnvVarDoesNotExistException envVar+    Just env -> return $ readMaybe env++-- | 'Exception' thrown by 'readEnvEx'' when the environment variable+-- cannot be 'read'.+data EnvVarCannotBeReadException =+  -- | The first 'String' is the name of the environment variable that cannot+  -- be 'read'.+  EnvVarCannotBeReadException String+  deriving (Data, Eq, Ord, Read, Show, Typeable)++instance Exception EnvVarCannotBeReadException++-- | Just like 'readEnvEx', but also throw an exception when the environment+-- variable cannot be 'read'.+--+-- This can throw both 'EnvVarCannotBeReadException' and+-- 'EnvVarDoesNotExistException' with 'throwM'.+--+-- Read an environment variable that exists:+--+-- >>> setEnv "TEST_ENV_VAR" "2000"+-- >>> readEnvEx' "TEST_ENV_VAR" :: IO Int+-- 2000+--+-- Try reading an environment variable that does not exist.  Throws+-- 'EnvVarDoesNotExistException':+--+-- >>> readEnvEx' "THIS_ENV_VAR_WILL_NOT_EXIST" :: IO Int+-- *** Exception: EnvVarDoesNotExistException "THIS_ENV_VAR_WILL_NOT_EXIST"+--+-- Try reading an environment variable that cannot be 'read'.  Throws+-- 'EnvVarCannotBeReadException':+--+-- >>> setEnv "BAD_ENV_VAR" "not an int"+-- >>> readEnvEx' "BAD_ENV_VAR" :: IO Int+-- *** Exception: EnvVarCannotBeReadException "BAD_ENV_VAR"+--+-- Note that this __DOES NOT__ read string values as one might expect:+--+-- >>> setEnv "TEST_ENV_VAR2" "some string 1"+-- >>> readEnvEx' "TEST_ENV_VAR2" :: IO String+-- *** Exception: EnvVarCannotBeReadException "TEST_ENV_VAR2"+--+-- It will read string values as if they were Haskell strings:+--+-- >>> setEnv "TEST_ENV_VAR3" "\"some string 1\""+-- >>> readEnvEx' "TEST_ENV_VAR3" :: IO String+-- "some string 1"+readEnvEx'+  :: (MonadIO m, Read a, MonadThrow m)+  => String -- ^ environment variable to lookup+  -> m a+readEnvEx' envVar = do+  maybeEnv <- readEnvEx envVar+  case maybeEnv of+    Nothing -> throwM $ EnvVarCannotBeReadException envVar+    Just env -> return env