config-schema 0.4.0.0 → 0.4.1.0
raw patch · 4 files changed
+61/−2 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Config.Schema.Load: SchemaError :: (NonEmpty (LoadError Position)) -> SchemaError
+ Config.Schema.Load: instance GHC.Exception.Exception Config.Schema.Load.SchemaError
+ Config.Schema.Load: instance GHC.Show.Show Config.Schema.Load.SchemaError
+ Config.Schema.Load: loadValueFromFile :: FilePath -> ValueSpecs a -> IO a
+ Config.Schema.Load: newtype SchemaError
Files
- ChangeLog.md +6/−0
- README.md +8/−0
- config-schema.cabal +1/−1
- src/Config/Schema/Load.hs +46/−1
ChangeLog.md view
@@ -1,5 +1,11 @@ # Revision history for config-schema +## 0.4.1.0++* Add `loadValueFromFile` and `SchemaError`. This is intended+ as a quick way to get a configuration file loaded with all+ errors being thrown as exceptions.+ ## 0.4.0.0 * Parameterize the Load module on a position type
README.md view
@@ -3,6 +3,14 @@ [](https://hackage.haskell.org/package/config-schema) [](http://travis-ci.org/glguy/config-schema) +Live Demo+--------++The config-value and config-schema packages are available in a [live demo](https://glguy.net/config-demo/).++About+--------+ This package allows the user to define configuration schemas suitable for matching against configuration files written in the [config-value](https://hackage.haskell.org/package/config-value) format.
config-schema.cabal view
@@ -1,5 +1,5 @@ name: config-schema-version: 0.4.0.0+version: 0.4.1.0 synopsis: Schema definitions for the config-value package description: This package makes it possible to defined schemas for use when loading configuration files using the config-value format.
src/Config/Schema/Load.hs view
@@ -12,12 +12,15 @@ -} module Config.Schema.Load ( loadValue+ , loadValueFromFile -- * Errors+ , SchemaError(..) , LoadError(..) , Problem(..) ) where +import Control.Exception (Exception(..), throwIO) import Control.Monad (zipWithM) import Control.Monad.Trans.Class (lift) import Control.Monad.Trans.State (StateT(..), runStateT)@@ -31,6 +34,7 @@ import qualified Data.List.NonEmpty as NonEmpty import Data.Text (Text) import qualified Data.Text as Text+import qualified Data.Text.IO as Text import Config import Config.Schema.Spec@@ -46,6 +50,47 @@ loadValue spec val = runLoad (getValue spec val) +-- | Read a configuration file, parse it, and validate it according+-- to the given specification.+--+-- Throws 'IOError', 'ParseError', or 'SchemaError'+loadValueFromFile ::+ FilePath {- ^ filename -} ->+ ValueSpecs a {- ^ specification -} ->+ IO a+loadValueFromFile path spec =+ do txt <- Text.readFile path+ val <- either throwIO return (parse txt)+ either (throwIO . SchemaError) return (loadValue spec val)+++-- | Newtype wrapper for schema load errors.+newtype SchemaError = SchemaError (NonEmpty (LoadError Position))+ deriving Show++-- | Custom 'displayException' implementation+instance Exception SchemaError where+ displayException (SchemaError e) = foldr showLoadError "" e+ where+ showLoadError (LoadError pos path problem)+ = shows (posLine pos)+ . showChar ':'+ . shows (posColumn pos)+ . showString ": "+ . foldr (\x xs -> showString (Text.unpack x) . showChar ':' . xs) id path+ . showChar ' '+ . showProblem problem+ . showChar '\n'++ showProblem p =+ case p of+ MissingSection x -> showString "missing required section `"+ . showString (Text.unpack x) . showChar '`'+ UnusedSection x -> showString "unused section `"+ . showString (Text.unpack x) . showChar '`'+ SpecMismatch x -> showString "expected " . showString (Text.unpack x)++ getSection :: p -> SectionSpec a -> StateT [Section p] (Load p) a getSection pos (ReqSection k _ w) = do v <- StateT (lookupSection pos k)@@ -102,7 +147,7 @@ -- against the given specification and associates them with the -- section name. getAssoc :: ValueSpecs a -> [Section p] -> Load p [(Text,a)]-getAssoc w = traverse $ \(Section _ k v) -> (,) k <$> getValue w v+getAssoc w = traverse $ \(Section _ k v) -> (,) k <$> scope k (getValue w v) -- | Match a value against its specification. If 'Just' is matched