salak 0.3.3.1 → 0.3.3.2
raw patch · 12 files changed
+385/−415 lines, 12 filesdep +dlistPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: dlist
API changes (from Hackage documentation)
- Salak: askSalak :: MonadSalak m => m SourcePack
- Salak: instance GHC.Base.Monad m => Salak.Internal.Prop.FromProp m Salak.FileConfig
- Salak.Internal: askSalak :: MonadSalak m => m SourcePack
- Salak.Internal: instance GHC.Base.Monad m => Salak.Internal.Prop.MonadSalak (Salak.Internal.RunSalakT m)
- Salak.Trie: alterF :: (Functor f, Eq v) => (Maybe v -> f (Maybe v)) -> Keys -> Trie v -> f (Trie v)
+ Salak: askSourcePack :: MonadSalak m => m SourcePack
+ Salak: instance Salak.Internal.Prop.FromProp m Salak.FileConfig
+ Salak.Internal: askSourcePack :: MonadSalak m => m SourcePack
+ Salak.Internal: fromKeys :: [Key] -> Keys
+ Salak.Internal: instance Control.Monad.IO.Class.MonadIO m => Salak.Internal.Prop.MonadSalak (Salak.Internal.RunSalakT m)
+ Salak.Trie: subTrie :: Key -> Trie v -> Trie v
+ Salak.Trie: subTries :: Keys -> Trie v -> Trie v
- Salak: class Monad m => FromProp m a
+ Salak: class FromProp m a
- Salak: fromProp :: (FromProp m a, Generic a, GFromProp m (Rep a)) => Prop m a
+ Salak: fromProp :: (FromProp m a, Generic a, GFromProp m (Rep a), Monad m) => Prop m a
- Salak.Internal: Keys :: [Key] -> Keys
+ Salak.Internal: Keys :: DList Key -> Keys
- Salak.Internal: SourcePack :: !Source -> ![Key] -> !MVar QFunc -> !MVar LFunc -> !IO ReloadResult -> SourcePack
+ Salak.Internal: SourcePack :: !Source -> !Keys -> !MVar QFunc -> !MVar LFunc -> !IO ReloadResult -> SourcePack
- Salak.Internal: [pref] :: SourcePack -> ![Key]
+ Salak.Internal: [pref] :: SourcePack -> !Keys
- Salak.Internal: [unKeys] :: Keys -> [Key]
+ Salak.Internal: [unKeys] :: Keys -> DList Key
- Salak.Internal: simpleKeys :: Text -> [Key]
+ Salak.Internal: simpleKeys :: Text -> Keys
Files
- README.md +2/−2
- salak.cabal +13/−3
- src/Salak.hs +2/−2
- src/Salak/Internal.hs +6/−4
- src/Salak/Internal/Key.hs +33/−6
- src/Salak/Internal/Prop.hs +160/−169
- src/Salak/Internal/Source.hs +2/−14
- src/Salak/Trie.hs +25/−25
- test/Salak/Internal/KeySpec.hs +37/−0
- test/Salak/Internal/PropSpec.hs +37/−0
- test/Salak/Internal/SourceSpec.hs +66/−0
- test/Spec.hs +2/−190
README.md view
@@ -72,7 +72,7 @@ , ext :: Int } deriving (Eq, Show) -instance Monad m => FromProp m Config where+instance FromProp m Config where fromProp = Config <$> "user" ? pattern "[a-z]{5,16}" <*> "pwd"@@ -90,7 +90,7 @@ λ> import Data.Default λ> import Data.Text(Text) λ> data Config = Config { name :: Text, dir :: Maybe Text, ext :: Int} deriving (Eq, Show)-λ> instance Monad m => FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1+λ> instance FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1 λ> runSalak def (require "") :: IO Config Config {name = "daniel", dir = Nothing, ext = 1} ```
salak.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: salak-version: 0.3.3.1+version: 0.3.3.2 license: MIT license-file: LICENSE copyright: 2019 Daniel YU@@ -26,7 +26,9 @@ Salak.Internal.Prop Salak.Internal.Writable default-language: Haskell2010- default-extensions: RecordWildCards TupleSections+ default-extensions: RecordWildCards TupleSections OverloadedStrings+ ScopedTypeVariables FlexibleInstances MultiParamTypeClasses+ DeriveGeneric ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures build-depends: attoparsec >=0.13.2.2 && <0.14,@@ -35,6 +37,7 @@ containers >=0.6.0.1 && <0.7, data-default >=0.7.1.1 && <0.8, directory >=1.3.3.0 && <1.4,+ dlist >=0.8.0.7 && <0.9, exceptions >=0.10.2 && <0.11, filepath >=1.4.2.1 && <1.5, hashable >=1.2.7.0 && <1.3,@@ -50,8 +53,12 @@ test-suite spec type: exitcode-stdio-1.0 main-is: Spec.hs+ build-tool-depends: hspec-discover:hspec-discover -any hs-source-dirs: test src other-modules:+ Salak.Internal.KeySpec+ Salak.Internal.PropSpec+ Salak.Internal.SourceSpec Salak Salak.Internal Salak.Internal.Key@@ -62,7 +69,9 @@ Salak.Trie Paths_salak default-language: Haskell2010- default-extensions: RecordWildCards TupleSections+ default-extensions: RecordWildCards TupleSections OverloadedStrings+ ScopedTypeVariables FlexibleInstances MultiParamTypeClasses+ DeriveGeneric ghc-options: -Wall -fno-warn-orphans -fno-warn-missing-signatures build-depends: QuickCheck >=2.13.2 && <2.14,@@ -72,6 +81,7 @@ containers >=0.6.0.1 && <0.7, data-default >=0.7.1.1 && <0.8, directory >=1.3.3.0 && <1.4,+ dlist >=0.8.0.7 && <0.9, exceptions >=0.10.2 && <0.11, filepath >=1.4.2.1 && <1.5, hashable >=1.2.7.0 && <1.3,
src/Salak.hs view
@@ -108,7 +108,7 @@ , configDir :: Maybe FilePath } -instance Monad m => FromProp m FileConfig where+instance FromProp m FileConfig where fromProp = FileConfig <$> "name" .?= Nothing <*> "dir" .?= Nothing@@ -210,7 +210,7 @@ -- >>> import Data.Default -- >>> import Data.Text(Text) -- >>> data Config = Config { name :: Text, dir :: Maybe Text, ext :: Int} deriving (Eq, Show)--- >>> instance Monad m => FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1+-- >>> instance FromProp m Config where fromProp = Config <$> "user" <*> "dir" <*> "ext" .?= 1 -- >>> runSalak def (require "") :: IO Config -- Config {name = "daniel", dir = Nothing, ext = 1} --
src/Salak/Internal.hs view
@@ -42,6 +42,7 @@ , Keys(..) , Key(..) , simpleKeys+ , fromKeys , ToKeys(..) , setVal , Val(..)@@ -100,7 +101,7 @@ liftNT a = MS.get >>= liftIO . runLoad a instance MonadIO m => MonadSalak (LoadSalakT m) where- askSalak = MS.get >>= toSourcePack+ askSourcePack = MS.get >>= toSourcePack setLogF f = do UpdateSource{..} <- MS.get liftIO $ void $ swapMVar lfunc f@@ -125,9 +126,10 @@ runRun :: Monad m => RunSalakT m a -> SourcePack -> m a runRun (RunSalakT ma) = runReaderT ma -instance Monad m => MonadSalak (RunSalakT m) where- askSalak = RunSalakT ask +instance MonadIO m => MonadSalak (RunSalakT m) where+ askSourcePack = ask+ instance (MonadThrow m, IU.MonadUnliftIO m) => IU.MonadUnliftIO (RunSalakT m) where askUnliftIO = do ut <- ask@@ -172,7 +174,7 @@ runLoad (lm >> MS.get) (UpdateSource r 0 HM.empty l q u) >>= toSourcePack toSourcePack :: MonadIO m => UpdateSource -> m SourcePack-toSourcePack UpdateSource{..} = liftIO (readMVar ref) >>= \s -> return $ SourcePack s [] qfunc lfunc go+toSourcePack UpdateSource{..} = liftIO (readMVar ref) >>= \s -> return $ SourcePack s mempty qfunc lfunc go where go = do t <- readMVar ref
src/Salak/Internal/Key.hs view
@@ -1,9 +1,14 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} module Salak.Internal.Key( Key(..) , Keys(..)+ , mempty , simpleKeys+ , singletonKey+ , fromKeys+ , toKeyList , ToKeys(..) , isNum , isStr@@ -11,11 +16,14 @@ import Control.Applicative ((<|>)) import Data.Attoparsec.Text-import Data.Coerce (coerce)+import qualified Data.DList as D import Data.Hashable import Data.List (intercalate) import Data.Text (Text) import qualified Data.Text as T+#if __GLASGOW_HASKELL__ < 804+import Data.Semigroup+#endif data Key = KT !Text@@ -28,10 +36,29 @@ compare (KI _) _ = LT compare _ _ = GT -newtype Keys = Keys { unKeys :: [Key] } deriving Eq+newtype Keys = Keys { unKeys :: D.DList Key } deriving Eq +emptyKey :: Keys+emptyKey = Keys D.empty++singletonKey :: Key -> Keys+singletonKey k = fromKeys [k]++fromKeys :: [Key] -> Keys+fromKeys = Keys . D.fromList++toKeyList :: Keys -> [Key]+toKeyList = D.toList . unKeys++instance Semigroup Keys where+ (Keys a) <> (Keys b) = Keys $ a <> b++instance Monoid Keys where+ mempty = emptyKey+ mappend = (<>)+ instance Show Keys where- show ks = toKey (coerce ks)+ show = toKey . D.toList . unKeys where toKey = intercalate "." . go go (a@(KT _):cs) = let (b,c) = break isStr cs in (show a ++ concat (show <$> b)) : go c@@ -56,8 +83,8 @@ show (KT x) = T.unpack x show (KI i) = "[" ++ show i ++ "]" -simpleKeys :: Text -> [Key]-simpleKeys as = fmap KT $ filter (not.T.null) $ T.splitOn "." as+simpleKeys :: Text -> Keys+simpleKeys = fromKeys . fmap KT . filter (not.T.null) . T.splitOn "." exprs :: Parser [Key] exprs = concat <$> ( (expr <|> return []) `sepBy` char '.')@@ -91,7 +118,7 @@ toKeys = Right instance ToKeys Text where- toKeys = fmap Keys . selectors+ toKeys = fmap fromKeys . selectors where selectors = go . parse exprs . flip T.snoc '\n' go (Done i r) = if i /= "\n" then Left $ "uncomplete parse" ++ T.unpack i else Right r
src/Salak/Internal/Prop.hs view
@@ -17,6 +17,7 @@ import Control.Monad import Control.Monad.Catch import Control.Monad.Except+import Control.Monad.Fail import Control.Monad.Identity (Identity (..)) import Control.Monad.Reader import qualified Data.ByteString as B@@ -26,7 +27,7 @@ import Data.Hashable (Hashable) import qualified Data.HashMap.Strict as HM import Data.Int-import Data.List (sortBy)+import Data.List (sort) import qualified Data.Map.Strict as M import Data.Maybe import Data.Menshen@@ -47,44 +48,26 @@ import Salak.Internal.Val import qualified Salak.Trie as TR import Text.Read (readMaybe)--class Monad m => FromProp m a where- fromProp :: Prop m a- default fromProp :: (Generic a, GFromProp m (Rep a)) => Prop m a- fromProp = fmap to gFromProp--newtype Prop m a- = Prop { unProp :: ReaderT SourcePack (ExceptT SomeException m) a }- deriving (Functor, Applicative, Monad, MonadReader SourcePack, MonadIO)--instance MonadTrans Prop where- lift = Prop . lift . lift--instance Monad m => A.Alternative (Prop m) where- empty = notFound- a <|> b = do- v <- try a- case v of- Right x -> return x- Left (_ :: SomeException) -> b+import Unsafe.Coerce (unsafeCoerce) -- | Core type class of salak, which provide function to parse properties. class Monad m => MonadSalak m where- -- | Monad has the ability to get a `SourcePack` instance.- askSalak :: m SourcePack + -- | Monad has the ability to get a SourcePack instance.+ askSourcePack :: m SourcePack+ -- | Get reload action which used for reload profiles askReload :: m (IO ReloadResult)- askReload = reload <$> askSalak+ askReload = reload <$> askSourcePack setLogF :: MonadIO m => (String -> IO ()) -> m () setLogF f = do- SourcePack{..} <- askSalak+ SourcePack{..} <- askSourcePack liftIO $ void $ swapMVar lref f logSalak :: MonadIO m => String -> m () logSalak msg = do- SourcePack{..} <- askSalak+ SourcePack{..} <- askSourcePack liftIO $ do f <- readMVar lref f msg@@ -99,55 +82,98 @@ -- `require` supports parse `IO` values, which actually wrap a 'MVar' variable and can be reseted by reloading configurations. -- Normal value will not be affected by reloading configurations. require :: (MonadThrow m, FromProp m a) => Text -> m a- require ks = do- sp@SourcePack{..} <- askSalak- case search ks source of- Left e -> throwM $ SalakException (unpack ks) (toException $ PropException e)- Right (k,t) -> do- v <- runProp2 sp { source = t, pref = pref ++ unKeys k} fromProp- case v of- Left e -> case fromException e of- Just (SalakException a b) -> throwM $ SalakException a b- Just pe -> throwM $ SalakException (unpack ks) (toException pe)- _ -> throwM $ SalakException (unpack ks) e- Right x -> return x+ require ks = askSourcePack >>= \s -> runProp s $ do+ case toKeys ks of+ Left e -> failKey (unpack ks) (PropException e)+ Right k -> withKeys k fromProp -instance {-# OVERLAPPABLE #-} (m ~ t m', Monad m', Monad m, MonadTrans t, MonadSalak m') => MonadSalak m where- askSalak = lift askSalak+-- | Property parser, used to parse property from `Value`+newtype Prop m a+ = Prop { unProp :: ReaderT SourcePack (ExceptT SomeException m) a }+ deriving (Functor, Applicative, Monad, MonadReader SourcePack, MonadIO) -instance Monad m => MonadSalak (Prop m) where- askSalak = Prop ask+runProp :: MonadThrow m => SourcePack -> Prop m a -> m a+runProp sp (Prop p) = do+ v <- runExceptT (runReaderT p sp)+ case v of+ Left e -> throwM e+ Right x -> return x +withProp :: (SourcePack -> SourcePack) -> Prop m a -> Prop m a+withProp = unsafeCoerce withReaderT++withKey :: Key -> Prop m a -> Prop m a+withKey = withKeys . singletonKey++withKeys :: Keys -> Prop m a -> Prop m a+withKeys key = withProp+ $ \SourcePack{..} ->+ SourcePack{pref = pref <> key, source = TR.subTries key source, ..}++data SalakException+ = PropException String -- ^ Parse failed+ | NullException -- ^ Not found+ | SalakException String SomeException+ deriving Show++instance Exception SalakException+++failKey :: Monad m => String -> SalakException -> Prop m a+failKey ks e = do+ SourcePack{..} <- ask+ throwM+ $ SalakException (go (show pref) ks)+ $ toException e+ where+ go "" a = a+ go a "" = a+ go a b = a <> "." <> b++-- | Automatic convert literal string into an instance of `Prop` @m@ @a@.+instance (Monad m, FromProp m a) => IsString (Prop m a) where+ fromString ks = do+ case toKeys ks of+ Left e -> failKey ks (PropException e)+ Right k -> withKeys k fromProp+++instance MonadTrans Prop where+ lift = Prop . lift . lift++instance Monad m => A.Alternative (Prop m) where+ empty = failKey "" NullException++ a <|> b = do+ v <- try a+ case v of+ Right x -> return x+ Left (_ :: SomeException) -> b++instance Monad m => MonadError SomeException (Prop m) where+ throwError = Prop . lift . throwError . toException+ catchError (Prop ma) me = Prop $ do+ c <- ask+ lift $ catchError (runReaderT ma c) (\e -> runReaderT (unProp $ me e) c)+ instance Monad m => MonadThrow (Prop m) where- throwM = Prop . lift . throwError . toException+ throwM = throwError . toException instance Monad m => MonadCatch (Prop m) where- catch (Prop a) f = do- sp <- ask- v <- lift $ runExceptT (runReaderT a sp)- case v of- Left e -> case fromException e of- Just ee -> f ee- _ -> throwM e- Right x -> return x+ catch ma me = catchError ma (\e -> maybe (throwM e) me $ fromException e) -runProp2 :: Monad m => SourcePack -> Prop m a -> m (Either SomeException a)-runProp2 sp (Prop p) = runExceptT (runReaderT p sp)+instance Monad m => MonadFail (Prop m) where+ fail = failKey "" . PropException -runProp1 :: MonadThrow m => SourcePack -> Prop m a -> m a-runProp1 sp p = do- v <- runProp2 sp p- case v of- Left e -> throwM e- Right x -> return x -runProp :: Monad m => SourcePack -> Prop m a -> Prop m a-runProp sp p = do- v <- lift $ runProp2 sp p- case v of- Left e -> throwM e- Right x -> return x+-- | Type class used to parse properties.+class FromProp m a where + -- | Parse properties from `Value`.+ fromProp :: Monad m => Prop m a+ default fromProp :: (Generic a, GFromProp m (Rep a), Monad m) => Prop m a+ fromProp = fmap to gFromProp+ instance FromProp m a => FromProp m (Maybe a) where fromProp = do v <- try fromProp@@ -162,7 +188,6 @@ instance FromProp m a => FromProp m (Either String a) where fromProp = do- SourcePack{..} <- ask v <- try fromProp return $ case v of Left e -> Left $ show (e :: SomeException)@@ -170,19 +195,15 @@ instance {-# OVERLAPPABLE #-} FromProp m a => FromProp m [a] where fromProp = do- sp@SourcePack{..} <- askSalak- foldM (go sp) [] $ sortBy g2 $ filter (isNum.fst) $ HM.toList $ TR.getMap source- where- go s vs (k,t) = (:vs) <$> runProp s { pref = pref s ++ [k], source = t} fromProp- g2 (a,_) (b,_) = compare b a+ SourcePack{..} <- ask+ sequence $ (`withKey` fromProp) <$> sort (filter isNum $ HM.keys $ TR.getMap source) instance {-# OVERLAPPABLE #-} (IsString s, FromProp m a) => FromProp m [(s, a)] where fromProp = do- sp@SourcePack{..} <- askSalak- foldM (go sp) [] $ sortBy g2 $ filter (isStr.fst) $ HM.toList $ TR.getMap source+ SourcePack{..} <- ask+ sequence $ go <$> sort (filter isStr $ HM.keys $ TR.getMap source) where- go s vs (k,t) = (:vs) . (fromString $ show $ Keys [k],) <$> runProp s { pref = pref s ++ [k], source = t} fromProp- g2 (a,_) (b,_) = compare b a+ go k = (fromString $ show $ singletonKey k,) <$> withKey k fromProp instance (Eq s, Hashable s, IsString s, FromProp m a) => FromProp m (HM.HashMap s a) where fromProp = HM.fromList <$> fromProp@@ -201,8 +222,7 @@ buildIO sp a = liftIO $ do aref <- newMVar a modifyMVar_ (qref sp) $ \f -> return $ \s ->- let b = runProp1 sp {source = search2 s (pref sp), pref = pref sp} fromProp- in case b of+ case runProp sp {source = s} $ withKeys (pref sp) fromProp of Left e -> Left $ show e Right v -> do vb <- v@@ -210,34 +230,7 @@ return (swapMVar aref (fromMaybe a vb) >> io) return (readMVar aref) -data SalakException- = PropException String -- ^ Parse failed- | NullException -- ^ Not found- | SalakException String SomeException- deriving Show -instance Exception SalakException---- | Automatic convert literal string into an instance of `Prop` @m@ @a@.-instance FromProp m a => IsString (Prop m a) where- fromString ks = do- sp@SourcePack{..} <- askSalak- case search ks source of- Left e -> throwM $ SalakException- (if null pref then ks else show (Keys pref) ++ "." ++ ks)- (toException $ PropException e)- Right (k,t) -> runProp sp { source = t, pref = pref ++ unKeys k} fromProp--notFound :: Monad m => Prop m a-notFound = do- SourcePack{..} <- askSalak- throwM $ SalakException (show (Keys pref)) $ toException NullException--err :: Monad m => String -> Prop m a-err e = do- SourcePack{..} <- askSalak- throwM $ PropException $ show (Keys pref) ++ ":" ++ e- -- | Prop operators. -- -- Suppose we have the following definition:@@ -276,24 +269,24 @@ -- | Support for setting default `IO` value. instance (MonadIO m, FromProp (Either SomeException) a) => PropOp (Prop m) (IO a) where (.?=) ma a = do- sp <- askSalak+ sp <- ask v <- try ma case v of Left (_ :: SomeException) -> liftIO a >>= buildIO sp Right o -> return o instance Monad m => HasValid (Prop m) where- invalid = err . toI18n+ invalid = Control.Monad.Fail.fail . toI18n -- | Parse primitive value from `Value` readPrimitive :: Monad m => (Value -> Either String a) -> Prop m a readPrimitive f = do- SourcePack{..} <- askSalak+ SourcePack{..} <- ask vx <- g $ TR.getPrimitive source >>= getVal case f <$> vx of- Just (Left e) -> err e+ Just (Left e) -> Control.Monad.Fail.fail e Just (Right a) -> return a- _ -> notFound+ _ -> A.empty where g = return @@ -305,29 +298,27 @@ go _ x = Left $ fst (typeOfV x) ++ " cannot convert to enum" -class Monad m => GFromProp m f where- gFromProp :: Prop m (f a)+class GFromProp m f where+ gFromProp :: Monad m => Prop m (f a) -instance {-# OVERLAPPABLE #-} (Monad m, Constructor c, GFromProp m a) => GFromProp m (M1 C c a) where+instance {-# OVERLAPPABLE #-} (Constructor c, GFromProp m a) => GFromProp m (M1 C c a) where gFromProp | conIsRecord m = fmap M1 gFromProp | otherwise = fmap M1 $ gEnum $ T.pack (conName m) where m = undefined :: t c a x -gEnum :: (Monad m, GFromProp m f) => Text -> Prop m (f a)+gEnum :: (GFromProp m f, Monad m) => Text -> Prop m (f a) gEnum va = do o <- gFromProp readEnum $ \x -> if x==va then Right o else Left "enum invalid" instance {-# OVERLAPPABLE #-} (Selector s, GFromProp m a) => GFromProp m(M1 S s a) where- gFromProp = Prop $ do- let k = KT $ T.pack $ selName (undefined :: t s a p)- withReaderT (\s -> s { pref = pref s ++ [k], source = search1 (source s) k }) $ unProp $ M1 <$> gFromProp+ gFromProp = withKey (KT $ T.pack $ selName (undefined :: t s a p)) $ M1 <$> gFromProp instance {-# OVERLAPPABLE #-} GFromProp m a => GFromProp m (M1 D i a) where gFromProp = M1 <$> gFromProp -instance {-# OVERLAPPABLE #-} (FromProp m a) => GFromProp m (K1 i a) where+instance {-# OVERLAPPABLE #-} FromProp m a => GFromProp m (K1 i a) where gFromProp = fmap K1 fromProp instance Monad m => GFromProp m U1 where@@ -336,62 +327,62 @@ instance {-# OVERLAPPABLE #-} (GFromProp m a, GFromProp m b) => GFromProp m (a:*:b) where gFromProp = (:*:) <$> gFromProp <*> gFromProp -instance {-# OVERLAPPABLE #-} (Monad m, GFromProp m a, GFromProp m b) => GFromProp m (a:+:b) where+instance {-# OVERLAPPABLE #-} (GFromProp m a, GFromProp m b) => GFromProp m (a:+:b) where gFromProp = fmap L1 gFromProp A.<|> fmap R1 gFromProp -instance (Monad m, FromProp m a) => FromProp m (Identity a) where+instance FromProp m a => FromProp m (Identity a) where fromProp = Identity <$> fromProp -instance (Monad m, FromProp m a, FromProp m b) => FromProp m (a,b) where+instance (FromProp m a, FromProp m b) => FromProp m (a,b) where fromProp = (,) <$> fromProp <*> fromProp -instance (Monad m, FromProp m a, FromProp m b, FromProp m c) => FromProp m(a,b,c) where+instance (FromProp m a, FromProp m b, FromProp m c) => FromProp m(a,b,c) where fromProp = (,,) <$> fromProp <*> fromProp <*> fromProp -instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d) => FromProp m(a,b,c,d) where+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d) => FromProp m(a,b,c,d) where fromProp = (,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp -instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e) => FromProp m(a,b,c,d,e) where+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e) => FromProp m(a,b,c,d,e) where fromProp = (,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp -instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f) => FromProp m(a,b,c,d,e,f) where+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f) => FromProp m(a,b,c,d,e,f) where fromProp = (,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp -instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g) => FromProp m(a,b,c,d,e,f,g) where+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g) => FromProp m(a,b,c,d,e,f,g) where fromProp = (,,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp -instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h) => FromProp m(a,b,c,d,e,f,g,h) where+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h) => FromProp m(a,b,c,d,e,f,g,h) where fromProp = (,,,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp -instance (Monad m, FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h, FromProp m i) => FromProp m(a,b,c,d,e,f,g,h,i) where+instance (FromProp m a, FromProp m b, FromProp m c, FromProp m d, FromProp m e, FromProp m f, FromProp m g, FromProp m h, FromProp m i) => FromProp m(a,b,c,d,e,f,g,h,i) where fromProp = (,,,,,,,,) <$> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp <*> fromProp -instance (Monad m, FromProp m a) => FromProp m (Min a) where+instance FromProp m a => FromProp m (Min a) where fromProp = Min <$> fromProp -instance (Monad m, FromProp m a) => FromProp m (Max a) where+instance FromProp m a => FromProp m (Max a) where fromProp = Max <$> fromProp -instance (Monad m, FromProp m a) => FromProp m (First a) where+instance FromProp m a => FromProp m (First a) where fromProp = First <$> fromProp -instance (Monad m, FromProp m a) => FromProp m (Last a) where+instance FromProp m a => FromProp m (Last a) where fromProp = Last <$> fromProp -instance (Monad m, FromProp m a) => FromProp m (Dual a) where+instance FromProp m a => FromProp m (Dual a) where fromProp = Dual <$> fromProp -instance (Monad m, FromProp m a) => FromProp m (Sum a) where+instance FromProp m a => FromProp m (Sum a) where fromProp = Sum <$> fromProp -instance (Monad m, FromProp m a) => FromProp m (Product a) where+instance FromProp m a => FromProp m (Product a) where fromProp = Product <$> fromProp -instance (Monad m, FromProp m a) => FromProp m (Option a) where+instance FromProp m a => FromProp m (Option a) where fromProp = Option <$> fromProp -instance Monad m => FromProp m Bool where+instance FromProp m Bool where fromProp = readPrimitive go where go (VB x) = Right x@@ -403,25 +394,25 @@ _ -> Left "string convert bool failed" go x = Left $ getType x ++ " cannot be bool" -instance Monad m => FromProp m Text where+instance FromProp m Text where fromProp = readPrimitive go where go (VT x) = Right x go x = Right $ T.pack $ snd $ typeOfV x -instance Monad m => FromProp m TL.Text where+instance FromProp m TL.Text where fromProp = TL.fromStrict <$> fromProp -instance Monad m => FromProp m B.ByteString where+instance FromProp m B.ByteString where fromProp = TB.encodeUtf8 <$> fromProp -instance Monad m => FromProp m BL.ByteString where+instance FromProp m BL.ByteString where fromProp = TBL.encodeUtf8 <$> fromProp -instance Monad m => FromProp m String where+instance FromProp m String where fromProp = T.unpack <$> fromProp -instance Monad m => FromProp m Scientific where+instance FromProp m Scientific where fromProp = readPrimitive go where go (VT x) = case readMaybe $ T.unpack x of@@ -430,49 +421,49 @@ go (VI x) = Right x go x = Left $ getType x ++ " cannot be number" -instance Monad m => FromProp m Float where+instance FromProp m Float where fromProp = toRealFloat <$> fromProp -instance Monad m => FromProp m Double where+instance FromProp m Double where fromProp = toRealFloat <$> fromProp -instance Monad m => FromProp m Integer where+instance FromProp m Integer where fromProp = toInteger <$> (fromProp :: Prop m Int) -instance Monad m => FromProp m Int where+instance FromProp m Int where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Int8 where+instance FromProp m Int8 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Int16 where+instance FromProp m Int16 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Int32 where+instance FromProp m Int32 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Int64 where+instance FromProp m Int64 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Word where+instance FromProp m Word where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Word8 where+instance FromProp m Word8 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Word16 where+instance FromProp m Word16 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Word32 where+instance FromProp m Word32 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m Word64 where+instance FromProp m Word64 where fromProp = fromProp >>= toNum -instance Monad m => FromProp m NominalDiffTime where+instance FromProp m NominalDiffTime where fromProp = fromInteger <$> fromProp -instance Monad m => FromProp m DiffTime where+instance FromProp m DiffTime where fromProp = fromInteger <$> fromProp instance (HasResolution a, Monad m) => FromProp m (Fixed a) where@@ -481,40 +472,40 @@ toNum :: (Monad m, Integral i, Bounded i) => Scientific -> Prop m i toNum s = case toBoundedInteger s of Just v -> return v- _ -> err "scientific number doesn't fit in the target representation"+ _ -> Control.Monad.Fail.fail "scientific number doesn't fit in the target representation" -instance Monad m => FromProp m CBool where+instance FromProp m CBool where fromProp = do b <- fromProp return $ if b then 1 else 0 -instance Monad m => FromProp m CShort where+instance FromProp m CShort where fromProp = CShort <$> fromProp -instance Monad m => FromProp m CUShort where+instance FromProp m CUShort where fromProp = CUShort <$> fromProp -instance Monad m => FromProp m CInt where+instance FromProp m CInt where fromProp = CInt <$> fromProp -instance Monad m => FromProp m CUInt where+instance FromProp m CUInt where fromProp = CUInt <$> fromProp -instance Monad m => FromProp m CLong where+instance FromProp m CLong where fromProp = CLong <$> fromProp -instance Monad m => FromProp m CULong where+instance FromProp m CULong where fromProp = CULong <$> fromProp -instance Monad m => FromProp m CLLong where+instance FromProp m CLLong where fromProp = CLLong <$> fromProp -instance Monad m => FromProp m CULLong where+instance FromProp m CULLong where fromProp = CULLong <$> fromProp -instance Monad m => FromProp m CFloat where+instance FromProp m CFloat where fromProp = CFloat <$> fromProp -instance Monad m => FromProp m CDouble where+instance FromProp m CDouble where fromProp = CDouble <$> fromProp
src/Salak/Internal/Source.hs view
@@ -7,7 +7,6 @@ import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HM import qualified Data.Heap as H-import Data.Maybe import Salak.Internal.Key import Salak.Internal.Val import qualified Salak.Trie as T@@ -27,7 +26,7 @@ data SourcePack = SourcePack { source :: !Source- , pref :: ![Key]+ , pref :: !Keys , qref :: !(MVar QFunc) , lref :: !(MVar LFunc) , reload :: !(IO ReloadResult)@@ -61,23 +60,12 @@ gen i = foldr go T.empty where go (k,v) x = case toKeys k of- Left e -> T.alter (g3 e) (Keys []) x+ Left e -> T.alter (g3 e) mempty x Right k' -> T.alter (g2 $ Val i $ toVal v) k' x g2 v (Just (a,Vals c)) = Just (a, Vals $ H.insert v c) g2 v _ = Just ([], Vals $ H.singleton v) g3 e (Just (a,c)) = Just (e:a,c) g3 e _ = Just ([e], Vals H.empty)--search :: (ToKeys k) => k -> Source -> Either String (Keys, Source)-search k t = fmap (go . unKeys) (toKeys k)- where- go ks = (Keys ks, foldl search1 t ks)--search2 :: Source -> [Key] -> Source-search2 = foldl search1--search1 :: Source -> Key -> Source-search1 m key = fromMaybe T.empty $ HM.lookup key $ T.getMap m fmt :: ModType -> Int -> String -> String -> String fmt m i s n = concat ['#' : show i, ' ' : show m, ' ' : s , ' ' : n]
src/Salak/Trie.hs view
@@ -21,13 +21,15 @@ , Salak.Trie.null , member , lookup+ , subTrie+ , subTries , insert , modify , modifyF , modify' , update , alter- , alterF+ -- , alterF -- * Lists , Salak.Trie.toList , fromList@@ -41,13 +43,14 @@ import Control.Applicative (pure, (<*>)) import Control.Monad (Monad (..)) import Data.Bool+import qualified Data.DList as D import Data.Eq import Data.Foldable (Foldable (..)) import Data.Function import Data.Functor import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HM-import Data.List (concat, intercalate, map, reverse, (++))+import Data.List (concat, intercalate, map, (++)) import Data.Maybe import Data.Traversable import Data.Tuple (uncurry)@@ -97,15 +100,16 @@ member :: Eq v => Keys -> Trie v -> Bool member k t = isJust (lookup k t) +subTrie :: Key -> Trie v -> Trie v+subTrie key = fromMaybe empty . HM.lookup key . getMap++subTries :: Keys -> Trie v -> Trie v+subTries ks v = foldl (flip subTrie) v (toKeyList ks)+ -- | /O(log (n+m))/. Return the primitive value to which the specified key is mapped, -- or Nothing if this trie contains no mapping for the key. lookup :: Eq v => Keys -> Trie v -> Maybe v-lookup (Keys keys) = go keys- where- go [] (Trie v _) = v- go (k:ks) (Trie _ m) = case HM.lookup k m of- Just t -> go ks t- _ -> Nothing+lookup keys = getPrimitive . subTries keys -- | /O(log n)/. Associate the specified value with the specified key in this trie. -- If this trie previously contained a mapping for the key, the old value is replaced.@@ -120,7 +124,7 @@ -- | /O(log (n+m))/. The expression (`modify'` ks f trie) modifies the sub trie at ks. modify' :: Eq v => Keys -> (Trie v -> Trie v) -> Trie v -> Trie v-modify' (Keys ks) f = foldr modify f ks+modify' ks f = foldr modify f (toKeyList ks) -- | /O(log m)/. The expression (`modifyF` k f trie) modifies the sub trie at k. modifyF :: (Monad m, Eq v) => Key -> (Trie v -> m (Trie v)) -> Trie v -> m (Trie v)@@ -131,33 +135,29 @@ -- | /O(1)/. The expression (update f trie) updates the primitive value in the trie. update :: Eq v => (Maybe v -> Maybe v) -> Trie v -> Trie v-update f = alter f (Keys [])+update f = alter f mempty -- | /O(n)/. The expression (update f ks trie) updates the primitive value of sub trie at ks. alter :: Eq v => (Maybe v -> Maybe v) -> Keys -> Trie v -> Trie v-alter f (Keys keys) = go keys- where- go [] (Trie v m) = Trie (f v) m- go (k:ks) (Trie v m) = Trie v $ HM.alter (g2 ks) k m- g2 ks t = let t1 = go ks (fromMaybe empty t) in if t1 == empty then Nothing else Just t1+alter f keys = modify' keys (\(Trie a b) -> Trie (f a) b) -- | /O(n)/. The expression (update f ks trie) updates the primitive value of sub trie at ks.-alterF :: (Functor f, Eq v) => (Maybe v -> f(Maybe v)) -> Keys -> Trie v -> f (Trie v)-alterF f (Keys keys) = go keys- where- go [] (Trie v m) = (`Trie` m) <$> f v- go (k:ks) (Trie v m) = Trie v <$> HM.alterF (g2 ks) k m- g2 ks t = g3 <$> go ks (fromMaybe empty t)- g3 t = if t == empty then Nothing else Just t+-- alterF :: (Functor f, Eq v) => (Maybe v -> f(Maybe v)) -> Keys -> Trie v -> f (Trie v)+-- alterF f keys = modifyF+ -- where+ -- go D.Nil (Trie v m) = (`Trie` m) <$> f v+ -- go (D.Cons k ks) (Trie v m) = Trie v <$> HM.alterF (g2 ks) k m+ -- g2 ks t = g3 <$> go ks (fromMaybe empty t)+ -- g3 t = if t == empty then Nothing else Just t -- | /O(n*m)/. Return a list of this tries's elements. The list is produced lazily. toList :: Trie v -> [(Keys, v)]-toList = go []+toList = go D.empty where- go p (Trie (Just v) m) = (Keys $ reverse p, v) : g2 p m+ go p (Trie (Just v) m) = (Keys p, v) : g2 p m go p (Trie _ m) = g2 p m g2 p m = concat $ g3 p <$> HM.toList m- g3 p (k,t) = go (k:p) t+ g3 p (k,t) = go (D.cons k p) t -- | /O(n*m*log n)/. Construct a trie with the supplied mappings. -- If the list contains duplicate mappings, the later mappings take precedence.
+ test/Salak/Internal/KeySpec.hs view
@@ -0,0 +1,37 @@+module Salak.Internal.KeySpec where++import Data.List (intercalate)+import Data.Text (Text, pack, unpack)+import Salak.Internal.Key+import Test.Hspec+import Test.QuickCheck++newtype SKey = SKey { unKey :: Text } deriving Show++instance Arbitrary SKey where+ arbitrary = do+ key <- choose (1,20)+ vs <- vectorOf key $ do+ k <- choose (1,20)+ v <- vectorOf k $ choose ('a','z')+ b <- choose (0,10) :: Gen Int+ if b > 0 then return v else do+ x <- choose (0,10) :: Gen Int+ return (v ++ "[" ++ show x ++ "]")+ return (SKey $ pack $ intercalate "." vs)+++spec :: SpecWith ()+spec = do+ context "selectors" $ do+ it "normal" $ do+ toKeys ("" :: Text) `shouldBe` Right mempty+ toKeys ("." :: Text) `shouldBe` Right mempty+ toKeys (".." :: Text) `shouldBe` Right mempty+ toKeys ("xx" :: Text) `shouldBe` Right (fromKeys $ [KT "xx"])+ toKeys ("xx[0]" :: Text) `shouldBe` Right (fromKeys $ [KT "xx", KI 0])+ toKeys ("xx.yy" :: Text) `shouldBe` Right (fromKeys $ [KT "xx", KT "yy"])+ toKeys ("xx[0][1]" :: Text) `shouldBe` Right (fromKeys $ [KT "xx", KI 0, KI 1])+ show (fromKeys $ KT "x" : (KI <$> [0..9])) `shouldBe` "x[0][1][2][3][4][5][6][7][8][9]"+ it "QuickCheck" $ do+ quickCheck $ \s -> let s' = unKey s in (show <$> toKeys s') `shouldBe` Right (unpack s')
+ test/Salak/Internal/PropSpec.hs view
@@ -0,0 +1,37 @@+module Salak.Internal.PropSpec where++import Control.Concurrent.MVar+import Data.Int+import Salak.Internal+import Salak.Internal.Source+import Salak.Internal.Val+import qualified Salak.Trie as T+import Test.Hspec+-- import Test.QuickCheck++newSource :: Value -> Source+newSource v = T.singleton $ modVals (Val 0 v) emptyVals++newSourcePack :: Value -> IO SourcePack+newSourcePack v = do+ let source = newSource v+ pref = mempty+ reload = return $ ReloadResult False []+ qref <- newMVar $ \_ -> Right (return ())+ lref <- newMVar $ \_ -> return ()+ return SourcePack{..}++spec :: SpecWith ()+spec = do+ context "VT" $ do+ it "text" $ do+ sp <- newSourcePack (VT "128")+ let run :: forall m a. Monad m => RunSalakT m a -> m a+ run = (`runRun` sp)+ vInt :: Int <- run $ require ""+ vInt32 :: Int32 <- run $ require ""+ -- vInt8 :: Int8 <- run $ require ""+ 128 `shouldBe` vInt+ 128 `shouldBe` vInt32+ -- print vInt8+
+ test/Salak/Internal/SourceSpec.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE NoOverloadedLists #-}+module Salak.Internal.SourceSpec where++import Control.Monad.Writer+import Data.Text (Text, unpack)+import GHC.Generics+import Salak+import Salak.Internal+import Salak.Internal.Source+import qualified Salak.Trie as T+import System.Random (randomIO)+import Test.Hspec+import Test.QuickCheck+++data Config = Config+ { level :: IO Int+ , world :: Maybe Bool+ }++instance MonadIO m => FromProp m Config where+ fromProp = Config <$> "level" .?= (return 1) <*> "world"++data Hello = Hello+ { hello :: IO Int+ } deriving Generic++instance MonadIO m => FromProp m Hello++loadRandom :: (MonadThrow m, MonadIO m) => Text -> LoadSalakT m ()+loadRandom key = loadList True (unpack key) go+ where+ go = do+ a :: Int <- randomIO+ return [(key, a)]++spec :: SpecWith ()+spec = do+ context "source" $ do+ it "normal - 2" $ do+ let (_,b,c) = extract T.empty $ gen 0 ([("hello", "world")] :: [(Text, Text)])+ length c `shouldBe` 0+ length (T.toList b) `shouldBe` 1+ it "normal - 2" $ do+ let (_,b,c) = extract T.empty $ gen 0 ([("hello.value", "world")] :: [(Text, Text)])+ length c `shouldBe` 0+ length (T.toList b) `shouldBe` 1+ context "Reload test" $ do+ it "reload" $ do+ loadAndRunSalak (loadRandom "hello") $ do+ Hello{..} <- require ""+ Config{..} <- require ""+ x <- liftIO hello+ liftIO $ print x+ liftIO $ print world+ q1 <- liftIO level+ r <- askReload+ lift $ quickCheck $ \(_ :: Int) -> do+ ReloadResult{..} <- liftIO r+ when hasError $ print msgs+ hasError `shouldBe` False+ msgs `shouldBe` ["hello:Mod"]+ y <- hello+ x `shouldNotBe` y+ q2 <- level+ q1 `shouldBe` q2
test/Spec.hs view
@@ -1,190 +1,2 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Main where--import Control.Monad.Writer-import Data.List (intercalate)-import Data.Text (Text, pack, unpack)-import GHC.Generics-import Salak-import Salak.Internal-import Salak.Internal.Source-import qualified Salak.Trie as T-import System.Random (randomIO)-import Test.Hspec-import Test.QuickCheck--main :: IO ()-main = hspec spec--spec :: Spec-spec = do- describe "Salak.Types" specProperty--newtype SKey = SKey { unKey :: Text } deriving Show--instance Arbitrary SKey where- arbitrary = do- key <- choose (1,20)- vs <- vectorOf key $ do- k <- choose (1,20)- v <- vectorOf k $ choose ('a','z')- b <- choose (0,10) :: Gen Int- if b > 0 then return v else do- x <- choose (0,10) :: Gen Int- return (v ++ "[" ++ show x ++ "]")- return (SKey $ pack $ intercalate "." vs)--data Hello = Hello- { hello :: IO Int- } deriving Generic--instance MonadIO m => FromProp m Hello--data Config = Config- { level :: IO Int- , world :: Maybe Bool- }--instance MonadIO m => FromProp m Config where- fromProp = Config <$> "level" .?= (return 1) <*> "world"--loadRandom :: (MonadThrow m, MonadIO m) => Text -> LoadSalakT m ()-loadRandom key = loadList True (unpack key) go- where- go = do- a :: Int <- randomIO- return [(key, a)]--specProperty :: SpecWith ()-specProperty = do- context "selectors" $ do- it "normal" $ do- toKeys ("" :: Text) `shouldBe` Right (Keys $ [])- toKeys ("." :: Text) `shouldBe` Right (Keys $ [])- toKeys (".." :: Text) `shouldBe` Right (Keys $ [])- toKeys ("xx" :: Text) `shouldBe` Right (Keys $ [KT "xx"])- toKeys ("xx[0]" :: Text) `shouldBe` Right (Keys $ [KT "xx", KI 0])- toKeys ("xx.yy" :: Text) `shouldBe` Right (Keys $ [KT "xx", KT "yy"])- toKeys ("xx[0][1]" :: Text) `shouldBe` Right (Keys $ [KT "xx", KI 0, KI 1])- show (Keys $ KT "x" : (KI <$> [0..9])) `shouldBe` "x[0][1][2][3][4][5][6][7][8][9]"- it "QuickCheck" $ do- quickCheck $ \s -> let s' = unKey s in (show <$> toKeys s') `shouldBe` Right (unpack s')- -- context "value" $ do- -- it "basic" $ do- -- newVT "xxxx" 0 `shouldBe` VT 0 "xxxx"- -- newVT "{x.y}" 0 `shouldBe` VT 0 "{x.y}"- -- newVT "${x*}" 0 `shouldBe` VT 0 "${x*}"- -- newVT "${x}" 0 `shouldBe` VRef 0 [RRef [KT "x"]]- -- newVT "${x.y}" 0 `shouldBe` VRef 0 [RRef [KT "x", KT "y"]]- -- newVT "${x${y}}" 0 `shouldBe` VT 0 "${x${y}}"- -- newVT "a${x}b" 0 `shouldBe` VRef 0 [RVal "a", RRef [KT "x"], RVal "b"]- -- newVT "a${x}b${" 0 `shouldBe` VRef 0 [RVal "a", RRef [KT "x"], RVal "b${"]- -- newVT "a${x}b${c}" 0 `shouldBe` VRef 0 [RVal "a", RRef [KT "x"], RVal "b", RRef [KT "c"]]- context "source" $ do- it "normal - 2" $ do- let (a,b,c) = extract T.empty $ gen 0 ([("hello", "world")] :: [(Text, Text)])- length c `shouldBe` 0- length (T.toList b) `shouldBe` 1- -- it "normal - 3" $ do- -- let (s2,e2) = runWriter $ insert "1" (VT 0 "world") emptySource- -- sizeSource s2 `shouldBe` 1- -- length e2 `shouldBe` 0- -- it "normal - 4" $ do- -- let (s3,e3) = runWriter $ insert "a.b" (VT 0 "world") emptySource- -- print s3- -- sizeSource s3 `shouldBe` 1- -- length e3 `shouldBe` 0- -- context "source - merge" $ do- -- let s = fst $ runWriter $ insert "hello" (VT 0 "world") emptySource- -- so = fst $ runWriter $ insert "hello" (VT 1 "yyyyy") emptySource- -- s1 = fst $ runWriter $ insert "hello" (VT 0 "xxxxx") emptySource- -- it "merge - del" $ do- -- let (s2,e2) = runWriter $ replace 0 emptySource s- -- s2 `shouldBe` emptySource- -- e2 `shouldBe` ["#0 Del hello"]- -- let (s3,e3) = runWriter $ replace 1 emptySource s- -- s3 `shouldBe` s- -- e3 `shouldBe` []- -- it "merge - mod" $ do- -- let (s3,e3) = runWriter $ replace 0 s1 s- -- e3 `shouldBe` ["#0 Mod hello"]- -- s3 `shouldBe` s1- -- let (s2,e2) = runWriter $ replace 1 s1 s- -- e2 `shouldBe` []- -- s2 `shouldBe` s- -- let (_,e4) = runWriter $ replace 1 so s- -- e4 `shouldBe` ["#1 Add hello"]- -- it "merge - add" $ do- -- let (s4,e4) = runWriter $ replace 0 s emptySource- -- e4 `shouldBe` ["#0 Add hello"]- -- s4 `shouldBe` s- -- let (s2,e2) = runWriter $ replace 1 s emptySource- -- s2 `shouldBe` emptySource- -- e2 `shouldBe` []- -- let (s3,e3) = runWriter $ replace 1 so emptySource- -- e3 `shouldBe` ["#1 Add hello"]- -- s3 `shouldBe` so- -- it "merge - unchange" $ do- -- let (s5,e5) = runWriter $ replace 0 s s- -- e5 `shouldBe` []- -- s5 `shouldBe` s- -- context "Generic" $ do- -- it "conf" $ do- -- sp <- runLoadT Nothing $ loadOnceMock- -- [ ("name", "Daniel")- -- , ("age", "18")- -- , ("male", "yes")- -- ]- -- errs sp `shouldBe` []- -- let a = search "" sp :: Either String Conf- -- print a- -- isRight a `shouldBe` True- -- it "placeholder" $ do- -- let xs = [ ("name", "daniel")- -- , ("user", "${name}")- -- , ("a","${b}")- -- , ("b","${a}")- -- , ("x", "${y}")- -- , ("y", "${z}")- -- , ("z", "Hey! you")- -- ]- -- loadAndRunSalak (loadOnceMock xs) $ do- -- a <- require "name"- -- b <- require "user"- -- x <- require "x"- -- z <- require "z"- -- lift $ do- -- a `shouldBe` (b :: Text)- -- x `shouldBe` (z :: Text)- -- let x = loadAndRunSalak (loadOnceMock xs) (require "a") :: IO Text- -- x `shouldThrow` anyErrorCall- context "Reload test" $ do- it "reload" $ do- loadAndRunSalak (loadRandom "hello") $ do- Hello{..} <- require ""- Config{..} <- require ""- x <- liftIO hello- liftIO $ print x- liftIO $ print world- q1 <- liftIO level- r <- askReload- lift $ quickCheck $ \(_ :: Int) -> do- ReloadResult{..} <- liftIO r- when hasError $ print msgs- hasError `shouldBe` False- msgs `shouldBe` ["hello:Mod"]- y <- hello- x `shouldNotBe` y- q2 <- level- q1 `shouldBe` q2---+-- file test/Spec.hs+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}