rapid 0.1.5 → 0.1.5.1
raw patch · 3 files changed
+82/−87 lines, 3 files
Files
- README.md +1/−2
- Rapid.hs +58/−70
- rapid.cabal +23/−15
README.md view
@@ -1,5 +1,4 @@-Rapid-=====+# [Rapid](https://hackage.haskell.org/package/rapid) This is a helper library for rapid prototyping in GHCi sessions. It provides hot-reloadable background threads as well as values that can be
Rapid.hs view
@@ -1,7 +1,7 @@ -- | -- Copyright: (c) 2016 Ertugrul Söylemez -- License: BSD3--- Maintainer: Ertugrul Söylemez <esz@posteo.de>+-- Maintainer: Markus Läll <markus.l2ll@gmail.com> -- Stability: experimental -- -- This module provides a rapid prototyping suite for GHCi that can be@@ -405,15 +405,17 @@ {- $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).+While developing a project you may want to have your app running in+the background and restart (parts of) it as you iterate. The premises+to using this library are: -To use this library in your project create a module conventionally named-@DevelMain@ that exports an action conventionally named @update@:+1. you already have such a project +2. you use GHCi++To use this functionality, create a new module in your project and+export the @update@ action:+ > module DevelMain (update) where > > import Rapid@@ -424,11 +426,9 @@ > -- We'll list our components here shortly. > pure () -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 HTTP server thread that is just restarted each time you reload.-Here is an example using the Snap Framework:+After loading this module in GHCi you run @update@ whenever you want+to restart the application in the background. E.g, in the case of a+web server that server is simply restarted on every @update@: > import qualified Data.Text as T > import Rapid@@ -440,22 +440,18 @@ > restart r "webserver" $ > quickHttpServe (writeText (T.pack "Hello world!")) -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 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@.+The app keeps running in the background even when you reload modules,+and GHCi REPL continues to be functional as well. To apply new+changes, you simply reload @DevelMain@ again and run @update@.+Changing "Hello world!" to something else above will start responding+with the new text after you 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-to 'stop' is actually ignored. It only takes the action argument for-your convenience.+To stop the background thread, replace @restart@ with @stop@ within+@update@ and run it. Note that the action given to 'stop' is actually+ignored. It only takes the action argument for your convenience. -You can run multiple threads at the same time and also have threads that-are not restarted during a reload, but are only started and then kept-running:+You can run multiple threads in the background simultaneously, have+some of them restart while others not: > import MyProject.MyDatabase > import MyProject.MyBackgroundWorker@@ -464,28 +460,23 @@ > > update = > rapid 0 $ \r -> do-> start r "database" myDatabase-> start r "worker" myBackgroundWorker-> restart r "webserver" myWebServer+> start r "database" myDatabase -- doesn't restart on update+> start r "worker" myBackgroundWorker -- doesn't restart on update+> restart r "webserver" myWebServer -- restarts on update -Usually you would put 'restart' in front of the component that you are-currently working on, while using 'start' with all others.+Usually you'd use @restart@ in front of the component you are working+on, while using @start@ for 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.+Note that even while working on @MyProject.MyWebServer@ you're always+reloading @DevelMain@ to get the new @update@. -} {- $reusing -Mutable references as introduced in the previous section can also be-used to shorten the development cycle in the case when an expensive-resource has to be created. As an example imagine that you need to-parse a huge file into a data structure. You can keep the result of-that in memory across reloads. Example with parsing JSON:+This library can also be used to shorten the development cycle when+using expensive resources: > import Control.Exception > import Data.Aeson@@ -499,48 +490,45 @@ > > -- You can now reuse 'value' across reloads. -If you want to recreate the value at some point, you can just change-'createRef' to 'writeRef' and then run @update@. Keep in mind to change-it back @createRef@ afterward. Use 'deleteRef' to remove values you no-longer need, so they can be garbage-collected.+The above parses blah.json just once on startup. To actually recreate+the value replace @createRef@ to @writeRef@ temporarily and run @update@. +Using @deleteRef@ in the same manner removes values you no longer need.+ -} {- $safety -It's easy to crash your GHCi session with this library. In order to-prevent that, you must follow these rules:+It's easy to crash GHCi with this library. In order to prevent that,+follow these rules: - * Do not change your service name type (the type argument of 'Rapid',- i.e. the second argument to 'restart', 'start' and 'stop') within a- session. The simplest way to do that is to resist the temptation to- define a custom name type, and just use strings instead. If you do- change the name type, you should restart GHCi.+ * Do not change your service name type (the second argument to+ @start@, @stop@ and @restart@) within a session. Simplest way+ to do that is to resist the temptation to define a custom name+ type and just use strings instead. If you do change the name+ type then you need to restart GHCi. - * Be careful with mutable variable created with 'createRef': If the- value type changes (e.g. constructors or fields were changed), the- variable must be recreated, for example by using 'writeRef' once. This- most likely entails restarting all threads that were using the variable.- Again the safest option is to just restart GHCi.+ * Be careful with mutable variables created with @createRef@: if the+ value type changes (e.g. constructors or fields were changed), so+ must the variable be recreated, e.g by using @writeRef@ once.+ This likely also entails restarting all the threads that were+ using this variable. Again, the safest option is to restart GHCi. * If any package in the current environment changes (especially this library itself), for example by updating a package via @cabal@ or- @stack@, the @update@ action is likely to crash or go wrong in subtle- ways due to binary incompatibility. If packages change, restart GHCi.+ @stack@, the @update@ action is likely to crash or go wrong in+ subtle ways due to binary incompatibility. Again, restarting GHCi+ solves this. - * __This library is a development tool! Do not even think of using it to hot-reload in a productive environment!__- There are much safer and more appropriate ways to hot-reload code in- production, for example by using a plugin system.+ * __This library is a development tool! Do not use it to hot-reload+ productive environments!__ There are much safer and more+ appropriate ways to hot-reload code in production, for example by+ using a plugin system. The reason for this unsafety is that the underlying /foreign-store/-library is itself very unsafe in nature and requires that we maintain-binary compatibility. This library hides most of that unsafety, but-still requires that you follow the rules above.--Please take the last rule seriously and never ever use this library in-production! If something goes wrong during a reload, we do not get a-convenient run-time exception; we get a memory violation, which can-cause anything from a segfault to a remotely exploitable security hole.+library is itself unsafe by nature, requiring us to maintain binary+compatibility. This library hides most of that unsafety, but still+requires you to follow the rules listed above. -}
rapid.cabal view
@@ -1,5 +1,5 @@ name: rapid-version: 0.1.5+version: 0.1.5.1 category: Development synopsis: Hot reload and reload-surviving values with GHCi maintainer: Markus Läll <markus.l2ll@gmail.com>@@ -10,20 +10,28 @@ license: BSD3 license-file: LICENSE -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: 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>.+description: This package provides a rapid prototyping suite for+ GHCi:++ .++ - Reload individual components of your application as+ you iterate: improves development experience for+ long-running applications such as (web) servers or+ user interfaces by keeping the app running in the+ background and allowing reloading it after code+ changes.++ .++ - Reuse expensive resources across reloads: useful in+ batch-style programs to compute/aquire a resource+ once, then reuse it across code reloads.++ .++ 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