]>
Commit | Line | Data |
---|---|---|
675085c2 JG |
1 | # blazeT [![Build Status](https://travis-ci.org/johannesgerer/blazeT.svg?branch=master)](https://travis-ci.org/johannesgerer/blazeT) [![Hackage](https://img.shields.io/hackage/v/blazeT.svg)](https://hackage.haskell.org/package/blazeT) |
2 | ||
3 | A true monad (transformer) version of the | |
4 | [blaze-markup](https://hackage.haskell.org/package/blaze-markup) and | |
5 | [blaze-html](https://hackage.haskell.org/package/blaze-html) | |
6 | libraries. | |
7 | ||
8 | # Why? | |
9 | ||
10 | While blaze's `Markup` and `Html` types have `Monad` instances and can | |
11 | leverage the the concise `do` notation, they do not satisfy | |
12 | the | |
13 | [Monad Laws](https://hackage.haskell.org/package/base-4.8.0.0/docs/Control-Monad.html#t:Monad) and | |
14 | thus cannot be used as Monads, let alone Monad transformers. | |
15 | ||
16 | ## Use Cases | |
17 | ||
18 | The `MarkupT` Monad Transformer enables us to write Markup (e.g. HTML) | |
19 | templates that have access to all those Monads you cannot live without | |
20 | anymore. | |
21 | ||
22 | Accessing an environment | |
23 | ([MonadReader](https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Reader-Class.html)), | |
24 | accumulating log or other diagnostic output | |
25 | ([MonadWriter](https://hackage.haskell.org/package/mtl-2.2.1/docs/Control-Monad-Writer-Class.html)), | |
26 | doing `IO` (like database access) are the first things that come to | |
27 | mind. | |
28 | ||
95eb4d6a | 29 | The reason of existence of this library is its use |
675085c2 JG |
30 | in [Lykah](http://johannesgerer.com/Lykah), which powers my personal |
31 | website | |
32 | [http://johannesgerer.com](http://johannesgerer.com/johannesgerer.com). In | |
33 | Lykah, the HTML templates have access to the whole site structure (to | |
95eb4d6a JG |
34 | build things like menus or blog post lists) and automatically check, |
35 | insert and keep track of referenced pages and assets, which turns out | |
36 | to be very useful functionality of a static website generator. | |
675085c2 JG |
37 | |
38 | # How to use it? | |
39 | ||
40 | ## Backwards compatible | |
41 | ||
42 | The library is intended to serve as a drop-in replacement for the | |
43 | `blaze-markup` and `blaze-html` libraries and should be backwards | |
44 | compatible: | |
45 | ||
46 | Simply replace your `module Text.Blaze.*` imports with `module | |
47 | Text.BlazeT.*` and it should give the same results. | |
48 | ||
49 | For usage of blaze check out | |
50 | their [documentation](https://jaspervdj.be/blaze/). | |
51 | ||
52 | ## Unleash the monads | |
53 | ||
95eb4d6a JG |
54 | [Text.BlazeT](https://hackage.haskell.org/package/blazeT/docs/Text-BlazeT.html) |
55 | exports `runWith` and `execWith`, which work on any | |
56 | `Text.BlazeT.Renderer.*`. The rendered markup will be returned within | |
57 | the base monad, whose actions can be | |
58 | [`lift`ed](https://hackage.haskell.org/package/transformers-0.5.2.0/docs/Control-Monad-Trans-Class.html) | |
59 | into the Markup, as shown in the following example (from | |
60 | [here](src/Readme.hs)): | |
675085c2 | 61 | |
95eb4d6a JG |
62 | ```Haskell |
63 | {-# LANGUAGE OverloadedStrings #-} | |
64 | ||
65 | import Data.Time (getCurrentTime) | |
66 | import Text.BlazeT.Html5 hiding (main) | |
67 | import Text.BlazeT.Renderer.String | |
68 | import Control.Monad.Trans.Class (lift) | |
69 | ||
70 | -- Backwords compatible Blaze HTML | |
71 | old :: Markup | |
72 | old = do | |
73 | p $ "created with blaze-html" | |
74 | ||
75 | -- BlazeT HTML with lifted IO actions | |
76 | new :: MarkupT IO () | |
77 | new = do | |
78 | time <- lift getCurrentTime | |
79 | p $ string $ "created with blazeT at " ++ show time | |
80 | ||
81 | main :: IO () | |
82 | main = do | |
83 | putStrLn $ renderMarkup old | |
84 | putStrLn =<< execWith renderMarkup new | |
85 | ||
86 | ``` | |
87 | ||
88 | prints: | |
89 | ||
90 | ```HTML | |
91 | <p>created with blaze-html</p> | |
92 | <p>created with blazeT at 2016-10-26 01:09:16.969147361 UTC</p> | |
93 | ``` | |
94 | ||
95 | # Installation | |
96 | ||
97 | 1. To make it available on your system (or sandbox) use `cabal install blazeT`. | |
98 | ||
99 | 2. To play around with the source, obtain by cloning this repo or use | |
100 | `cabal get blazet`, enter the directory and run: | |
101 | ||
102 | ```bash | |
103 | cabal sandbox init #optional | |
104 | cabal install | |
105 | ``` | |
106 | ||
107 | # Documentation on [Hackage](https://hackage.haskell.org/package/blazeT) | |
675085c2 JG |
108 | |
109 | # Implementation | |
110 | ||
95eb4d6a | 111 | ... is contained |
675085c2 JG |
112 | in |
113 | [Text.BlazeT.Internals](https://hackage.haskell.org/package/blazeT/docs/Text-BlazeT-Internals.html). | |
114 | ||
95eb4d6a JG |
115 | Everything is build around the simple `newtype` definition of the |
116 | `MarkupT` transformer, which makes use | |
117 | the | |
118 | [Monoid](https://hackage.haskell.org/package/base-4.7.0.2/docs/Data-Monoid.html) instance | |
119 | of `Blaze.Markup` and is basically a `WriterT` writing `Blaze.Markup`: | |
675085c2 JG |
120 | |
121 | ```Haskell | |
122 | newtype MarkupT m a = MarkupT { fromMarkupT :: WriterT B.Markup m a } | |
123 | ``` | |
124 | ||
95eb4d6a JG |
125 | The old `Text.Blaze.Markup` type is replaced by a rank-2 version of |
126 | the transformer: | |
127 | ||
128 | ```Haskell | |
129 | type Markup = forall m . Monad m => MarkupT m () | |
130 | ``` | |
131 | ||
675085c2 | 132 | Wrappers used to lift all `Blaze` entities into `BlazeT` are trivially |
95eb4d6a JG |
133 | expressible using basic `WriterT` class methods. Wrapping |
134 | `Blaze.Markup` is simply `WriterT.tell`: | |
675085c2 JG |
135 | |
136 | ```Haskell | |
137 | wrapMarkupT :: Monad m => B.Markup -> MarkupT m () | |
138 | wrapMarkupT = tell | |
139 | ``` | |
140 | Wrapping functions that modify `Blaze.Markup` is simply `WriterT.censor`: | |
141 | ||
142 | ```Haskell | |
143 | wrapMarkupT2 :: Monad m => (B.Markup -> B.Markup) -> MarkupT m a -> MarkupT m a | |
144 | wrapMarkupT2 = censor | |
145 | ``` | |
146 |