packages feed

commander-cli 0.5.0.0 → 0.6.0.0

raw patch · 5 files changed

+116/−33 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Options.Commander: Optional :: Optionality
+ Options.Commander: Required :: Optionality
+ Options.Commander: data Env :: Optionality -> Symbol -> * -> *
+ Options.Commander: data Optionality
+ Options.Commander: env :: KnownSymbol name => (x -> ProgramT p m a) -> ProgramT (Env 'Required name x & p) m a
+ Options.Commander: envOpt :: KnownSymbol name => (Maybe x -> ProgramT p m a) -> ProgramT (Env 'Optional name x & p) m a
+ Options.Commander: envOptDef :: KnownSymbol name => x -> (x -> ProgramT p m a) -> ProgramT (Env 'Optional name x & p) m a
+ Options.Commander: instance (Options.Commander.Unrender t, GHC.TypeLits.KnownSymbol name, Options.Commander.HasProgram p) => Options.Commander.HasProgram (Options.Commander.Env 'Options.Commander.Optional name t Options.Commander.& p)
+ Options.Commander: instance (Options.Commander.Unrender t, GHC.TypeLits.KnownSymbol name, Options.Commander.HasProgram p) => Options.Commander.HasProgram (Options.Commander.Env 'Options.Commander.Required name t Options.Commander.& p)

Files

README.md view
@@ -10,13 +10,13 @@  ```bash usage:-task-manager help -task-manager -d <task-directory :: [Char]> edit <task-name :: [Char]> -task-manager -d <task-directory :: [Char]> open <task-name :: [Char]> -task-manager -d <task-directory :: [Char]> close <task-name :: [Char]> -task-manager -d <task-directory :: [Char]> tasks -task-manager -d <task-directory :: [Char]> priorities -task-manager -d <task-directory :: [Char]> +task-manager help+task-manager (required env: TASK_DIRECTORY :: [Char]> edit <task-name :: [Char]>+task-manager (required env: TASK_DIRECTORY :: [Char]> open <task-name :: [Char]>+task-manager (required env: TASK_DIRECTORY :: [Char]> close <task-name :: [Char]>+task-manager (required env: TASK_DIRECTORY :: [Char]> tasks+task-manager (required env: TASK_DIRECTORY :: [Char]> priorities+task-manager (required env: TASK_DIRECTORY :: [Char]> ```  
Test.hs view
@@ -15,10 +15,11 @@ import Control.Monad import System.Exit import Control.Exception+import System.Environment (setEnv) import Data.Maybe  main :: IO ()-main = rawTest >> argTest >> optTest >> flagTest >> bigProgTests+main = rawTest >> argTest >> optTest >> flagTest >> bigProgTests >> optDefTest >> envTest  rawProg :: ProgramT Raw IO Bool rawProg = raw (pure True)@@ -74,6 +75,21 @@ optDefProg prop = optDef "Default" \o -> raw (pure (prop o))  optDefTest :: IO ()-optDefTest = parlay (== "Default") (State mempty mempty mempty)-          >> parlay (== "hello") (State mempty (HashMap.fromList [("o", "hello")]) mempty) where-  parlay prop state = maybe exitFailure (cond (pure ()) exitFailure) =<< runCommanderT (run (optDefProg prop)) state+optDefTest = +     parlay (pure ()) exitFailure (== "Default") (State mempty mempty mempty)+  >> parlay (pure ()) exitFailure (== "hello") (State mempty (HashMap.fromList [("o", "hello")]) mempty)+  >> parlay exitFailure (pure ()) (== "Default0") (State mempty mempty mempty)+  >> parlay exitFailure (pure ()) (== "hello0") (State mempty (HashMap.fromList [("o", "hello")]) mempty)+  where+  parlay y n prop state = maybe exitFailure (cond y n) =<< runCommanderT (run (optDefProg prop)) state++envProg :: (x -> Bool) -> ProgramT (Env 'Required "ONOGOTTAFINDABIGNAME" x & Raw) IO Bool+envProg prop = env \e -> raw (pure (prop e))++envTest :: IO ()+envTest = do+  testBool =<< isNothing <$> test (envProg (== ("POOP" :: String))) (State mempty mempty mempty)+  setEnv "ONOGOTTAFINDABIGNAME" "POOP"+  testMaybeBool =<< test (envProg (== ("POOP" :: String))) (State mempty mempty mempty)+  setEnv "ONOGOTTAFINDABIGNAME" "POP"+  testMaybeBool =<< fmap not <$> test (envProg (== ("POOP" :: String))) (State mempty mempty mempty)
app/Main.hs view
@@ -13,7 +13,7 @@ import Options.Commander  import Prelude import System.Directory-import System.Process+import System.Process hiding (env) import Data.List import Text.Read import System.Exit@@ -22,7 +22,7 @@ type TaskManager   = Named "task-manager"   & ("help" & Raw-  + Opt "d" "task-directory" FilePath+  + Env 'Required "TASK_DIRECTORY" FilePath     & ("edit"  & TaskProgram      + "open"  & TaskProgram      + "close" & TaskProgram@@ -35,7 +35,7 @@ type TaskProgram = Arg "task-name" String & Raw    taskManager :: ProgramT TaskManager IO ()-taskManager = toplevel @"task-manager" . optDef @"d" @"task-directory" "tasks" $ \tasksFilePath -> +taskManager = toplevel @"task-manager" . env @"TASK_DIRECTORY" $ \tasksFilePath ->        sub @"edit" (editTask tasksFilePath)    <+> sub @"open" (newTask tasksFilePath)   <+> sub @"close" (closeTask tasksFilePath)
commander-cli.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.4  name:                commander-cli-version:             0.5.0.0+version:             0.6.0.0 synopsis:            A command line argument/option parser library built around a monadic metaphor description:         A command line argument/option parser library built around a monadic metaphor. homepage:            https://github.com/SamuelSchlesinger/commander-cli
src/Options/Commander.hs view
@@ -54,6 +54,7 @@  @ usage:+file help file maybe-read \<filename :: String\> ~read file maybe-write -file \<file-to-write :: String\> @@@ -74,13 +75,13 @@   {- |     To construct a 'ProgramT' (a specification of a CLI program), you can     have 'arg'uments, 'opt'ions, 'raw' actions in a monad (typically IO),-    'sub'programs, 'named' programs, you can combine programs together using -    '<+>', and you can generate primitive 'usage' information with 'usage'.-    We also have a convenience combinator, 'toplevel', which lets you add-    a name and a help command to your program using the 'usage' combinator.+    'sub'programs, 'named' programs, 'env'ironment variables, you can combine +    programs together using '<+>', and you can generate primitive 'usage'+    information with 'usage'. There are combinators for retrieving environment+    variables as well. We also have a convenience combinator, 'toplevel',+    which lets you add a name and a help command to your program using the 'usage' combinator.   -}-  arg, opt, optDef, raw, sub, named, flag, toplevel, (<+>), usage,-  -- ** Describing CLI Programs+  arg, opt, optDef, raw, sub, named, flag, toplevel, (<+>), usage, env, envOpt, envOptDef,   -- ** Run CLI Programs   {- |     To run a 'ProgramT' (a specification of a CLI program), you will @@ -91,7 +92,7 @@     Each 'ProgramT' has a type level description, build from these type level     combinators.   -}-  type (&), type (+), Arg, Opt, Named, Raw, Flag,+  type (&), type (+), Arg, Opt, Named, Raw, Flag, Env, Optionality(Required, Optional),   -- ** Interpreting CLI Programs   {- |     The 'HasProgram' class forms the backbone of this library, defining the@@ -105,6 +106,8 @@            SubProgramT, unSubProgramT,            NamedProgramT, unNamedProgramT,            FlagProgramT, unFlagProgramT,+           EnvProgramT'Optional, unEnvProgramT'Optional, unEnvDefault,+           EnvProgramT'Required, unEnvProgramT'Required,            (:+:)            ),   -- ** The CommanderT Monad@@ -138,7 +141,7 @@ import GHC.TypeLits (Symbol, KnownSymbol, symbolVal) import GHC.Generics (Generic) import Numeric.Natural-import System.Environment (getArgs)+import System.Environment (getArgs, lookupEnv) import Data.Typeable (Typeable, typeRep) import qualified Data.ByteString as SBS import qualified Data.ByteString.Char8 as BS8@@ -215,6 +218,10 @@ instance Unrender Char where   unrender = find (const True) +-- | The type level naming combinator, giving your program a name for the+-- sake of documentation.+data Named :: Symbol -> *+ -- | The type level argument combinator, with a 'Symbol' designating the -- name of that argument. data Arg :: Symbol -> * -> *@@ -224,23 +231,27 @@ -- documentation purposes. data Opt :: Symbol -> Symbol -> * -> * --- | The type level naming combinator, giving your program a name for the--- sake of documentation.-data Named :: Symbol -> *+-- | The type level flag combinator, taking a name as input, allowing your+-- program to take flags with the syntax @~flag@.+data Flag :: Symbol -> * --- | The type level program sequencing combinator, taking two program types--- and sequencing them one after another.-data (&) :: k -> * -> *-infixr 4 &+-- | The type level environment variable combinator, taking a name as+-- input, allowing your program to take environment variables as input+-- automatically.+data Env :: Optionality -> Symbol -> * -> *  -- | The type level raw monadic program combinator, allowing a command line -- program to just do some computation. data Raw :: * --- | The type level flag combinator, taking a name as input, allowing your--- program to take flags with the syntax @~flag@.-data Flag :: Symbol -> *+-- | The type level tag for whether or not a variable is required or not.+data Optionality = Required | Optional +-- | The type level program sequencing combinator, taking two program types+-- and sequencing them one after another.+data (&) :: k -> * -> *+infixr 4 &+ -- | The type level combining combinator, taking two program types as -- input, and being interpreted as a program which attempts to run the -- first command line program and, if parsing its flags, subprograms,@@ -394,6 +405,41 @@   hoist :: (forall x. m x -> n x) -> ProgramT p m a -> ProgramT p n a   invocations :: [Text] +instance (Unrender t, KnownSymbol name, HasProgram p) => HasProgram (Env 'Required name t & p) where+  newtype ProgramT (Env 'Required name t & p) m a = EnvProgramT'Required { unEnvProgramT'Required :: t -> ProgramT p m a }+  run f = Action $ \state -> do+    val <- lookupEnv (symbolVal (Proxy @name))+    case val of+      Just v ->+        case unrender (pack v) of+          Just t -> return (run (unEnvProgramT'Required f t), state)  +          Nothing -> return (Defeat, state)+      Nothing -> return (Defeat, state)+  hoist n (EnvProgramT'Required f) = EnvProgramT'Required (hoist n . f)+  invocations =+    [(("(required env: " <> pack (symbolVal (Proxy @name))+    <> " :: " <> pack (show (typeRep (Proxy @t)))+    <> "> ") <>)] <*> invocations @p++instance (Unrender t, KnownSymbol name, HasProgram p) => HasProgram (Env 'Optional name t & p) where+  data ProgramT (Env 'Optional name t & p) m a = EnvProgramT'Optional+    { unEnvProgramT'Optional :: Maybe t -> ProgramT p m a+    , unEnvDefault :: Maybe t }+  run f = Action $ \state -> do+    val <- lookupEnv (symbolVal (Proxy @name))+    case val of+      Just v ->+        case unrender (pack v) of+          Just t -> return (run (unEnvProgramT'Optional f t), state)  +          Nothing -> return (Defeat, state)+      Nothing -> return (run (unEnvProgramT'Optional f (unEnvDefault f)), state)++  hoist n (EnvProgramT'Optional f d) = EnvProgramT'Optional (hoist n . f) d+  invocations =+    [(("(optional env: " <> pack (symbolVal (Proxy @name))+    <> " :: " <> pack (show (typeRep (Proxy @t)))+    <> "> ") <>)] <*> invocations @p+ instance (Unrender t, KnownSymbol name, HasProgram p) => HasProgram (Arg name t & p) where   newtype ProgramT (Arg name t & p) m a = ArgProgramT { unArgProgramT :: t -> ProgramT p m a }   run f = Action $ \State{..} -> do@@ -501,6 +547,27 @@         => ProgramT p IO a          -> IO (Maybe a) command prog = initialState >>= runCommanderT (run prog)++-- | Required environment variable combinator+env :: KnownSymbol name+  => (x -> ProgramT p m a)+  -> ProgramT (Env 'Required name x & p) m a+env = EnvProgramT'Required++-- | Optional environment variable combinator+envOpt :: KnownSymbol name+  => (Maybe x -> ProgramT p m a)+  -> ProgramT (Env 'Optional name x & p) m a+envOpt = flip EnvProgramT'Optional Nothing++-- | Optional environment variable combinator with default+envOptDef :: KnownSymbol name+  => x+  -> (x -> ProgramT p m a)+  -> ProgramT (Env 'Optional name x & p) m a+envOptDef x f = EnvProgramT'Optional { unEnvDefault = Just x, unEnvProgramT'Optional = \case { Just x -> f x; Nothing -> error "Violated invariant of optEnvDef" } }++-- | Environment   -- | Argument combinator arg :: KnownSymbol name