packages feed

boots 0.0.1 → 0.0.2

raw patch · 9 files changed

+72/−23 lines, 9 filesdep ~salakdep ~salak-yamlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: salak, salak-yaml

API changes (from Hackage documentation)

- Boots: booting :: Plugin () m cxt -> AppT cxt m () -> m ()
+ Boots: boot :: Monad m => Plugin () m (m ()) -> m ()
+ Boots: bootApp :: Plugin () m cxt -> AppT cxt m () -> m ()
+ Boots: isoPlugin :: (m () -> n ()) -> (n () -> m ()) -> Plugin i n u -> Plugin i m u
+ Boots: type App cxt = AppT cxt IO
- Boots: bracketP :: MonadCatch m => m u -> (u -> m ()) -> Plugin i m u
+ Boots: bracketP :: forall m i u. MonadCatch m => m u -> (u -> m ()) -> Plugin i m u

Files

README.md view
@@ -7,12 +7,20 @@  Boot applications by using plugins. +### Motivation++Simplify to create an application in Haskell.++When we decide to create an application using Haskell. We may need using configurations, loggers as basic functions. If this application needs storages, caches, etc., then we have to weaving the management of connection of these facilities into the application. Connections need to be created before and be destroyed after using them. There is a common strategy to manage connections, that is using `Control.Monad.Cont`. Then we can encapsulate the management of connections separately. For example, we can write a database plugin `Plugin cxt m DBConnection`, which can manage the database connections in monad `m` with context `cxt`. Context `cxt` may be requested for configurations or logging functions. When all the components of application are encapsulated by plugins, then building an application will be simplified.++### Have a Try+ ```Haskell main :: IO ()-main = booting (pluginSimple "application") go+main = bootApp (pluginSimple "application") go   where     go = forever $ do-      user <- require "user"-      logInfo $ "Hello, " <> user <> "!"+      user <- require "user"              -- Request for configuration.+      logInfo $ "Hello, " <> user <> "!"  -- Request for logging.       liftIO $ threadDelay 1000000 ```
boots.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: boots-version: 0.0.1+version: 0.0.2 license: MIT license-file: LICENSE copyright: 2019 Daniel YU@@ -30,7 +30,7 @@     default-language: Haskell2010     default-extensions: FlexibleInstances MultiParamTypeClasses                         GeneralizedNewtypeDeriving OverloadedStrings RecordWildCards-                        FlexibleContexts+                        FlexibleContexts RankNTypes ScopedTypeVariables     build-depends:         base >=4.10 && <5,         data-default >=0.7.1.1 && <0.8,@@ -52,7 +52,7 @@     default-language: Haskell2010     default-extensions: FlexibleInstances MultiParamTypeClasses                         GeneralizedNewtypeDeriving OverloadedStrings RecordWildCards-                        FlexibleContexts+                        FlexibleContexts RankNTypes ScopedTypeVariables     build-depends:         base >=4.10 && <5,         boots -any,@@ -84,7 +84,7 @@     default-language: Haskell2010     default-extensions: FlexibleInstances MultiParamTypeClasses                         GeneralizedNewtypeDeriving OverloadedStrings RecordWildCards-                        FlexibleContexts+                        FlexibleContexts RankNTypes ScopedTypeVariables     build-depends:         base >=4.10 && <5,         data-default >=0.7.1.1 && <0.8,
main/Main.hs view
@@ -5,7 +5,7 @@ import           Control.Monad  main :: IO ()-main = booting (pluginSimple "application") go+main = bootApp (pluginSimple "application") go   where     go = forever $ do       logInfo "Hello, world!"
src/Boots.hs view
@@ -8,11 +8,40 @@ -- -- Boot application by using plugins. --+-- * Motivation+--+-- Simplify to create an application in Haskell.+--+-- When we decide to create an application using Haskell.+-- We may need using configurations, loggers as basic functions. +-- If this application needs storages, caches, etc., +-- then we have to weaving the management of connection of these facilities into the application. +-- Connections need to be created before and be destroyed after using them. +-- There is a common strategy to manage connections, that is using `Control.Monad.Cont`. +-- Then we can encapsulate the management of connections separately. +-- For example, we can write a database plugin `Plugin` @cxt@ @m@ @DBConnection@, +-- which can manage the database connections in monad @m@ with context @cxt@. +-- Context @cxt@ may be requested for getting configurations or logging functions. +-- When all the components of application are encapsulated by plugins, then building an application will be simplified.+--+-- * Have a Try+-- -- >>> booting (pluginSimple "application") (logInfo "hello") -- 2019-07-27 19:35:30  INFO [application] Ghci1 - hello -- >>> booting (pluginSimple "application") (require "user" >>= logInfo) -- 2019-07-27 19:37:45  INFO [application] Ghci2 - daniel --+-- Main+-- +-- > main :: IO ()+-- > main = bootApp (pluginSimple "application") go+-- >   where+-- >     go = forever $ do+-- >       user <- require "user"              -- Request for configuration.+-- >       logInfo $ "Hello, " <> user <> "!"  -- Request for logging.+-- >       liftIO $ threadDelay 1000000+--+ module Boots(     module Boots.Internal   , module Boots.Plugin
src/Boots/Internal.hs view
@@ -9,17 +9,22 @@ -- Boot cores. -- module Boots.Internal(-  -- * Main function-    booting+  -- * Plugin+    boot+  , module Boots.Internal.Plugin   -- * Application+  , bootApp   , module Boots.Internal.App-  -- * Application plugin-  , module Boots.Internal.Plugin   ) where  import           Boots.Internal.App import           Boots.Internal.Plugin --- | Run application using a plugin. Context @cxt@ can't escape from @m@.-booting :: Plugin () m cxt -> AppT cxt m () -> m ()-booting plugin app = runPlugin () plugin (`runAppT` app)+-- | Run application only in plugin.+boot :: Monad m => Plugin () m (m ()) -> m ()+boot plugin = runPlugin () plugin id++-- | Run application in context with the help of plugin. Context @cxt@ can't escape from @m@.+--  If you want to define your own `AppT` then please use 'boot' or 'runPlugin'.+bootApp :: Plugin () m cxt -> AppT cxt m () -> m ()+bootApp plugin app = runPlugin () plugin (`runAppT` app)
src/Boots/Internal/App.hs view
@@ -10,6 +10,7 @@ -- module Boots.Internal.App(     AppT+  , App   , runAppT   , liftIO   , ask@@ -17,7 +18,6 @@   , throwM   ) where -import           Boots.Internal.Plugin import           Control.Monad.Catch import           Control.Monad.IO.Unlift import           Control.Monad.Reader@@ -25,6 +25,9 @@ -- | Application monad transformation. newtype AppT cxt m a = AppT { unAppT :: ReaderT cxt m a }   deriving (Functor, Applicative, Monad, MonadTrans, MonadReader cxt, MonadIO, MonadThrow, MonadCatch, MonadMask)++-- | Simple IO monad.+type App cxt = AppT cxt IO  -- | Run application monad transformation. runAppT :: cxt -> AppT cxt m a -> m a
src/Boots/Internal/Plugin.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-} -- | -- Module:      Boots.Internal.Plugin -- Copyright:   2019 Daniel YU@@ -16,6 +14,7 @@   , promote   , withPlugin   , mapPlugin+  , isoPlugin   , bracketP   ) where @@ -50,11 +49,16 @@ withPlugin :: (i -> j) -> Plugin j m u -> Plugin i m u withPlugin f = Plugin . withReaderT f . unPlugin +-- | Transform a plugin with monad @n@ to a plugin with monad @m@.+isoPlugin :: (m () -> n ()) -> (n () -> m ()) -> Plugin i n u -> Plugin i m u+isoPlugin f g = Plugin . mapReaderT go . unPlugin+  where+    go (ContT fnc) = ContT $ \mc -> g $ fnc (f . mc)+ -- | Apply a function to transform the result of a continuation-passing computation. mapPlugin :: (m () -> m ()) -> Plugin i m u -> Plugin i m u mapPlugin f = Plugin . mapReaderT (mapContT f) . unPlugin - -- | Create bracket style plugin, used for manage resources, which need to open and close. -- -- A simple example:@@ -65,7 +69,7 @@ -- using -- close bracketP-  :: MonadCatch m+  :: forall m i u. MonadCatch m   => m u          -- ^ Open resource.   -> (u -> m ())  -- ^ Close resource.   -> Plugin i m u -- ^ Resource plugin.@@ -73,8 +77,8 @@   where     {-# INLINE go #-}     go f u = do-      v <- try (f u)-      cl u+      v <- try $ f u+      _ <- try $ cl u :: m (Either SomeException ())       case v of         Left  e -> throwM (e :: SomeException)         Right x -> return x
src/Boots/Plugin/Logger.hs view
@@ -22,13 +22,13 @@   , logOther   ) where -import Data.Monoid((<>)) import           Boots.Internal import           Boots.Plugin.Salak import           Control.Monad import           Control.Monad.Logger.CallStack import           Control.Monad.Reader import           Data.Default+import           Data.Monoid                    ((<>)) import           Data.Text                      (Text, toLower, unpack) import           Data.Word import           Lens.Micro
test/Spec.hs view