packages feed

yaml-config 0.3.0 → 0.4.0

raw patch · 3 files changed

+77/−73 lines, 3 filesdep −failurePVP ok

version bump matches the API change (PVP)

Dependencies removed: failure

API changes (from Hackage documentation)

- Data.Yaml.Config: lookup :: (Failure KeyError m, FromJSON a) => Key -> Config -> m a
+ Data.Yaml.Config: lookup :: (Monad m, FromJSON a) => Key -> Config -> m a
- Data.Yaml.Config: subconfig :: Failure KeyError m => Key -> Config -> m Config
+ Data.Yaml.Config: subconfig :: Monad m => Key -> Config -> m Config
- Data.Yaml.Config.Internal: lookup :: (Failure KeyError m, FromJSON a) => Key -> Config -> m a
+ Data.Yaml.Config.Internal: lookup :: (Monad m, FromJSON a) => Key -> Config -> m a
- Data.Yaml.Config.Internal: subconfig :: Failure KeyError m => Key -> Config -> m Config
+ Data.Yaml.Config.Internal: subconfig :: Monad m => Key -> Config -> m Config

Files

src/Data/Yaml/Config/Internal.hs view
@@ -1,17 +1,18 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-}  module Data.Yaml.Config.Internal-    ( Config(..)+    (+    -- * Types+      Config(..)     , KeyError(..)     , Key -    -- * Work with files+    -- * Loading     , load -    -- * Explore config+    -- * Access functions     , keys     , subconfig     , lookup@@ -19,20 +20,19 @@     , fullpath     ) where -import Prelude hiding (lookup)-import Control.DeepSeq (NFData(rnf))-import Control.Exception (Exception)+import Control.DeepSeq (NFData (rnf))+import Control.Exception (Exception, throw) import Control.Monad (foldM) import Data.Maybe (fromMaybe) import Data.Monoid ((<>))-import Data.Typeable (Typeable) import qualified Data.Text as ST+import Data.Typeable (Typeable)+import Prelude hiding (lookup) -import Data.Yaml (Object, FromJSON(parseJSON), parseMaybe) import qualified Data.HashMap.Strict as HashMap+import Data.Yaml (FromJSON (parseJSON), Object, parseMaybe) import qualified Data.Yaml as Yaml import qualified Data.Yaml.Include as YamlInclude-import Control.Failure  -- | Config or field name type Key = ST.Text@@ -50,20 +50,21 @@ instance NFData Config where     rnf (Config p o) = rnf p `seq` rnf o `seq` () -ke :: Failure KeyError m => Key -> m a-ke = failure . KeyError+ke :: Monad m => Key -> m a+ke = throw . KeyError --- | Show full path from the root to target key. Levels are separated by dots.+-- | Returns full path from the root to the given key.+-- Levels are separated by dots. -- -- >>> fullpath sub "field1" -- "section1.field1" -- fullpath :: Config -> Key -> Key-fullpath (Config parents _) path = ST.intercalate "." $-    reverse $ path : parents+fullpath (Config parents _) path =+    ST.intercalate "." $ reverse (path : parents) --- | Find file in filesystem and try to load it as YAML config.--- May fail with @InvalidYaml@ if file not found.+-- | Attempts to load a config from a given YAML file.+-- Fails with @InvalidYaml@ if the file does not exist. -- -- >>> config <- load "example.yaml" --@@ -72,7 +73,7 @@   where     err = error $ "Invalid config file " <> f <> "." --- | Show all first level config field's.+-- | Returns all toplevel keys in a config. -- -- >>> keys config -- ["section1","section2"]@@ -80,22 +81,29 @@ keys :: Config -> [Key] keys (Config _ o) = HashMap.keys o --- | Get value for given key.--- May fail with @KeyError@ if key doesn't exist.+-- | Returns a value for a given key.+-- Fails with a @KeyError@ if the key doesn't exist. -- -- >>> keys sub -- ["field1","field2"] -- >>> putStrLn =<< lookup "field1" sub -- value1 ---lookup :: (Failure KeyError m, FromJSON a)-       => Key                               -- ^ Field name-       -> Config                            -- ^ Config for find-       -> m a                               -- ^ Field value+lookup :: (Monad m, FromJSON a)+       => Key                   -- ^ Field name+       -> Config                -- ^ Config to query+       -> m a                   -- ^ Looked up value lookup path c = maybe err return $ lookupMaybe path c   where     err = ke $ "Field " <> fullpath c path <> " not found or has wrong type." +-- | An exception-free alternative to @lookup@.+--+-- >>> keys sub+-- ["field1","field2"]+-- >>> lookupMaybe "field1" sub+-- Just "value1"+-- lookupMaybe :: FromJSON a => Key -> Config -> Maybe a lookupMaybe path conf = foldM (flip subconfig) conf (init pathes) >>=     look (last pathes)@@ -103,28 +111,28 @@     look k (Config _ o) = HashMap.lookup k o >>= parseMaybe parseJSON     pathes = ST.splitOn "." path --- | Find value in config and return it or return default value.+-- | Returns a value for a given key or a default value if a key doesn't exist. -- -- >>> lookupDefault "field3" "def" sub -- "def" -- lookupDefault :: FromJSON a-              => Key         -- ^ Field name-              -> a           -- ^ Default value-              -> Config      -- ^ Config for find-              -> a           -- ^ Founded or default value+              => Key            -- ^ Field name+              -> a              -- ^ Default value+              -> Config         -- ^ Config to query+              -> a              -- ^ Looked up or default value lookupDefault p d = fromMaybe d . lookup p --- | Get subconfig by name.--- May fail with @KeyError@ if target key doesn't exist at current level.+-- | Narrows into a config section corresponding to a given key.+-- Fails with a @KeyError@ if a key doesn't exist at the current level. -- -- >>> :set -XOverloadedStrings -- >>> sub <- subconfig "section1" config ---subconfig :: Failure KeyError m+subconfig :: Monad m           => Key                 -- ^ Subconfig name-          -> Config              -- ^ (Sub)Config for find-          -> m Config            -- ^ Founded Subconfig+          -> Config              -- ^ (Sub)Config to narrow into+          -> m Config            -- ^ Subconfig subconfig path c@(Config parents o) = case HashMap.lookup path o of     Just (Yaml.Object so) -> return $ Config (path : parents) so     _                     -> err
tests/Tests.hs view
@@ -3,23 +3,18 @@ module Main where  import Control.Monad (liftM)-import Data.Monoid ((<>))-import Data.Hashable (Hashable)-import Data.Text (Text) import Data.List as List+import Data.Monoid ((<>)) import Data.Text as Text-import qualified Data.Text as ST -import Test.Tasty (defaultMain, testGroup)-import Test.Tasty.QuickCheck (testProperty)-import Test.QuickCheck (Gen, Property, Arbitrary(..), elements, sized, oneof,-                        listOf)-import Test.QuickCheck.Monadic (assert)-import Data.Yaml(Object, Value(Object, Null)) import qualified Data.HashMap.Strict as HashMap+import Data.Yaml (Object, Value (Object))+import Test.QuickCheck (Arbitrary (..), Gen, expectFailure, sized)+import Test.QuickCheck.Monadic (monadicIO, run)+import Test.Tasty (defaultMain, testGroup)+import Test.Tasty.QuickCheck (Property, testProperty) -import Data.Yaml.Config.Internal (Config(Config), Key, subconfig, keys,-                                  fullpath)+import Data.Yaml.Config.Internal (Config (Config), Key, fullpath, keys, subconfig)  type CorrectPath = [Key] @@ -35,46 +30,50 @@ newObject = HashMap.fromList  deepConfig :: Gen DeepObject-deepConfig = sized deepConfig' >>= \(keys, obj) ->-    return $ DeepObject (Config [] obj) $ List.tail keys+deepConfig = sized deepConfig' >>= \(ks, obj) ->+    return $ DeepObject (Config [] obj) $ List.tail ks  deepConfig' :: Int -> Gen ([Key], Object)-deepConfig' 0 = arbitrary >>= \newKey -> return $ ([newKey], newObject [])+deepConfig' 0 = arbitrary >>= \newKey -> return ([newKey], newObject []) deepConfig' n | n > 0 = do     newKey <- arbitrary-    (keys, newNode) <- deepConfig' (pred n)-    return $ (newKey : keys, newObject [(List.head keys , Object newNode)])+    (ks, newNode) <- deepConfig' (pred n)+    return (newKey : ks, newObject [(List.head ks , Object newNode)])  testCorrectSubconfigPath :: DeepObject -> Bool testCorrectSubconfigPath (DeepObject _ []) = True testCorrectSubconfigPath (DeepObject config (key : others)) =     maybe False (`subcheck` others) $ subconfig key config   where-    subcheck sc keys = testCorrectSubconfigPath $ DeepObject sc keys+    subcheck sc = testCorrectSubconfigPath . DeepObject sc -testWrongSubconfigPath :: DeepObject -> Bool-testWrongSubconfigPath (DeepObject config []) = List.null $ keys config+testWrongSubconfigPath' :: DeepObject -> Property+testWrongSubconfigPath' = expectFailure . monadicIO . run . testWrongSubconfigPath++testWrongSubconfigPath :: DeepObject -> IO Bool+testWrongSubconfigPath (DeepObject config []) = return . List.null $ keys config testWrongSubconfigPath (DeepObject config (nextKey : others)) =-    maybe nextCheck (const False) $ subconfig wrongKey config+    maybe nextCheck (const $ return False) $ subconfig wrongKey config   where-    nextCheck = maybe False (testWrongSubconfigPath . nextDeep) $+    nextCheck = maybe (return False) (testWrongSubconfigPath . nextDeep) $         subconfig nextKey config     nextDeep = flip DeepObject others     wrongKey = nextKey <> "_"  testCorrectPath :: DeepObject -> Bool testCorrectPath = testCorrectPath' []-testCorrectPath' path (DeepObject config (nextKey : others)) = checkPath config-    && (maybe False (`subcheck` others) $ subconfig nextKey config)   where-    subcheck sc keys = testCorrectPath' (nextKey : path) $ DeepObject sc keys-    checkPath c = fullpath c nextKey ==-                  (ST.intercalate "." $ List.reverse $ nextKey : path)-testCorrectPath' _ (DeepObject config []) = List.null $ keys config+    testCorrectPath' path (DeepObject config (nextKey : others)) = checkPath config+        && maybe False (`subcheck` others) (subconfig nextKey config)+      where+        subcheck sc = testCorrectPath' (nextKey : path) . DeepObject sc+        checkPath c = fullpath c nextKey ==+            Text.intercalate "." (List.reverse $ nextKey : path)+    testCorrectPath' _ (DeepObject config []) = List.null $ keys config  main :: IO () main = defaultMain $ testGroup "Tests"-    [ testProperty "wrongSubconfigPath" testWrongSubconfigPath+    [ testProperty "wrongSubconfigPath" testWrongSubconfigPath'     , testProperty "correctSubconfigPath" testCorrectSubconfigPath     , testProperty "correctPath" testCorrectPath     ]
yaml-config.cabal view
@@ -1,5 +1,5 @@ Name:               yaml-config-Version:            0.3.0+Version:            0.4.0 Synopsis:           Configuration management Description:        Configuration management License:            MIT@@ -20,10 +20,9 @@   Ghc-options:      -Wall -fno-warn-orphans   Build-depends:    base                       >= 4.5.0 && < 5.0.0                   , deepseq                    >= 1.3-                  , unordered-containers       >= 0.2.0                   , text                       >= 0.11.0+                  , unordered-containers       >= 0.2.0                   , yaml                       >= 0.8.10-                  , failure                    >= 0.2.0    Exposed-modules:  Data.Yaml.Config                     Data.Yaml.Config.Internal@@ -34,17 +33,15 @@   Default-language: Haskell2010   Type:             exitcode-stdio-1.0 -  Build-depends:    base                       >= 4.5.0 && < 5.0.0+  Build-depends:    QuickCheck                 >= 2.6.0+                  , base                       >= 4.5.0 && < 5.0.0                   , deepseq                    >= 1.3-                  , unordered-containers       >= 0.2.0-                  , text                       >= 0.11.0-                  , yaml                       >= 0.8.10-                  , failure                    >= 0.2.0-                   , hashable                   >= 1.2.0                   , tasty                      >= 0.10.0                   , tasty-quickcheck           >= 0.8.0-                  , QuickCheck                 >= 2.6.0+                  , text                       >= 0.11.0+                  , unordered-containers       >= 0.2.0+                  , yaml                       >= 0.8.10  Source-repository head     Type:     git