packages feed

envparse 0.1.0 → 0.2.0

raw patch · 7 files changed

+134/−43 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Env: parseTest :: Parser a -> [(String, String)] -> Maybe a
+ Env: parseOr :: (String -> IO a) -> Mod Info b -> Parser b -> IO (Either a b)
+ Env: parsePure :: Mod Info a -> Parser a -> [(String, String)] -> Either String a
+ Env: prefixed :: String -> Parser a -> Parser a

Files

+ CHANGELOG.markdown view
@@ -0,0 +1,13 @@+0.2.0+=====++  * Added `prefixed`.++  * Added `parseOr`, a slightly generalized version of `parse`.++  * Renamed `parseTest` to `parsePure`++0.1.0+=====++  * Initial release.
envparse.cabal view
@@ -1,8 +1,8 @@ name:                envparse-version:             0.1.0+version:             0.2.0 synopsis:            Parse environment variables description:-  Here's a simple example+  Here's a simple example of a program that uses @envparse@'s parser:   .   @   module Main (main) where@@ -23,7 +23,28 @@     unless quiet $       putStrLn (\"Hello, \" ++ name ++ \"!\")   @-homepage:            http://example.com/+  .+  The @NAME@ environment variable is mandatory and contains the name of the person to+  greet. @QUIET@, on the other hand, is an optional boolean flag, false by default, that+  decides whether the greeting should be silent.+  .+  If the @NAME@ variable is undefined in the environment then running the program will+  result in the following help text:+  .+  @+  envparse example+   +  Available environment variables:+   +    NAME                   Target for the greeting+    QUIET                  Whether to actually print the+                           greeting+   +  Parsing errors:+   +    NAME is missing+  @+homepage:            https://supki.github.io/envparse license:             BSD2 license-file:        LICENSE author:              Matvey Aksenov@@ -34,11 +55,17 @@ cabal-version:       >= 1.10 extra-source-files:   README.markdown+  CHANGELOG.markdown   example/Main.hs  source-repository head   type:     git   location: https://github.com/supki/envparse++source-repository this+  type:     git+  location: https://github.com/supki/envparse+  tag:      0.2.0  library   default-language:
example/Main.hs view
@@ -24,5 +24,5 @@  hello :: IO Hello hello = Env.parse (header "envparse example") $-  Hello <$> var (str <=< nonempty) "NAME" (help "Target for the greeting")-        <*> switch "QUIET" (help "Whether to actually print the greeting")+  Hello <$> var (str <=< nonempty) "NAME"  (help "Target for the greeting")+        <*> switch                 "QUIET" (help "Whether to actually print the greeting")
src/Env.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE Safe #-}--- | Here's a simple example+-- | Here's a simple example of a program that uses @envparse@'s parser: -- -- @ -- module Main (main) where@@ -10,7 +10,7 @@ -- data Hello = Hello { name :: String, quiet :: Bool } -- -- hello :: IO Hello--- hello = 'Env.parse' ('header' \"envparse example\") $+-- hello = Env.'parse' ('header' \"envparse example\") $ --   Hello \<$\> 'var' ('str' <=< 'nonempty') \"NAME\"  ('help' \"Target for the greeting\") --         \<*\> 'switch'                 \"QUIET\" ('help' \"Whether to actually print the greeting\") --@@ -20,14 +20,37 @@ --   unless quiet $ --     putStrLn (\"Hello, \" ++ name ++ \"!\") -- @+--+-- The @NAME@ environment variable is mandatory and contains the name of the person to+-- greet. @QUIET@, on the other hand, is an optional boolean flag, false by default, that+-- decides whether the greeting should be silent.+--+-- If the @NAME@ variable is undefined in the environment then running the program will+-- result in the following help text:+--+-- @+-- envparse example+--+-- Available environment variables:+--+--   NAME                   Target for the greeting+--   QUIET                  Whether to actually print the+--                          greeting+--+-- Parsing errors:+--+--   NAME is missing+-- @ module Env   ( parse+  , parseOr   , Parser   , Mod   , Info   , header   , desc   , footer+  , prefixed   , var   , Var   , Reader@@ -50,7 +73,7 @@   , asum   -- * Testing   -- $testing-  , parseTest+  , parsePure   ) where  import           Control.Applicative@@ -72,22 +95,31 @@ -- what you want them to do  --- | Parse the environment+-- | Parse the environment or die ----- Prints the help text and exits with @EXIT_FAILURE@ if it encounters a parse error+-- Prints the help text and exits with @EXIT_FAILURE@ on encountering a parse error. -- -- @--- >>> parse ('header' \"env-parse 0.1.0\") ('var' 'str' \"USER\" ('def' \"nobody\"))+-- >>> parse ('header' \"env-parse 0.2.0\") ('var' 'str' \"USER\" ('def' \"nobody\")) -- @ parse :: Mod Info a -> Parser a -> IO a-parse i p = either (die . helpDoc i p) return . static p =<< getEnvironment+parse m = fmap (either (\_ -> error "absurd") id) . parseOr die m +-- | Try to parse the environment+--+-- Use this if simply dying on failure (the behavior of 'parse') is inadequate for your needs.+parseOr :: (String -> IO a) -> Mod Info b -> Parser b -> IO (Either a b)+parseOr f m p = traverseLeft f . parsePure m p =<< getEnvironment+ die :: String -> IO a die m = do IO.hPutStrLn IO.stderr m; exitFailure --- | Parse a static environment-parseTest :: Parser a -> [(String, String)] -> Maybe a-parseTest p = hush . static p+-- | Try to parse a pure environment+parsePure :: Mod Info a -> Parser a -> [(String, String)] -> Either String a+parsePure (Mod f) p = mapLeft (helpDoc (f defaultInfo) p) . static p -hush :: Either a b -> Maybe b-hush = either (const Nothing) Just+mapLeft :: (a -> b) -> Either a t -> Either b t+mapLeft f = either (Left . f) Right++traverseLeft :: Applicative f => (a -> f b) -> Either a t -> f (Either b t)+traverseLeft f = either (fmap Left . f) (pure . Right)
src/Env/Free.hs view
@@ -1,12 +1,15 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-}--- @Alt F@ is the free 'Alternative' functor on @F@+-- | @Alt F@ is the free 'Alternative' functor on @F@ module Env.Free   ( Alt(..)   , liftAlt   , runAlt   , foldAlt+  , hoistAlt+  -- * Debug+  , inspect   ) where  import Control.Applicative (Applicative(..), Alternative(..))@@ -18,14 +21,22 @@   Pure :: a -> Alt f a   Ap   :: Alt f (a -> b) -> Alt f a -> Alt f b   Alt  :: Alt f a -> Alt f a -> Alt f a-  Fun  :: f a -> Alt f a+  Lift :: f a -> Alt f a +-- | Print the free structure+inspect :: Alt f a -> String+inspect Nope      = "Nope"+inspect (Pure _)  = "Pure _"+inspect (Ap f x)  = concat ["(", inspect f, ") <*> (", inspect x, ")"]+inspect (Alt x y) = concat ["(", inspect x, ") <|> (", inspect y, ")"]+inspect (Lift _)  = "Lift _"+ instance Functor f => Functor (Alt f) where   fmap _ Nope      = Nope   fmap f (Pure a)  = Pure (f a)   fmap f (Ap a v)  = Ap (fmap (f .) a) v   fmap f (Alt a b) = Alt (fmap f a) (fmap f b)-  fmap f (Fun a)   = Fun (fmap f a)+  fmap f (Lift a)  = Lift (fmap f a)  instance Functor f => Applicative (Alt f) where   pure = Pure@@ -37,7 +48,7 @@   liftAlt :: f a -> Alt f a-liftAlt = Fun+liftAlt = Lift  runAlt :: forall f g a. Alternative g => (forall x. f x -> g x) -> Alt f a -> g a runAlt u = go where@@ -46,10 +57,13 @@   go (Pure a)  = pure a   go (Ap f x)  = go f <*> go x   go (Alt s t) = go s <|> go t-  go (Fun x)   = u x+  go (Lift x)  = u x  foldAlt :: Monoid p => (forall a. f a -> p) -> Alt f b -> p foldAlt f = unMon . runAlt (Mon . f)++hoistAlt :: forall f g b. Functor g => (forall a. f a -> g a) -> Alt f b -> Alt g b+hoistAlt nat = runAlt (Lift . nat)   -- | The 'Alternative' functor induced by the 'Monoid'
src/Env/Help.hs view
@@ -12,16 +12,15 @@ import           Env.Parse  -helpDoc :: Mod Info a -> Parser a -> [Error] -> String-helpDoc (Mod f) p fs = intercalate "\n\n" . catMaybes $-  [ infoHeader-  , fmap (intercalate "\n" . splitWords 50) infoDesc-  , Just "Available environment variables:"-  , Just (intercalate "\n" (helpParserDoc p))-  , fmap (intercalate "\n" . splitWords 50) infoFooter-  ] ++ map Just (helpFailuresDoc fs)- where-  Info { infoHeader, infoDesc, infoFooter } = f defaultInfo+helpDoc :: Info a -> Parser b -> [Error] -> String+helpDoc Info { infoHeader, infoDesc, infoFooter } p fs =+  intercalate "\n\n" . catMaybes $+    [ infoHeader+    , fmap (intercalate "\n" . splitWords 50) infoDesc+    , Just "Available environment variables:"+    , Just (intercalate "\n" (helpParserDoc p))+    , fmap (intercalate "\n" . splitWords 50) infoFooter+    ] ++ map Just (helpFailuresDoc fs)  helpParserDoc :: Parser a -> [String] helpParserDoc = concat . Map.elems . foldAlt (\v -> Map.singleton (varfName v) (helpVarfDoc v)) . unParser
src/Env/Parse.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE ViewPatterns #-} module Env.Parse   ( Parser(..)   , VarF(..)@@ -11,6 +12,7 @@   , header   , desc   , footer+  , prefixed   , var   , Var(..)   , defaultVar@@ -37,12 +39,11 @@ import           Env.Val  -static :: Parser a -> [(String, String)] -> Either [Error] a-static (Parser p) xs = toEither (runAlt go p)+static :: Parser b -> [(String, String)] -> Either [Error] b+static (Parser p) (Map.fromList -> env) =+  toEither (runAlt go p)  where-  go v = maybe id (\d x -> x <|> pure d) (varfDef v) (fromEither (readVar v =<< lookupVar v ys))--  ys = Map.fromList xs+  go v = maybe id (\d x -> x <|> pure d) (varfDef v) (fromEither (readVar v =<< lookupVar v env))  lookupVar :: VarF a -> Map String String -> Either [Error] String lookupVar v = note [ENoExistError (varfName v)] . Map.lookup (varfName v)@@ -69,7 +70,12 @@   empty = Parser empty   Parser f <|> Parser x = Parser (f <|> x) +-- | The string to prepend to the name of every declared environment variable+prefixed :: String -> Parser a -> Parser a+prefixed pre =+  Parser . hoistAlt (\v -> v { varfName = pre ++ varfName v }) . unParser + data Error   = ParseError String String   | ENoExistError String@@ -151,16 +157,16 @@  -- | Parser's metadata data Info a = Info-  { infoHeader :: Maybe String-  , infoDesc   :: Maybe String-  , infoFooter :: Maybe String+  { infoHeader   :: Maybe String+  , infoDesc     :: Maybe String+  , infoFooter   :: Maybe String   }  defaultInfo :: Info a defaultInfo = Info-  { infoHeader = Nothing-  , infoDesc   = Nothing-  , infoFooter = Nothing+  { infoHeader   = Nothing+  , infoDesc     = Nothing+  , infoFooter   = Nothing   }  -- | A help text header (it usually includes an application name and version)