packages feed

harg 0.1.0.1 → 0.1.3.0

raw patch · 10 files changed

+384/−126 lines, 10 filesdep +splitdep ~barbiesdep ~higgledyPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: split

Dependency ranges changed: barbies, higgledy

API changes (from Hackage documentation)

+ Options.Harg: manyParser :: String -> OptReader a -> OptReader [a]
+ Options.Harg: optDefaultStr :: (HasDefaultStr o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optDefaultStr" '["optDefault", "optRequired"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "optDefaultStr" "optOptional")) => String -> o attr a -> o (OptDefault : attr) a
+ Options.Harg: optRequired :: (HasRequired o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optRequired" '["optDefault", "optDefaultStr"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "optRequired" "optOptional")) => o attr a -> o (OptDefault : attr) a
+ Options.Harg.Construct: class HasDefaultStr o (attr :: [OptAttr])
+ Options.Harg.Construct: class HasRequired o (attr :: [OptAttr])
+ Options.Harg.Construct: instance Options.Harg.Construct.HasDefaultStr Options.Harg.Types.ArgumentOpt a
+ Options.Harg.Construct: instance Options.Harg.Construct.HasDefaultStr Options.Harg.Types.OptionOpt a
+ Options.Harg.Construct: instance Options.Harg.Construct.HasRequired Options.Harg.Types.ArgumentOpt a
+ Options.Harg.Construct: instance Options.Harg.Construct.HasRequired Options.Harg.Types.OptionOpt a
+ Options.Harg.Construct: manyParser :: String -> OptReader a -> OptReader [a]
+ Options.Harg.Construct: optDefaultStr :: (HasDefaultStr o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optDefaultStr" '["optDefault", "optRequired"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "optDefaultStr" "optOptional")) => String -> o attr a -> o (OptDefault : attr) a
+ Options.Harg.Construct: optRequired :: (HasRequired o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optRequired" '["optDefault", "optDefaultStr"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "optRequired" "optOptional")) => o attr a -> o (OptDefault : attr) a
+ Options.Harg.Construct: type DuplicateAttrErr attr = QuoteSym attr :<>: 'Text " is already specified."
+ Options.Harg.Construct: type DuplicateAttrMultipleErr attr rest = QuoteSym attr :<>: 'Text (CommaSep rest) :<>: 'Text " has already been specified."
+ Options.Harg.Construct: type IncompatibleAttrsErr l r = QuoteSym l :<>: 'Text " and " :<>: QuoteSym r :<>: 'Text " cannot be mixed in an option definition."
+ Options.Harg.Sources: hiddenSources :: HiddenSources f
+ Options.Harg.Sources: type DefaultSources = EnvSource
+ Options.Harg.Sources: type HiddenSources = DefaultStrSource
+ Options.Harg.Sources.DefaultStr: DefaultStrSource :: DefaultStrSource
+ Options.Harg.Sources.DefaultStr: DefaultStrSourceVal :: DefaultStrSourceVal
+ Options.Harg.Sources.DefaultStr: data DefaultStrSource (f :: Type -> Type)
+ Options.Harg.Sources.DefaultStr: data DefaultStrSourceVal
+ Options.Harg.Sources.DefaultStr: instance Data.Barbie.Internal.Functor.FunctorB Options.Harg.Sources.DefaultStr.DefaultStrSource
+ Options.Harg.Sources.DefaultStr: instance Data.Barbie.Internal.Functor.FunctorB a => Options.Harg.Sources.Types.RunSource Options.Harg.Sources.DefaultStr.DefaultStrSourceVal a
+ Options.Harg.Sources.DefaultStr: instance Data.Barbie.Internal.Product.ProductB Options.Harg.Sources.DefaultStr.DefaultStrSource
+ Options.Harg.Sources.DefaultStr: instance Data.Barbie.Internal.Traversable.TraversableB Options.Harg.Sources.DefaultStr.DefaultStrSource
+ Options.Harg.Sources.DefaultStr: instance GHC.Generics.Generic (Options.Harg.Sources.DefaultStr.DefaultStrSource f)
+ Options.Harg.Sources.DefaultStr: instance Options.Harg.Sources.Types.GetSource Options.Harg.Sources.DefaultStr.DefaultStrSource f
+ Options.Harg.Sources.DefaultStr: runDefaultStrSource :: forall a f. (FunctorB a, Applicative f) => a (Compose Opt f) -> a (Compose SourceRunResult f)
+ Options.Harg.Types: [_aDefaultStr] :: ArgumentOpt a -> Maybe String
+ Options.Harg.Types: [_oDefaultStr] :: OptionOpt a -> Maybe String
+ Options.Harg.Types: [_optDefaultStr] :: Opt a -> Maybe String
- Options.Harg: defaultSources :: EnvSource f
+ Options.Harg: defaultSources :: DefaultSources f
- Options.Harg: execCommands :: forall c ts xs. (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal c)) xs, All (RunSource ()) xs, MapAssocList xs) => c Opt -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
+ Options.Harg: execCommands :: forall c ts xs. (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal (c :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => c Opt -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
- Options.Harg: execCommandsDef :: forall ts xs. (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource EnvSourceVal) xs, All (RunSource ()) xs, MapAssocList xs) => AssocListF ts xs Opt -> IO (VariantF xs Identity)
+ Options.Harg: execCommandsDef :: forall ts xs. (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource (SourceVal (DefaultSources :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => AssocListF ts xs Opt -> IO (VariantF xs Identity)
- Options.Harg: optDefault :: (HasDefault o attr, NotInAttrs OptOptional attr "optDefault" "optOptional") => a -> o attr a -> o (OptDefault : attr) a
+ Options.Harg: optDefault :: (HasDefault o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optDefault" '["optDefaultStr", "optRequired"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "optDefault" "optOptional")) => a -> o attr a -> o (OptDefault : attr) a
- Options.Harg: optOptional :: (HasOptional o attr, NotInAttrs OptDefault attr "optOptional" "optDefault") => o attr a -> o (OptOptional : attr) (Maybe a)
+ Options.Harg: optOptional :: (HasOptional o attr, NotInAttrs OptOptional attr (DuplicateAttrErr "optOptional"), NotInAttrs OptDefault attr (IncompatibleAttrsErr "optOptional" "optDefault")) => o attr a -> o (OptOptional : attr) (Maybe a)
- Options.Harg.Construct: optDefault :: (HasDefault o attr, NotInAttrs OptOptional attr "optDefault" "optOptional") => a -> o attr a -> o (OptDefault : attr) a
+ Options.Harg.Construct: optDefault :: (HasDefault o attr, NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optDefault" '["optDefaultStr", "optRequired"]), NotInAttrs OptOptional attr (IncompatibleAttrsErr "optDefault" "optOptional")) => a -> o attr a -> o (OptDefault : attr) a
- Options.Harg.Construct: optOptional :: (HasOptional o attr, NotInAttrs OptDefault attr "optOptional" "optDefault") => o attr a -> o (OptOptional : attr) (Maybe a)
+ Options.Harg.Construct: optOptional :: (HasOptional o attr, NotInAttrs OptOptional attr (DuplicateAttrErr "optOptional"), NotInAttrs OptDefault attr (IncompatibleAttrsErr "optOptional" "optDefault")) => o attr a -> o (OptOptional : attr) (Maybe a)
- Options.Harg.Construct: type family NotInAttrs (x :: k) (xs :: [k]) (l :: Symbol) (r :: Symbol) :: Constraint
+ Options.Harg.Construct: type family CommaSep' (s :: Symbol) (xs :: [Symbol]) :: Symbol
- Options.Harg.Operations: execCommands :: forall c ts xs. (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal c)) xs, All (RunSource ()) xs, MapAssocList xs) => c Opt -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
+ Options.Harg.Operations: execCommands :: forall c ts xs. (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal (c :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => c Opt -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
- Options.Harg.Operations: execCommandsDef :: forall ts xs. (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource EnvSourceVal) xs, All (RunSource ()) xs, MapAssocList xs) => AssocListF ts xs Opt -> IO (VariantF xs Identity)
+ Options.Harg.Operations: execCommandsDef :: forall ts xs. (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource (SourceVal (DefaultSources :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => AssocListF ts xs Opt -> IO (VariantF xs Identity)
- Options.Harg.Operations: execCommandsWithCtx :: forall c ts xs. (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal c)) xs, All (RunSource ()) xs, MapAssocList xs) => HargCtx -> c Opt -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
+ Options.Harg.Operations: execCommandsWithCtx :: forall c ts xs. (TraversableB (VariantF xs), TraversableB c, ProductB c, Subcommands ts xs, GetSource c Identity, All (RunSource (SourceVal (c :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => HargCtx -> c Opt -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
- Options.Harg.Operations: execCommandsWithCtxDef :: forall ts xs. (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource EnvSourceVal) xs, All (RunSource ()) xs, MapAssocList xs) => HargCtx -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
+ Options.Harg.Operations: execCommandsWithCtxDef :: forall ts xs. (TraversableB (VariantF xs), Subcommands ts xs, All (RunSource (SourceVal (DefaultSources :* HiddenSources))) xs, All (RunSource ()) xs, MapAssocList xs) => HargCtx -> AssocListF ts xs Opt -> IO (VariantF xs Identity)
- Options.Harg.Sources: defaultSources :: EnvSource f
+ Options.Harg.Sources: defaultSources :: DefaultSources f
- Options.Harg.Types: ArgumentOpt :: Maybe String -> Maybe String -> Maybe String -> Maybe a -> OptReader a -> ArgumentOpt a
+ Options.Harg.Types: ArgumentOpt :: Maybe String -> Maybe String -> Maybe String -> Maybe a -> Maybe String -> OptReader a -> ArgumentOpt a
- Options.Harg.Types: Opt :: Maybe String -> Maybe Char -> Maybe String -> Maybe String -> Maybe String -> Maybe a -> OptReader a -> OptType a -> Opt a
+ Options.Harg.Types: Opt :: Maybe String -> Maybe Char -> Maybe String -> Maybe String -> Maybe String -> Maybe a -> Maybe String -> OptReader a -> OptType a -> Opt a
- Options.Harg.Types: OptionOpt :: Maybe String -> Maybe Char -> Maybe String -> Maybe String -> Maybe String -> Maybe a -> OptReader a -> OptionOpt a
+ Options.Harg.Types: OptionOpt :: Maybe String -> Maybe Char -> Maybe String -> Maybe String -> Maybe String -> Maybe a -> Maybe String -> OptReader a -> OptionOpt a

Files

CHANGELOG.md view
@@ -1,3 +1,22 @@ # Changelog for harg -## Unreleased changes+## 0.1.3.0 [2019.08.28]++- Add `manyParser` to parse list of options separated by delimiter++## 0.1.2.0 [2019.08.19]++- Add `optRequired` to mark option as required++## 0.1.1.0 [2019.08.16]++- Add `optDefaultStr` to provide defaults as unparsed strings+- Bump dependencies (`barbies` and `higgledy`)++## 0.1.0.1 [2019.07.19]++- Minor documentation changes++## 0.1.0.0 [2019.07.18]++- Initial release
README.lhs view
@@ -1,9 +1,10 @@-# `harg` :nut_and_bolt:+# harg -[![Build Status](https://travis-ci.org/alexpeits/harg.svg?branch=master)](https://travis-ci.org/alexpeits/harg) [![Hackage](https://img.shields.io/hackage/v/harg.svg)](https://hackage.haskell.org/package/harg)+[![Build Status](https://travis-ci.org/alexpeits/harg.svg?branch=master)](https://travis-ci.org/alexpeits/harg)+[![Hackage](https://img.shields.io/hackage/v/harg.svg)](https://hackage.haskell.org/package/harg)  `harg` is a library for configuring programs by scanning command line arguments, environment-variables and default values. Under the hood, it uses a subset of+variables, default values and more. Under the hood, it uses a subset of [`optparse-applicative`](https://hackage.haskell.org/package/optparse-applicative) to expose regular arguments, switch arguments and subcommands. The library relies heavily on the use of higher kinded data (HKD) thanks to the [`barbies`](https://hackage.haskell.org/package/barbies) library. Using@@ -17,8 +18,6 @@  tl;dr: Take a look at the [example](Example.hs). -(WIP)- Here are some different usage scenarios. Let's first enable some language extensions and add some imports: @@ -151,6 +150,24 @@ -> Maybe a` use `parseWith`, which runs the parser and in case of failure uses a default error message. For example, `readParser` is defined as `parseWith readMaybe`. +Finally, an optional option with type `a` can be specified by setting its type to `Maybe a`. The+declaration is exactly the same as it would be for `a`, and adding `optOptional` to the modifiers+turns turns the parser from `String -> Either String a` to `String -> Either String (Maybe a)` but+without using the `Read` instance for `Maybe`:++``` haskell ignore+someOpt :: Opt (Maybe Int)+someOpt+  = toOpt ( option readParser+          & optLong "something"+          & optOptional+          )+```++Note that `optOptional` can't be used with `optDefault`. Using them together raises a type error at+compile time, to ensure there's no ambiguous behaviour (e.g. the order of declaration of modifiers+should not influence the resulting option).+ There are 3 ways to configure this datatype.  ### 1. Using a `barbie` type@@ -706,6 +723,34 @@               & optHelp "JSON config filepath"               ) ```++Here, the type of the option for the JSON source is `ConfigFile`. This type is a wrapper around+`FilePath`, which looks like this:++``` haskell ignore+data ConfigFile+  = ConfigFile FilePath+  | NoConfigFile+```++This has the advantage that, if the user wants to specify an optional configuration file, they can+simply say:++``` haskell+jsonOpt :: Opt ConfigFile+jsonOpt+  = toOpt ( option strParser+          & optLong "json"+          & optDefault NoConfigFile+          )+```++Also, because `ConfigFile` has an `IsString` instance, there's no need to say+`optLong (ConfigFile "json")` (if `OverloadedStrings` is enabled).++There's a bit of a disconnect between `ConfigFile` and the ability to make optional options using+`Maybe` and `optOptional`. The reason for it is that the type that `JSONSource` wraps is not+polymorphic, since it needs to be a filepath specifically.  # Roadmap 
README.md view
@@ -1,9 +1,10 @@-# `harg` :nut_and_bolt:+# harg -[![Build Status](https://travis-ci.org/alexpeits/harg.svg?branch=master)](https://travis-ci.org/alexpeits/harg) [![Hackage](https://img.shields.io/hackage/v/harg.svg)](https://hackage.haskell.org/package/harg)+[![Build Status](https://travis-ci.org/alexpeits/harg.svg?branch=master)](https://travis-ci.org/alexpeits/harg)+[![Hackage](https://img.shields.io/hackage/v/harg.svg)](https://hackage.haskell.org/package/harg)  `harg` is a library for configuring programs by scanning command line arguments, environment-variables and default values. Under the hood, it uses a subset of+variables, default values and more. Under the hood, it uses a subset of [`optparse-applicative`](https://hackage.haskell.org/package/optparse-applicative) to expose regular arguments, switch arguments and subcommands. The library relies heavily on the use of higher kinded data (HKD) thanks to the [`barbies`](https://hackage.haskell.org/package/barbies) library. Using@@ -17,8 +18,6 @@  tl;dr: Take a look at the [example](Example.hs). -(WIP)- Here are some different usage scenarios. Let's first enable some language extensions and add some imports: @@ -151,6 +150,24 @@ -> Maybe a` use `parseWith`, which runs the parser and in case of failure uses a default error message. For example, `readParser` is defined as `parseWith readMaybe`. +Finally, an optional option with type `a` can be specified by setting its type to `Maybe a`. The+declaration is exactly the same as it would be for `a`, and adding `optOptional` to the modifiers+turns turns the parser from `String -> Either String a` to `String -> Either String (Maybe a)` but+without using the `Read` instance for `Maybe`:++``` haskell ignore+someOpt :: Opt (Maybe Int)+someOpt+  = toOpt ( option readParser+          & optLong "something"+          & optOptional+          )+```++Note that `optOptional` can't be used with `optDefault`. Using them together raises a type error at+compile time, to ensure there's no ambiguous behaviour (e.g. the order of declaration of modifiers+should not influence the resulting option).+ There are 3 ways to configure this datatype.  ### 1. Using a `barbie` type@@ -706,6 +723,34 @@               & optHelp "JSON config filepath"               ) ```++Here, the type of the option for the JSON source is `ConfigFile`. This type is a wrapper around+`FilePath`, which looks like this:++``` haskell ignore+data ConfigFile+  = ConfigFile FilePath+  | NoConfigFile+```++This has the advantage that, if the user wants to specify an optional configuration file, they can+simply say:++``` haskell+jsonOpt :: Opt ConfigFile+jsonOpt+  = toOpt ( option strParser+          & optLong "json"+          & optDefault NoConfigFile+          )+```++Also, because `ConfigFile` has an `IsString` instance, there's no need to say+`optLong (ConfigFile "json")` (if `OverloadedStrings` is enabled).++There's a bit of a disconnect between `ConfigFile` and the ability to make optional options using+`Maybe` and `optOptional`. The reason for it is that the type that `JSONSource` wraps is not+polymorphic, since it needs to be a filepath specifically.  # Roadmap 
harg.cabal view
@@ -1,8 +1,8 @@ cabal-version: 2.2  name:           harg-version:        0.1.0.1-synopsis:       Haskell program configuration from multiple sources+version:        0.1.3.0+synopsis:       Haskell program configuration using higher kinded data description:    Please see the README on GitHub at <https://github.com/alexpeits/harg#readme> homepage:       https://github.com/alexpeits/harg bug-reports:    https://github.com/alexpeits/harg/issues@@ -13,7 +13,7 @@ license:        BSD-3-Clause license-file:   LICENSE build-type:     Simple-category:       System, CLI, Options, Parsing+category:       System, CLI, Options, Parsing, HKD extra-source-files:     README.md     CHANGELOG.md@@ -38,6 +38,7 @@                       Options.Harg.Pretty                       Options.Harg.Single                       Options.Harg.Sources+                      Options.Harg.Sources.DefaultStr                       Options.Harg.Sources.Env                       Options.Harg.Sources.JSON                       Options.Harg.Sources.NoSource@@ -62,11 +63,12 @@                       -Wno-unticked-promoted-constructors   build-depends:      base >=4.7 && <5                     , aeson >= 1.4.2 && < 1.5-                    , barbies >= 1.0.0 && < 1.2+                    , barbies >= 1.1.0 && < 1.2                     , bytestring >= 0.10.8 && < 0.11                     , directory >= 1.3.3 && < 1.4-                    , higgledy >= 0.2.0 && < 0.3+                    , higgledy >= 0.3.0 && < 0.4                     , optparse-applicative >= 0.14.3 && < 0.15+                    , split >= 0.2.3 && < 0.3                     , text >= 1.2.3 && < 1.3                     , yaml >= 0.11.0 && < 0.12   default-language:   Haskell2010
src/Options/Harg.hs view
@@ -37,6 +37,8 @@   , optMetavar   , optEnvVar   , optDefault+  , optDefaultStr+  , optRequired   , optOptional   , toOpt   , Opt@@ -46,6 +48,7 @@   , readParser   , strParser   , boolParser+  , manyParser    -- ** Executing options   , execOpt
src/Options/Harg/Construct.hs view
@@ -7,9 +7,11 @@ import Data.Char          (toLower) import Data.Kind          (Constraint) import Data.String        (IsString(..))-import GHC.TypeLits       (ErrorMessage(..), TypeError, Symbol)+import GHC.TypeLits       (ErrorMessage(..), TypeError, Symbol, AppendSymbol) import Text.Read          (readMaybe) +import Data.List.Split    (splitOn)+ import Options.Harg.Types  @@ -72,9 +74,11 @@  class HasDefault o (attr :: [OptAttr]) where   -- | Add a default value to an option. Cannot be used in conjuction with-  -- 'optOptional'.+  -- with 'optRequired', 'optDefaultStr' or 'optOptional'.   optDefault-    :: NotInAttrs OptOptional attr "optDefault" "optOptional"+    :: ( NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optDefault" '["optDefaultStr", "optRequired"])+       , NotInAttrs OptOptional attr (IncompatibleAttrsErr "optDefault" "optOptional")+       )     => a -> o attr a -> o (OptDefault ': attr) a  instance HasDefault OptionOpt a where@@ -83,10 +87,40 @@ instance HasDefault ArgumentOpt a where   optDefault a o = o { _aDefault = Just a } --- optional--- | Class for options that can be optional. Cannot be used in--- conjunction with 'HasDefault'. Note that this will turn a parser for @a@--- into a parser for @Maybe a@, modifying the reader function appropriately.+class HasDefaultStr o (attr :: [OptAttr]) where+  -- | Add a default unparsed value to an option. Cannot be used in conjuction+  -- with 'optDefault', 'optRequired' or 'optOptional'.+  optDefaultStr+    :: ( NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optDefaultStr" '["optDefault", "optRequired"])+       , NotInAttrs OptOptional attr (IncompatibleAttrsErr "optDefaultStr" "optOptional")+       )+    => String -> o attr a -> o (OptDefault ': attr) a++instance HasDefaultStr OptionOpt a where+  optDefaultStr s o = o { _oDefaultStr = Just s }++instance HasDefaultStr ArgumentOpt a where+  optDefaultStr s o = o { _aDefaultStr = Just s }++class HasRequired o (attr :: [OptAttr]) where+  -- | Mark an option as required. Cannot be used in conjunction with+  -- 'optOptional', 'optDefault' or 'optRequiredStr'.+  optRequired+    :: ( NotInAttrs OptDefault attr (DuplicateAttrMultipleErr "optRequired" '["optDefault", "optDefaultStr"])+       , NotInAttrs OptOptional attr (IncompatibleAttrsErr "optRequired" "optOptional")+       )+    => o attr a -> o (OptDefault ': attr) a++instance HasRequired OptionOpt a where+  optRequired o = o { _oDefault = Nothing }++instance HasRequired ArgumentOpt a where+  optRequired o = o { _aDefault = Nothing }++-- | Class for options that can be optional. Cannot be used in conjunction with+-- 'HasDefault', 'HasDefaultStr' or 'HasRequired'. Note that this will turn a+-- parser for @a@ into a parser for @Maybe a@, modifying the reader function+-- appropriately. -- For example: -- -- @@@ -99,31 +133,36 @@ -- @ class HasOptional o (attr :: [OptAttr]) where   -- | Specify that an option is optional. This will convert an @Opt a@ to an-  -- @Opt (Maybe a)@+  -- @Opt (Maybe a)@. Cannot be used in conjunction with 'optDefault', 'optDefaultStr'+  -- or 'optRequired'.   optOptional-    :: NotInAttrs OptDefault attr "optOptional" "optDefault"+    :: ( NotInAttrs OptOptional attr (DuplicateAttrErr "optOptional")+       , NotInAttrs OptDefault attr (IncompatibleAttrsErr "optOptional" "optDefault")+       )     => o attr a -> o (OptOptional ': attr) (Maybe a)  instance HasOptional OptionOpt a where   optOptional OptionOpt{..}     = OptionOpt-        { _oLong    = _oLong-        , _oShort   = _oShort-        , _oHelp    = _oHelp-        , _oMetavar = _oMetavar-        , _oEnvVar  = _oEnvVar-        , _oDefault = Just Nothing-        , _oReader  = fmap Just . _oReader+        { _oLong       = _oLong+        , _oShort      = _oShort+        , _oHelp       = _oHelp+        , _oMetavar    = _oMetavar+        , _oEnvVar     = _oEnvVar+        , _oDefault    = Just Nothing+        , _oDefaultStr = Nothing+        , _oReader     = fmap Just . _oReader         }  instance HasOptional ArgumentOpt a where   optOptional ArgumentOpt{..}     = ArgumentOpt-        { _aHelp    = _aHelp-        , _aMetavar = _aMetavar-        , _aEnvVar  = _aEnvVar-        , _aDefault = Just Nothing-        , _aReader  = fmap Just . _aReader+        { _aHelp       = _aHelp+        , _aMetavar    = _aMetavar+        , _aEnvVar     = _aEnvVar+        , _aDefault    = Just Nothing+        , _aDefaultStr = Nothing+        , _aReader     = fmap Just . _aReader         }  -- | Class to convert an intermediate option type into 'Opt'. Instances@@ -135,40 +174,43 @@ instance IsOpt OptionOpt attr where   toOpt OptionOpt{..}     = Opt-        { _optLong    = _oLong-        , _optShort   = _oShort-        , _optHelp    = _oHelp-        , _optMetavar = _oMetavar-        , _optEnvVar  = _oEnvVar-        , _optDefault = _oDefault-        , _optReader  = _oReader-        , _optType    = OptionOptType+        { _optLong       = _oLong+        , _optShort      = _oShort+        , _optHelp       = _oHelp+        , _optMetavar    = _oMetavar+        , _optEnvVar     = _oEnvVar+        , _optDefault    = _oDefault+        , _optDefaultStr = _oDefaultStr+        , _optReader     = _oReader+        , _optType       = OptionOptType         }  instance IsOpt FlagOpt attr where   toOpt FlagOpt{..}     = Opt-        { _optLong    = _fLong-        , _optShort   = _fShort-        , _optHelp    = _fHelp-        , _optMetavar = Nothing-        , _optEnvVar  = _fEnvVar-        , _optDefault = Just _fDefault-        , _optReader  = _fReader-        , _optType    = FlagOptType _fActive+        { _optLong       = _fLong+        , _optShort      = _fShort+        , _optHelp       = _fHelp+        , _optMetavar    = Nothing+        , _optEnvVar     = _fEnvVar+        , _optDefault    = Just _fDefault+        , _optDefaultStr = Nothing+        , _optReader     = _fReader+        , _optType       = FlagOptType _fActive         }  instance IsOpt ArgumentOpt attr where   toOpt ArgumentOpt{..}     = Opt-        { _optLong    = Nothing-        , _optShort   = Nothing-        , _optHelp    = _aHelp-        , _optMetavar = _aMetavar-        , _optEnvVar  = _aEnvVar-        , _optDefault = _aDefault-        , _optReader  = _aReader-        , _optType    = ArgumentOptType+        { _optLong       = Nothing+        , _optShort      = Nothing+        , _optHelp       = _aHelp+        , _optMetavar    = _aMetavar+        , _optEnvVar     = _aEnvVar+        , _optDefault    = _aDefault+        , _optDefaultStr = _aDefaultStr+        , _optReader     = _aReader+        , _optType       = ArgumentOptType         }  -- | Create an option parser, equivalent to 'Options.Applicative.option'. The@@ -188,13 +230,14 @@   -> OptionOpt '[] a option p   = OptionOpt-      { _oLong    = Nothing-      , _oShort   = Nothing-      , _oHelp    = Nothing-      , _oMetavar = Nothing-      , _oEnvVar  = Nothing-      , _oDefault = Nothing-      , _oReader  = p+      { _oLong       = Nothing+      , _oShort      = Nothing+      , _oHelp       = Nothing+      , _oMetavar    = Nothing+      , _oEnvVar     = Nothing+      , _oDefault    = Nothing+      , _oDefaultStr = Nothing+      , _oReader     = p       }  -- | Similar to 'option', but accepts a modifier function and returns an 'Opt'@@ -333,11 +376,12 @@   -> ArgumentOpt '[] a argument p   = ArgumentOpt-      { _aHelp    = Nothing-      , _aMetavar = Nothing-      , _aEnvVar  = Nothing-      , _aDefault = Nothing-      , _aReader  = p+      { _aHelp       = Nothing+      , _aMetavar    = Nothing+      , _aEnvVar     = Nothing+      , _aDefault    = Nothing+      , _aDefaultStr = Nothing+      , _aReader     = p       }  -- | Similar to 'argument', but accepts a modifier function and returns an@@ -393,6 +437,13 @@       "false" -> Right False       _       -> Left ("Unable to parse " <> s <> " to Bool") +-- | A parser that can parse many items, returning a list.+manyParser+  :: String  -- ^ Separator+  -> OptReader a  -- ^ Parser for each string+  -> OptReader [a]+manyParser sep parser+  = traverse parser . splitOn sep  -- | Wrap a symbol in quotes, for pretty printing in type errors. type QuoteSym (s :: Symbol)@@ -403,15 +454,35 @@ type family NotInAttrs     (x :: k)     (xs :: [k])-    (l :: Symbol)-    (r :: Symbol)+    (err :: ErrorMessage)     :: Constraint where-  NotInAttrs _ '[]  _ _+  NotInAttrs _ '[]  _     = ()-  NotInAttrs x (x ': _) l r-    = TypeError-    (    QuoteSym l :<>: 'Text " and " :<>: QuoteSym r-    :<>: 'Text " cannot be mixed in an option definition."-    )-  NotInAttrs x (y ': xs) l r-    = NotInAttrs x xs l r+  NotInAttrs x (x ': _) err+    = TypeError err+  NotInAttrs x (y ': xs) err+    = NotInAttrs x xs err++type family CommaSep (xs :: [Symbol]) :: Symbol where+  CommaSep '[] = ""+  CommaSep '[x] = " or " `AppendSymbol` x+  CommaSep (x ': xs) = " or one of " `AppendSymbol` CommaSep' x xs++type family CommaSep' (s :: Symbol) (xs :: [Symbol]) :: Symbol where+  CommaSep' s '[]       = s+  CommaSep' s (x ': xs) = CommaSep' (s `AppendSymbol` ", " `AppendSymbol` x) xs++type DuplicateAttrErr attr+  =    QuoteSym attr+  :<>: 'Text " is already specified."++type DuplicateAttrMultipleErr attr rest+  =    QuoteSym attr+  :<>: 'Text (CommaSep rest)+  :<>: 'Text " has already been specified."++type IncompatibleAttrsErr l r+  =    QuoteSym l+  :<>: 'Text " and "+  :<>: QuoteSym r+  :<>: 'Text " cannot be mixed in an option definition."
src/Options/Harg/Operations.hs view
@@ -6,23 +6,26 @@ {-# LANGUAGE UndecidableInstances #-} module Options.Harg.Operations where -import           Data.Functor.Identity      (Identity(..))+import           Data.Functor.Identity           (Identity(..)) -import qualified Data.Barbie                as B-import qualified Options.Applicative        as Optparse+import qualified Data.Barbie                     as B+import qualified Options.Applicative             as Optparse -import           Options.Harg.Cmdline       (mkOptparseParser)-import           Options.Harg.Config        (mkConfigParser, getConfig)-import           Options.Harg.Het.All       (All)-import           Options.Harg.Het.HList     (AssocListF, MapAssocList(..))-import           Options.Harg.Het.Variant   (VariantF)-import           Options.Harg.Pretty        (ppWarning, ppError)-import           Options.Harg.Sources       (accumSourceResults, defaultSources)-import           Options.Harg.Sources.Env   (EnvSourceVal)-import           Options.Harg.Sources.Types (GetSource(..), RunSource(..))-import           Options.Harg.Subcommands   (Subcommands(..))-import           Options.Harg.Types         (HargCtx(..), getCtx, Opt, OptError)-import           Options.Harg.Util          (toDummyOpts, allToDummyOpts, compose)+import           Options.Harg.Cmdline            (mkOptparseParser)+import           Options.Harg.Config             (mkConfigParser, getConfig)+import           Options.Harg.Het.All            (All)+import           Options.Harg.Het.HList          (AssocListF, MapAssocList(..))+import           Options.Harg.Het.Prod           ((:*)(..))+import           Options.Harg.Het.Variant        (VariantF)+import           Options.Harg.Pretty             (ppWarning, ppError)+import           Options.Harg.Sources            ( accumSourceResults+                                                 , DefaultSources, defaultSources+                                                 , HiddenSources, hiddenSources+                                                 )+import           Options.Harg.Sources.Types      (GetSource(..), RunSource(..))+import           Options.Harg.Subcommands        (Subcommands(..))+import           Options.Harg.Types              (HargCtx(..), getCtx, Opt, OptError)+import           Options.Harg.Util               (toDummyOpts, allToDummyOpts, compose)   -- | Run the option parser and combine with values from the specified sources,@@ -43,7 +46,7 @@ execOptWithCtx ctx conf opts   = do       let-        configParser = mkConfigParser ctx (compose Identity conf)+        configParser = mkConfigParser ctx $ compose Identity (conf :* hiddenSources)         dummyParser = mkOptparseParser [] (toDummyOpts @String opts)       config <- getConfig ctx configParser dummyParser       sourceVals <- getSource ctx config@@ -107,7 +110,7 @@      , B.ProductB c      , Subcommands ts xs      , GetSource c Identity-     , All (RunSource (SourceVal c)) xs+     , All (RunSource (SourceVal (c :* HiddenSources))) xs      , All (RunSource ()) xs      , MapAssocList xs      )@@ -118,7 +121,7 @@ execCommandsWithCtx ctx conf opts   = do       let-        configParser = mkConfigParser ctx (compose Identity conf)+        configParser = mkConfigParser ctx $ compose Identity (conf :* hiddenSources)         (_, dummyCommands)           = mapSubcommand () (allToDummyOpts @String opts)         dummyParser@@ -144,7 +147,7 @@      , B.ProductB c      , Subcommands ts xs      , GetSource c Identity-     , All (RunSource (SourceVal c)) xs+     , All (RunSource (SourceVal (c :* HiddenSources))) xs      , All (RunSource ()) xs      , MapAssocList xs      )@@ -162,7 +165,7 @@   :: forall ts xs.      ( B.TraversableB (VariantF xs)      , Subcommands ts xs-     , All (RunSource EnvSourceVal) xs+     , All (RunSource (SourceVal (DefaultSources :* HiddenSources))) xs      , All (RunSource ()) xs      , MapAssocList xs      )@@ -178,7 +181,7 @@   :: forall ts xs.      ( B.TraversableB (VariantF xs)      , Subcommands ts xs-     , All (RunSource EnvSourceVal) xs+     , All (RunSource (SourceVal (DefaultSources :* HiddenSources))) xs      , All (RunSource ()) xs      , MapAssocList xs      )
src/Options/Harg/Sources.hs view
@@ -9,6 +9,7 @@  import qualified Data.Barbie                as B +import           Options.Harg.Sources.DefaultStr import           Options.Harg.Sources.Env import           Options.Harg.Sources.Types import           Options.Harg.Types@@ -40,7 +41,16 @@           OptParsed a       -> ([], Compose (Just a))           _                 -> ([], Compose Nothing) +type HiddenSources = DefaultStrSource++-- | Sources hidden from user that are always enabled+hiddenSources :: HiddenSources f+hiddenSources+  = DefaultStrSource++type DefaultSources = EnvSource+ -- | Default sources, equivalent to 'EnvSource'-defaultSources :: EnvSource f+defaultSources :: DefaultSources f defaultSources   = EnvSource
+ src/Options/Harg/Sources/DefaultStr.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric  #-}+{-# LANGUAGE TypeFamilies   #-}+module Options.Harg.Sources.DefaultStr where++import           Data.Functor.Compose       (Compose (..))+import           Data.Kind                  (Type)+import           GHC.Generics               (Generic)++import qualified Data.Barbie                as B++import           Options.Harg.Sources.Types+import           Options.Harg.Types+++-- | Source that enables a parser to read options from defaults that are provided+-- as strings (unparsed).+data DefaultStrSource (f :: Type -> Type) = DefaultStrSource+  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)++-- | Value of 'DefaultStrSource' is a dummy value, as the default string option can+-- be found inside the 'Opt' ('_optDefaultStr').+data DefaultStrSourceVal = DefaultStrSourceVal++instance GetSource DefaultStrSource f where+  type SourceVal DefaultStrSource = DefaultStrSourceVal+  getSource HargCtx{..} _+    = pure DefaultStrSourceVal++instance+    B.FunctorB a => RunSource DefaultStrSourceVal a where+  runSource DefaultStrSourceVal opt+    = [runDefaultStrSource opt]++runDefaultStrSource+  :: forall a f.+     ( B.FunctorB a+     , Applicative f+     )+  => a (Compose Opt f)+  -> a (Compose SourceRunResult f)+runDefaultStrSource+  = B.bmap go+  where+    go :: Compose Opt f x -> Compose SourceRunResult f x+    go (Compose opt@Opt{..})+      = case _optDefaultStr of+          Nothing+            -> Compose $ pure <$> OptNotFound+          Just str+            -> Compose $ tryParse str+      where+        tryParse+          = either+              (OptFoundNoParse . toOptError opt (Just "DefaultStrSource"))+              OptParsed+          . _optReader
src/Options/Harg/Types.hs view
@@ -8,15 +8,16 @@ -- | The basic option type data Opt a   = Opt-      { _optLong    :: Maybe String -- ^ Modifier for long options (e.g. @--user@)-      , _optShort   :: Maybe Char   -- ^ Modifier for short options (e.g. @-u@)-      , _optHelp    :: Maybe String -- ^ Option help to be shown when invoked-                                    --   with @--help/-h@ or in case of error-      , _optMetavar :: Maybe String -- ^ Metavar to be shown in the help description-      , _optEnvVar  :: Maybe String -- ^ Environment variable for use with 'EnvSource'-      , _optDefault :: Maybe a      -- ^ Default value-      , _optReader  :: OptReader a  -- ^ Option parser-      , _optType    :: OptType a    -- ^ Option type+      { _optLong       :: Maybe String -- ^ Modifier for long options (e.g. @--user@)+      , _optShort      :: Maybe Char   -- ^ Modifier for short options (e.g. @-u@)+      , _optHelp       :: Maybe String -- ^ Option help to be shown when invoked+                                       --   with @--help/-h@ or in case of error+      , _optMetavar    :: Maybe String -- ^ Metavar to be shown in the help description+      , _optEnvVar     :: Maybe String -- ^ Environment variable for use with 'EnvSource'+      , _optDefault    :: Maybe a      -- ^ Default value+      , _optDefaultStr :: Maybe String -- ^ Default value as string (unparsed)+      , _optReader     :: OptReader a  -- ^ Option parser+      , _optType       :: OptType a    -- ^ Option type       }   deriving Functor @@ -36,13 +37,14 @@ -- | Option for flags with arguments. Corresponds to 'Options.Applicative.option'. data OptionOpt (attr :: [OptAttr]) a   = OptionOpt-      { _oLong    :: Maybe String-      , _oShort   :: Maybe Char-      , _oHelp    :: Maybe String-      , _oMetavar :: Maybe String-      , _oEnvVar  :: Maybe String-      , _oDefault :: Maybe a-      , _oReader  :: OptReader a+      { _oLong       :: Maybe String+      , _oShort      :: Maybe Char+      , _oHelp       :: Maybe String+      , _oMetavar    :: Maybe String+      , _oEnvVar     :: Maybe String+      , _oDefault    :: Maybe a+      , _oDefaultStr :: Maybe String+      , _oReader     :: OptReader a       }  -- | Option for flags that act like switches between a default and an active@@ -62,11 +64,12 @@ -- 'Options.Applicative.argument'. data ArgumentOpt (attr :: [OptAttr]) a   = ArgumentOpt-      { _aHelp    :: Maybe String-      , _aMetavar :: Maybe String-      , _aEnvVar  :: Maybe String-      , _aDefault :: Maybe a-      , _aReader  :: OptReader a+      { _aHelp       :: Maybe String+      , _aMetavar    :: Maybe String+      , _aEnvVar     :: Maybe String+      , _aDefault    :: Maybe a+      , _aDefaultStr :: Maybe String+      , _aReader     :: OptReader a       }  -- | Datatype that holds errors that arise when running the sources.