packages feed

salak 0.1.6 → 0.1.7

raw patch · 10 files changed

+230/−173 lines, 10 filesdep +mtldep +transformers

Dependencies added: mtl, transformers

Files

README.md view
@@ -1,6 +1,6 @@ # salak -[![Hackage](https://img.shields.io/badge/hackage-v0.1.6-orange.svg)](https://hackage.haskell.org/package/salak)+[![Hackage](https://img.shields.io/badge/hackage-v0.2.1-orange.svg)](https://hackage.haskell.org/package/salak) [![Build Status](https://travis-ci.org/leptonyu/salak.svg?branch=master)](https://travis-ci.org/leptonyu/salak)  
salak.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: salak-version: 0.1.6+version: 0.1.7 license: BSD3 license-file: LICENSE copyright: (c) 2018 Daniel YU@@ -36,8 +36,10 @@         base >=4.11 && <5,         directory >=1.3.3.0 && <1.4,         filepath >=1.4.2.1 && <1.5,+        mtl >=2.2.2 && <2.3,         scientific >=0.3.6.2 && <0.4,         text >=1.2.3.1 && <1.3,+        transformers >=0.5.5.0 && <0.6,         unordered-containers >=0.2.9.0 && <0.3,         vector >=0.12.0.2 && <0.13,         yaml >=0.11.0.0 && <0.12@@ -68,8 +70,10 @@         directory >=1.3.3.0 && <1.4,         filepath >=1.4.2.1 && <1.5,         hspec ==2.*,+        mtl >=2.2.2 && <2.3,         scientific >=0.3.6.2 && <0.4,         text >=1.2.3.1 && <1.3,+        transformers >=0.5.5.0 && <0.6,         unordered-containers >=0.2.9.0 && <0.3,         vector >=0.12.0.2 && <0.13,         yaml >=0.11.0.0 && <0.12
src/Data/Salak.hs view
@@ -15,34 +15,40 @@   -- $use    -- * Properties Loader-    defaultProperties-  , ParseCommandLine+    LoadProperties+  , runLoad+  , askProperties+  , setValue+  , loadCommandLine+  , loadEnvironment+  , loadJSON+  , loadYaml+  , loadYamlIfExists+  -- ** Predefined Loaders+  , defaultProperties   , defaultProperties'   , defaultPropertiesWithFile   , defaultPropertiesWithFile'   , empty   -- * Lookup Properties   , lookup-  , lookup'   , toKeys   -- * Types   , Property(..)   , Properties(..)   , Key   , FromProperties(..)-  , Return(..)+  , Return   -- * Properties Loader Helper   , insert-  , makePropertiesFromEnvironment   , defaultParseCommandLine-  , makePropertiesFromCommandLine-  , makePropertiesFromJson-  , makePropertiesFromYaml+  , ParseCommandLine   , FileName   -- * Operations   , module Data.Salak.Operation   ) where +import           Control.Monad.Trans.Class (lift) import           Data.Maybe import           Data.Salak.Aeson import           Data.Salak.CommandLine@@ -50,10 +56,10 @@ import           Data.Salak.Operation import           Data.Salak.Types import           Data.Salak.Yaml-import           Data.Text              (Text, unpack)-import           Prelude                hiding (lookup)+import           Data.Text                 (pack)+import           Prelude                   hiding (lookup) import           System.Directory-import           System.FilePath        ((</>))+import           System.FilePath           ((</>))  -- | Initialize default properties from `CommandLine` and `Environment`. -- `CommandLine` use default parser.@@ -62,12 +68,12 @@  -- | Initialize default properties from `CommandLine` and `Environment`. defaultProperties' :: ParseCommandLine -> IO Properties-defaultProperties' dpc-  = makePropertiesFromCommandLine dpc empty-  >>= makePropertiesFromEnvironment+defaultProperties' dpc = runLoad $ do+  loadCommandLine dpc+  loadEnvironment  -- | Yaml file name.-type FileName = Text+type FileName = String  -- | Initialize default properties from `CommandLine`, `Environment` and `Yaml` files. -- All these configuration sources has orders, from highest order to lowest order:@@ -96,21 +102,20 @@   :: FileName -- ^ specify default config file name, can reset by config "salak.config.name" from `CommandLine` or `Environment`.   -> ParseCommandLine -- ^ parser for command line   -> IO Properties-defaultPropertiesWithFile' name dpc = do-  p <- defaultProperties' dpc-  let n  = fromMaybe name $ lookup "salak.config.name" p-      p' = insert (toKeys "salak.config.name") (PStr n) p-  c <- getCurrentDirectory-  h <- getHomeDirectory-  foldl (go n) (return p') [(lookup "salak.config.dir" p, False), (Just c, True), (Just h, True)]-  where-    go _ p (Nothing, _) = p-    go n p (Just d, ok) = let f = d </> unpack n in do-      p' <- p-      b <- doesFileExist f-      if b-        then makePropertiesFromYaml f p'-        else if ok then return p' else error $ "File " ++ f ++  " not found"+defaultPropertiesWithFile' name dpc = runLoad $ do+  loadCommandLine dpc+  loadEnvironment+  p <- askProperties+  let n  = fromMaybe name $ p .>> "salak.config.name"+      f  = p .>> "salak.config.dir"+  setValue "salak.config.name" (PStr $ pack n)+  case f of+    Just y -> loadYaml (y </> n)+    _      -> return ()+  c <- lift getCurrentDirectory+  loadYamlIfExists (Just $ c </> n)+  h <- lift getHomeDirectory+  loadYamlIfExists (Just $ h </> n)  -- $use --@@ -133,14 +138,16 @@ -- >   , ext  :: Int -- >   } deriving (Eq, Show) -- >--- > instance FromJSON Config where--- >   parseJSON = withObject "Config" $ \v -> Config--- >         <$> v .:  "name"--- >         <*> v .:? "dir"--- >         <*> (fromMaybe 1 <$> v .:? "ext")+-- > instance FromProperties Config where+-- >   fromProperties v = Config+-- >         <$> v .?> "name"+-- >         <*> v .?> "dir"+-- >         <*> v .?> "ext" .?= 1 -- -- > main = do -- >   p <- defaultPropertiesWithFile "salak.yml"--- >   let Just config = lookup "salak.config" p :: Maybe Config+-- >   let config  = p .>> "salak.config"  :: Config+-- >       enabled = p .?> "salak.enabled" .|= True -- >   print config+-- >   print enabled 
src/Data/Salak/Aeson.hs view
@@ -4,10 +4,12 @@  module Data.Salak.Aeson where +import           Control.Monad.IO.Class+import           Control.Monad.State import           Data.Aeson-import qualified Data.HashMap.Strict as M+import qualified Data.HashMap.Strict    as M import           Data.Salak.Types-import           Data.Vector         (fromList, toList)+import           Data.Vector            (toList)  -- | Load `Properties` from JSON `Value` makePropertiesFromJson :: Value -> Properties -> Properties@@ -30,18 +32,8 @@     g2 (a:_) = [a]     g3 (as,bs) (a,b) = (as++a,bs++b) -instance FromProperties Value where-  fromProperties (Properties []        []) = Empty-  fromProperties (Properties [PBool p] []) = OK $ Bool   p-  fromProperties (Properties [PNum  p] []) = OK $ Number p-  fromProperties (Properties [PStr  p] []) = OK $ String p-  fromProperties (Properties ps [])        = Array . fromList <$> traverse (fromProperties.singleton) ps-  fromProperties (Properties _ [m])        = OK $ Object $ M.map (fromReturn Null . fromProperties) m-  fromProperties (Properties _  ms)        = Array . fromList <$> traverse (fromProperties.singletonMap) ms--instance {-# OVERLAPPABLE #-} FromJSON a => FromProperties a where-  fromProperties a = do-    v :: Value <- fromProperties a-    case fromJSON v of-      Success r -> OK r-      Error   e -> Fail e+-- | Load Properties from JSON Value+--+-- @since 0.2.2+loadJSON :: MonadIO m => Value -> LoadProperties m ()+loadJSON = modify . makePropertiesFromJson
src/Data/Salak/CommandLine.hs view
@@ -1,8 +1,10 @@ module Data.Salak.CommandLine where +import           Control.Monad.IO.Class+import           Control.Monad.State import           Data.Maybe import           Data.Salak.Types-import           Data.Text          (pack)+import           Data.Text              (pack) import           System.Environment  -- | CommandLine parser. Parse command line into property key values.@@ -33,3 +35,13 @@ makePropertiesFromCommandLine' args parser p = do   v <- parser args   return $ makeProperties (fmap (\(a,b) -> (pack a,b)) v) p+++-- | Load Properties from CommandLine+--+-- @since 0.2.2+loadCommandLine :: MonadIO m => ParseCommandLine -> LoadProperties m ()+loadCommandLine pcl = do+  p <- get+  q <- liftIO $ makePropertiesFromCommandLine pcl p+  put q
src/Data/Salak/Environment.hs view
@@ -1,8 +1,10 @@ module Data.Salak.Environment where +import           Control.Monad.IO.Class+import           Control.Monad.State import           Data.Char import           Data.Salak.Types-import           Data.Text          (pack)+import           Data.Text              (pack) import           System.Environment  -- | Load `Properties` from 'Environment'@@ -16,3 +18,9 @@     go (k,v) = (pack $ fmap g2 k,PStr $ pack v)     g2 '_' = '.'     g2 a   = toLower a++-- | Load Properties from CommandLine+--+-- @since 0.2.2+loadEnvironment :: MonadIO m => LoadProperties m ()+loadEnvironment = get >>= liftIO . makePropertiesFromEnvironment >>= put
src/Data/Salak/Operation.hs view
@@ -3,26 +3,37 @@ import           Data.Salak.Types import           Data.Text        (Text, unpack) +-- | Find `Properties` by key and convert to specific Haskell value.+--+-- @since 0.2.1 infixl 5 .?> (.?>) :: FromProperties a => Properties -> Text -> Return a-(.?>) = flip lookup'+(.?>) = flip Data.Salak.Types.lookup +-- | Get property or use default value if not found, but will throw+-- exception if parse failed.+--+-- @since 0.2.1 infixl 5 .|= (.|=) :: Return a -> a -> a-(.|=) (OK   a) _ = a-(.|=) (Fail e) _ = error e-(.|=) _        d = d+(.|=) (Right a)       _ = a+(.|=) (Left (Fail e)) _ = error e+(.|=) _               d = d +-- | Use default value if Key not found+--+-- @since 0.2.1 infixl 5 .?= (.?=) :: Return a -> a -> Return a-(.?=) a b = OK (a .|= b)+(.?=) a b = Right (a .|= b) +-- | Find `Properties` by key and convert to specific Haskell value.+-- Throw error if property not found or parse failed+--+-- @since 0.2.1 infixl 5 .>> (.>>) :: FromProperties a => Properties -> Text -> a-(.>>) p k = case p .?> k of-  OK v   -> v-  Empty  -> case fromProperties empty of-    (OK   a) -> a-    (Fail e) -> error e-    _        -> error $ "Config " <> unpack k <> " not found"-  Fail e -> error e+(.>>) p key = case p .?> key of+  Right v           -> v+  Left (EmptyKey k) -> error $ "property " <> unpack k <> " not set"+  Left (Fail e)     -> error e
src/Data/Salak/Types.hs view
@@ -6,6 +6,7 @@ module Data.Salak.Types where  import           Control.Monad       ((>=>))+import           Control.Monad.State import           Data.Char import qualified Data.HashMap.Strict as M import           Data.Int@@ -15,7 +16,8 @@ import           Data.Text           (Text) import qualified Data.Text           as T import           Data.Word-import           Text.Read+import           System.Directory+import           Text.Read           (readMaybe)  -- | Property key type Key = Text@@ -65,7 +67,6 @@ empty :: Properties empty = Properties [] [] - singleton :: Property -> Properties singleton p = Properties [p] [] @@ -92,25 +93,24 @@ insertMap as p = M.alter (Just . insert as p . fromMaybe empty)  -- | Find `Properties` by key and convert to specific Haskell value.--- Return `Nothing` means not found, and throw `ErrorCall` means convert failed.-lookup :: FromProperties a => Text -> Properties -> Maybe a-lookup k = from . lookup' k-  where-    from :: Return a -> Maybe a-    from (OK a)   = Just a-    from Empty    = Nothing-    from (Fail e) = error e---- | Find `Properties` by key and convert to specific Haskell value.-lookup' :: FromProperties a => Text -> Properties -> Return a-lookup' = go . toKeys+lookup :: FromProperties a => Text -> Properties -> Return a+lookup k = go (toKeys k)   where+    {-# INLINE go #-}     go [] p                      = fromProperties p-    go (a:as) (Properties _ [m]) = case M.lookup a m of-      Just n -> go as n-      _      -> Empty-    go _ _                       = Empty+    go (a:as) (Properties _ ms) = case go as $ fromMaybe empty $ select a ms of+        Left (EmptyKey ke) -> Left $ EmptyKey $ joinKey a ke+        v                  -> v+    select _ []  = Nothing+    select a [m] = M.lookup a m+    select _ _   = Nothing ++joinKey :: Text -> Text -> Text+joinKey "" k = k+joinKey k "" = k+joinKey a b  = a <> "." <> b+ -- | Insert batch properties to `Properties` makeProperties :: [(Text, Property)] -> Properties -> Properties makeProperties = flip (foldl go)@@ -118,52 +118,33 @@     go m (k,v) = insert (toKeys k) v m  -- | Return of `FromProperties`-data Return a-  = Empty-  | OK a-  | Fail String-  deriving Show--instance Functor Return where-  fmap f (OK a)   = OK (f a)-  fmap _ Empty    = Empty-  fmap _ (Fail b) = Fail b--instance Applicative Return where-  pure = OK-  (OK f) <*> (OK a) = OK (f a)-  (Fail x) <*> (Fail y) = Fail $ x ++ ";" ++ y-  (Fail x) <*> _ = Fail x-  _ <*> (Fail y) = Fail y-  _ <*> _ = Empty--instance Monad Return where-  (OK a)   >>= f = f a-  Empty    >>= _ = Empty-  (Fail b) >>= _ = Fail b--fromReturn :: b -> Return b -> b-fromReturn _ (OK a) = a-fromReturn a _      = a+type Return = Either ErrResult+data ErrResult = EmptyKey Text | Fail String deriving Show  -- | Convert `Properties` to Haskell value. class FromProperties a where   fromProperties :: Properties -> Return a  instance FromProperties Property where-  fromProperties (Properties [a] _) = OK a-  fromProperties (Properties [] _)  = Empty-  fromProperties _                  = Fail "property has multi values"+  fromProperties (Properties [a] _) = Right a+  fromProperties (Properties [] _)  = Left $ EmptyKey ""+  fromProperties _                  = Left $ Fail "property has multi values"  instance {-# OVERLAPPABLE #-} FromProperties a => FromProperties [a] where-  fromProperties (Properties ps ms) = traverse fromProperties $ fmap singleton ps ++ fmap singletonMap ms+  fromProperties (Properties ps ms) = traverse fromProperties $ fmap singleton ps <> fmap singletonMap ms +instance {-# OVERLAPPABLE #-} FromProperties a => FromProperties (Maybe a) where+  fromProperties p = case fromProperties p of+    Right          a  -> Right (Just a)+    Left (EmptyKey _) -> Right Nothing+    Left r            -> Left r+ instance FromProperties Scientific where   fromProperties = fromProperties >=> go     where-      go (PNum a) = OK a+      go (PNum a) = Right a       go (PStr a) = to readMaybe $ T.unpack a-      go _        = Fail "bool cannot convert to number"+      go _        = Left $ Fail "bool cannot convert to number"  instance FromProperties String where   fromProperties a = T.unpack <$> fromProperties a@@ -171,8 +152,8 @@ instance FromProperties Text where   fromProperties = fromProperties >=> go     where-      go (PStr a) = OK a-      go a        = OK $ T.pack $ show a+      go (PStr a) = Right a+      go a        = Right $ T.pack $ show a  instance FromProperties Float where   fromProperties a = toRealFloat <$> fromProperties a@@ -215,25 +196,57 @@  to :: (b -> Maybe a) -> b -> Return a to v b = case v b of-  Just a  -> OK a-  Nothing -> Fail "number convert failed"+  Just a  -> Right a+  Nothing -> Left $ Fail "number convert failed"  instance FromProperties Bool where   fromProperties = fromProperties >=> go     where-      go (PBool a) = OK a+      go (PBool a) = Right a       go (PStr  a) = g2 $ T.toLower a-      go _         = Fail "number cannot convert to bool"+      go _         = Left $ Fail "number cannot convert to bool"       g2 :: Text -> Return Bool-      g2 "true"  = OK True-      g2 "false" = OK False-      g2 _       = Fail "string value cannot convert to bool"+      g2 "1"     = Right True+      g2 "true"  = Right True+      g2 "0"     = Right False+      g2 "false" = Right False+      g2 _       = Left $ Fail "string value cannot convert to bool"  instance FromProperties Char where   fromProperties = fromProperties >=> go     where       go (PStr s)-        | T.null s  = Empty-        | otherwise = OK $ T.head s-      go _          = Fail "cannot convert to char"+        | T.null s  = Left  $ EmptyKey ""+        | otherwise = Right $ T.head s+      go _          = Left  $ Fail "cannot convert to char" +-- | Monad to Load Properties+--+-- @since 0.2.2+type LoadProperties = StateT Properties++-- | Load Properties+--+-- @since 0.2.2+runLoad :: Monad m => LoadProperties m a -> m Properties+runLoad a = snd <$> runStateT a empty++-- | Get current Properties+--+-- @since 0.2.2+askProperties :: Monad m => LoadProperties m Properties+askProperties = get++-- | Set value to current properties+--+-- @since 0.2.2+setValue :: Monad m => Text -> Property -> LoadProperties m ()+setValue k v = do+  p <- askProperties+  put (insert (toKeys k) v p)++loadIfExists :: MonadIO m => Maybe FilePath -> (FilePath -> LoadProperties m ()) -> LoadProperties m ()+loadIfExists (Just f) a = do+    e <- liftIO $ doesFileExist f+    when e (a f)+loadIfExists _ _ = return ()
src/Data/Salak/Yaml.hs view
@@ -1,5 +1,7 @@ module Data.Salak.Yaml where +import           Control.Monad.IO.Class+import           Control.Monad.State import           Data.Salak.Aeson import           Data.Salak.Types import           Data.Yaml@@ -9,3 +11,18 @@ makePropertiesFromYaml file p = do   v <- decodeFileThrow file   return $ makePropertiesFromJson v p++-- | Load Properties from Yaml+--+-- @since 0.2.2+loadYaml :: MonadIO m => FilePath -> LoadProperties m ()+loadYaml file = do+  p <- get+  q <- liftIO $ makePropertiesFromYaml file p+  put q++-- | Load Properties from Yaml if exists+--+-- @since 0.2.2+loadYamlIfExists :: MonadIO m => Maybe FilePath -> LoadProperties m ()+loadYamlIfExists mf = loadIfExists mf loadYaml
test/Spec.hs view
@@ -4,13 +4,11 @@  module Main where -import           Data.Aeson import qualified Data.HashMap.Strict    as M-import           Data.Maybe import           Data.Salak import           Data.Salak.CommandLine import           Data.Salak.Environment-import qualified Data.Salak.Types       as P+import           Data.Salak.Operation   () import           Data.Text              (Text, intercalate, pack) import           System.Environment import           Test.Hspec@@ -32,11 +30,11 @@   , ext  :: Int   } deriving (Eq, Show) -instance FromJSON Config where-  parseJSON = withObject "Config" $ \v -> Config-        <$> v .: "name"-        <*> v .: "dir"-        <*> (fromMaybe 1 <$> v .:? "ext")+instance FromProperties Config where+  fromProperties v = Config+        <$> v .?> "name"+        <*> v .?> "dir"+        <*> v .?> "ext" .?= 1  specProperty = do   context "empty" $ do@@ -63,39 +61,39 @@     it "Reject replacement" $ do       insert k "1" m `shouldBe` m     it "quickCheck" $ do-      quickCheck $ \a' (b :: Integer) -> let a = pack a' in Just b == P.lookup a (insert (toKeys a) (PNum $ fromInteger b) empty)-      quickCheck $ \a' (b :: Bool)    -> let a = pack a' in Just b == P.lookup a (insert (toKeys a) (PBool b) empty)-      quickCheck $ \a' (b :: String)  -> let a = pack a' in Just b == P.lookup a (insert (toKeys a) (PStr $ pack b) empty)+      quickCheck $ \a' (b :: Int)    -> let a = pack a' in Just b == (insert (toKeys a) (PNum $ fromIntegral b) empty) .>> a+      quickCheck $ \a' (b :: Bool)   -> let a = pack a' in Just b == (insert (toKeys a) (PBool b)               empty) .>> a+      quickCheck $ \a' (b :: String) -> let a = pack a' in Just b == (insert (toKeys a) (PStr $ pack b)         empty) .>> a   context "lookup" $ do     it "normal" $ do       let m = insert ["a"] (PNum 1) empty           n = insert ["a"] (PStr "true") empty-      (P.lookup "a" empty :: Maybe Int)    `shouldBe`   Nothing-      (P.lookup "a" m     :: Maybe Int)    `shouldBe`   Just  1-      (P.lookup "a" m     :: Maybe Bool)   `shouldFail` Nothing-      (P.lookup "a" m     :: Maybe String) `shouldBe`   Just "1.0"-      (P.lookup "a" n     :: Maybe Int)    `shouldFail` Nothing-      (P.lookup "a" n     :: Maybe Bool)   `shouldBe`   Just True-      (P.lookup "a" n     :: Maybe Text)   `shouldBe`   Just "true"+      (empty .>> "a" :: Maybe Int)    `shouldBe`   Nothing+      (m     .>> "a" :: Maybe Int)    `shouldBe`   Just  1+      (m     .>> "a" :: Maybe Bool)   `shouldFail` Nothing+      (m     .>> "a" :: Maybe String) `shouldBe`   Just "1.0"+      (n     .>> "a" :: Maybe Int)    `shouldFail` Nothing+      (n     .>> "a" :: Maybe Bool)   `shouldBe`   Just True+      (n     .>> "a" :: Maybe Text)   `shouldBe`   Just "true"   context "makeProperties" $ do     it "normal" $ do       m <- makePropertiesFromEnvironment empty       h <- getEnv "HOME"-      (P.lookup "home" m) `shouldBe` Just h+      (m .>> "home") `shouldBe` Just h   context "command-line" $ do     it "normal" $ do       let args = ["--package.a.enabled=true","--package.b.enabled=false","package.c.enabled=false"]       m    <- makePropertiesFromCommandLine' args defaultParseCommandLine empty-      P.lookup "package.a.enabled" m `shouldBe` Just True-      P.lookup "package.b.enabled" m `shouldBe` Just False-      (P.lookup "package.c.enabled" m :: Maybe Bool )`shouldBe` Nothing+      (m .>> "package.a.enabled") `shouldBe` Just True+      (m .>> "package.b.enabled") `shouldBe` Just False+      (m .>> "package.c.enabled" :: Maybe Bool )`shouldBe` Nothing   context "environment" $ do     it "normal" $ do       let args = [("PACKAGE_A_ENABLED","true"),("PACKAGE_B_ENABLED","false")]           m    = makePropertiesFromEnvironment' args empty-      P.lookup "package.a.enabled" m `shouldBe` Just True-      P.lookup "package.b.enabled" m `shouldBe` Just False-      (P.lookup "package.c.enabled" m :: Maybe Bool )`shouldBe` Nothing+      (m .>> "package.a.enabled") `shouldBe` Just True+      (m .>> "package.b.enabled") `shouldBe` Just False+      (m .>> "package.c.enabled" :: Maybe Bool )`shouldBe` Nothing  specProperties = do   context "defaultPropertiesWithFile" $ do@@ -103,32 +101,27 @@         confName' = pack confName     it "read config" $ do       unsetEnv "SALAK_CONFIG_NAME"-      p <- defaultPropertiesWithFile confName'-      P.lookup "salak.config.name" p `shouldBe` Just confName+      p <- defaultPropertiesWithFile confName+      p .>> "salak.config.name" `shouldBe` Just confName     it "read config - replacement" $ do       setEnv "SALAK_CONFIG_NAME" confName       p <- defaultPropertiesWithFile "salak.ok"-      P.lookup "salak.config.name" p `shouldBe` Just confName+      p .>> "salak.config.name" `shouldBe` Just confName     it "read config - not found" $ do       setEnv "SALAK_CONFIG_NAME" "salak.notfound"       setEnv "SALAK_CONFIG_DIR" "test"-      defaultPropertiesWithFile confName' `shouldThrow` anyErrorCall+      defaultPropertiesWithFile confName `shouldThrow` anyException     it "read config - read file parse Config" $ do       setEnv "SALAK_CONFIG_NAME" confName       setEnv "SALAK_CONFIG_DIR" "test"       setEnv "SALAK_CONFIG" confName-      p <- defaultPropertiesWithFile confName'-      let get :: FromProperties a => Text -> Maybe a-          get = flip P.lookup p-      -- print p-      -- let v::Return Value = fromProperties p-      -- P.fromReturn (return ()) $ BC.putStrLn . encodePretty <$> v-      get "salak.config.name"                `shouldBe`   Just confName-      get "salak.config"                     `shouldBe`   Just confName-      (get "salak.config" :: Maybe Config)   `shouldBe`   Just (Config confName' "test" 1)-      (get "array"        :: Maybe [String]) `shouldBe`   Just ["a","b"]-      (get "array"        :: Maybe [Int])    `shouldFail` Nothing-      (get "array"        :: Maybe String)   `shouldFail` Nothing+      p <- defaultPropertiesWithFile confName+      (p .>> "salak.config.name")              `shouldBe`   Just confName+      (p .>> "salak.config")                   `shouldBe`   Just confName+      (p .>> "salak.config" :: Maybe Config)   `shouldBe`   Just (Config confName' "test" 1)+      (p .>> "array"        :: Maybe [String]) `shouldBe`   Just ["a","b"]+      (p .>> "array"        :: Maybe [Int])    `shouldFail` Nothing+      (p .>> "array"        :: Maybe String)   `shouldFail` Nothing