rapid 0.1.1 → 0.1.2
raw patch · 3 files changed
+136/−32 lines, 3 files
Files
- CHANGELOG.md +5/−0
- Rapid.hs +117/−23
- rapid.cabal +14/−9
CHANGELOG.md view
@@ -1,3 +1,8 @@+# 0.1.2++ * Added `restartWith` and `startWith`.+ * Better documentation.+ # 0.1.1 * Minor documentation fixes.
Rapid.hs view
@@ -12,7 +12,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE RankNTypes #-} -- | -- Module: Rapid@@ -20,15 +20,22 @@ -- License: Apache License 2.0 -- Maintainer: Ertugrul Söylemez <esz@posteo.de> ----- This library provides a safer and more convenient wrapper around the--- <https://hackage.haskell.org/package/foreign-store foreign-store library>.+-- This module provides a rapid prototyping suite for GHCi that can be+-- used standalone or integrated into editors. You can hot-reload+-- individual running components as you make changes to their code. It+-- is designed to shorten the development cycle during the development+-- of long-running programs like servers, web applications and+-- interactive user interfaces. ----- You can use it for background services within a GHCi session that--- survive loading, reloading and unloading modules, which is--- particularly useful when writing long-running programs like servers--- and user interfaces.+-- It can also be used in the context of batch-style programs: Keep+-- resources that are expensive to create in memory and reuse them+-- across module reloads instead of reloading/recomputing them after+-- every code change. ----- __Please read the "Safety and securty" section below!__+-- Technically this package is a safe and convenient wrapper around+-- <https://hackage.haskell.org/package/foreign-store foreign-store>.+--+-- __Read the "Safety and securty" section before using this module!__ module Rapid ( -- * Introduction@@ -40,6 +47,9 @@ -- ** Reusing expensive resources -- $reusing + -- ** Cabal notes+ -- $cabal+ -- ** Emacs integration -- $emacs @@ -52,7 +62,9 @@ -- * Threads restart,+ restartWith, start,+ startWith, stop, -- * Communication@@ -182,10 +194,27 @@ -> k -- ^ Name of the thread. -> IO () -- ^ Action the thread runs. -> IO ()-restart r k action =+restart = restartWith async+++-- | Create a thread with the given name that runs the given action.+--+-- The thread is restarted each time an update occurs.+--+-- The first argument is the function used to create the thread. It can+-- be used to select between 'async', 'asyncBound' and 'asyncOn'.++restartWith+ :: (Ord k)+ => (forall a. IO a -> IO (Async a)) -- ^ Thread creation function.+ -> Rapid k -- ^ Rapid state handle.+ -> k -- ^ Name of the thread.+ -> IO () -- ^ Action the thread runs.+ -> IO ()+restartWith myAsync r k action = withThread r k $ \mtv -> do whenJust mtv cancelAndWait- Just <$> async action+ Just <$> myAsync action -- | Create a thread with the given name that runs the given action.@@ -193,13 +222,36 @@ -- When an update occurs and the thread is currently not running, it is -- started. -start :: (Ord k) => Rapid k -> k -> IO () -> IO ()-start r k action =+start+ :: (Ord k)+ => Rapid k -- ^ Rapid state handle.+ -> k -- ^ Name of the thread.+ -> IO () -- ^ Action the thread runs.+ -> IO ()+start = startWith async+++-- | Create a thread with the given name that runs the given action.+--+-- When an update occurs and the thread is currently not running, it is+-- started.+--+-- The first argument is the function used to create the thread. It can+-- be used to select between 'async', 'asyncBound' and 'asyncOn'.++startWith+ :: (Ord k)+ => (forall a. IO a -> IO (Async a)) -- ^ Thread creation function.+ -> Rapid k -- ^ Rapid state handle.+ -> k -- ^ Name of the thread.+ -> IO () -- ^ Action the thread runs.+ -> IO ()+startWith myAsync r k action = withThread r k $- maybe (Just <$> async action)+ maybe (Just <$> myAsync action) (\tv -> poll tv >>= maybe (pure (Just tv))- (\_ -> Just <$> async action))+ (\_ -> Just <$> myAsync action)) -- | Delete the thread with the given name.@@ -270,6 +322,32 @@ fmap (\x -> (Just (toDyn x), x)) gen +{- $cabal++In general a Cabal project should not have this library as a build-time+dependency. However, in certain environments (like Nix-based+development) it may be beneficial to include it in the @.cabal@ file+regardless. A simple solution is to add a flag:++> flag Devel+> default: False+> description: Enable development dependencies+> manual: True+>+> library+> build-depends:+> base >= 4.8 && < 5,+> {- ... -}+> if flag(devel)+> build-depends: rapid+> {- ... -}++Now you can configure your project with @-fdevel@ during development and+have this module available.++-}++ {- $communication If you need your background threads to communicate with each other, for@@ -351,6 +429,12 @@ {- $intro +While working on a project you may want to have your code running in the+background and restart parts of it as you make changes. The premise of+this introduction is that you already have such a project, for example a+web application, and that you use a persistent GHCi session (either+standalone or built into your editor).+ To use this library in your project create a module conventionally named @DevelMain@ that exports an action conventionally named @update@: @@ -361,14 +445,14 @@ > update :: IO () > update = > rapid 0 $ \r ->-> -- Your service management goes here.+> -- We'll list our components here shortly. > pure () -The idea is that within a GHCi session this @update@ action is run+The idea is that within a GHCi session you run this @update@ action whenever you want to reload your project during development. In the simplest case, like in a web application, your project consists of a-single service that is just restarted each time you reload. Here is an-example using the Snap Framework:+single HTTP server thread that is just restarted each time you reload.+Here is an example using the Snap Framework: > import qualified Data.Text as T > import Rapid@@ -383,10 +467,10 @@ Once you run @update@ in a GHCi session, a server is started (port 8000) that keeps running in the background, even when you reload modules. The REPL is fully responsive, so you can continue working. When you want to-apply the changes you have made, you run @update@ again. To see this in-action, change the text string in the example, reload the module and-then run @update@. Also observe that nothing is changed until you-actually run @update@.+apply the changes you have made, you reload the @DevelMain@ module and+run @update@ again. To see this in action, change the text string in+the example, reload the module and then run @update@. Also observe that+nothing is changed until you actually run @update@. When you want to stop a running background thread, replace 'restart' within the @update@ action by 'stop' and run @update@. The action given@@ -397,14 +481,24 @@ are not restarted during a reload, but are only started and then kept running: +> import MyProject.MyDatabase+> import MyProject.MyBackgroundWorker+> import MyProject.MyWebServer+> import Rapid+> > update =-> rapid 0 $ \r ->+> rapid 0 $ \r -> do > start r "database" myDatabase > start r "worker" myBackgroundWorker > restart r "webserver" myWebServer Usually you would put 'restart' in front of the component that you are currently working on, while using 'start' with all others.++Note that even though you are working on the code in+@MyProject.MyWebServer@ you are always reloading the @DevelMain@ module.+There is nothing wrong with loading and reloading other modules, but+only this module gives you access to your @update@ action. -}
rapid.cabal view
@@ -13,9 +13,9 @@ -- limitations under the License. name: rapid-version: 0.1.1+version: 0.1.2 category: Development-synopsis: GHCi background threads, hot reloading and reload-surviving values+synopsis: Rapid prototyping with GHCi: hot reloading of running components and reload-surviving values maintainer: Ertugrul Söylemez <esz@posteo.de> author: Ertugrul Söylemez <esz@posteo.de>@@ -25,15 +25,20 @@ license: Apache license-file: LICENSE -description: This package provides a safe and convenient wrapper around- <https://hackage.haskell.org/package/foreign-store foreign-store>- for hot-reloadable background threads during a GHCi session, useful- for the development of long-running programs like servers, web+description: This package provides a rapid prototyping suite for GHCi+ that can be used standalone or integrated into editors. You can+ hot-reload individual running components as you make changes to+ their code. It is designed to shorten the development cycle during+ the development of long-running programs like servers, web applications and interactive user interfaces. .- It can also be used in the context of batch-style programs to keep- resources that are expensive to create in memory instead of having- to recreate them after every module reload.+ It can also be used in the context of batch-style programs: Keep+ resources that are expensive to create in memory and reuse them+ across module reloads instead of reloading/recomputing them after+ every code change.+ .+ Technically this package is a safe and convenient wrapper around+ <https://hackage.haskell.org/package/foreign-store foreign-store>. build-type: Simple cabal-version: >= 1.10