snap-0.5.2: Snap: A Haskell Web Framework: project starter executable and glue code library

Snap.Extension.Heist.Impl

Contents

- Heist State Definitions
- The MonadHeist Interface
- Convenience Functions

Description

`Snap.Extension.Heist.Impl` is an implementation of the `MonadHeist` interface defined in `Snap.Extension.Heist`.

As always, to use, add `HeistState` to your application's state, along with an instance of `HasHeistState` for your application's state, making sure to use a `heistInitializer` in your application's `Initializer`, and then you're ready to go.

`Snap.Extension.Heist.Impl` is a little different to other Snap Extensions, which is unfortunate as it is probably the most widely useful one. As explained below, `HeistState` takes your application's monad as a type argument, and `HasHeistState` is a multi-parameter type class, the additional first parameter also being your application's monad.

Two instances of `MonadHeist` are provided with this module. One is designed for users wanting to use Heist templates with their application, the other is designed for users writing Snap Extensions which use their own Heist templates internally.

The first one of these instances is `HasHeistState (SnapExtend s) s => MonadHeist (SnapExtend s) (SnapExtend s)`. This means that any type `s` which has a `HeistState`, whose 'TemplateState'\'s monad is `SnapExtend s` forms a `MonadHeist` whose 'TemplateState'\'s monad is `SnapExtend s` and whose monad itself is `SnapExtend s`. The `s` here is your application's state, and `SnapExtend s` is your application's monad.

The second one of these instances is `HasHeistState m s => MonadHeist m (ReaderT s m)`. This means that any type `s` which has, for any m, a `HeistState m`, forms a `MonadHeist`, whose 'TemplateState'\'s monad is `m`, when made the environment of a `ReaderT` wrapped around `m`. The `s` here would be the Snap Extension's internal state, and the `m` would be `SnapExtend` wrapped around any `s'` which was an instance of the Snap Extension's `HasState` class.

This implementation does not require that your application's monad implement interfaces from any other Snap Extension.

Synopsis

- data MonadSnap m => HeistState m
- class MonadSnap m => HasHeistState m s | s -> m where
  - getHeistState :: s -> HeistState m
  - setHeistState :: HeistState m -> s -> s
  - modifyHeistState :: (HeistState m -> HeistState m) -> s -> s
- heistInitializer :: MonadSnap m => FilePath -> (TemplateState m -> TemplateState m) -> Initializer (HeistState m)
- class (Monad n, MonadSnap m) => MonadHeist n m | m -> n where
  - render :: ByteString -> m ()
  - renderAs :: ByteString -> ByteString -> m ()
  - heistLocal :: (TemplateState n -> TemplateState n) -> m a -> m a
  - heistServe :: m ()
  - heistServeSingle :: ByteString -> m ()
- registerSplices :: (MonadSnap m, MonadIO n) => HeistState m -> [(Text, Splice m)] -> n ()

# Heist State Definitions

data MonadSnap m => HeistState m

Your application's state must include a `HeistState` in order for your application to be a `MonadHeist`.

Unlike other `-State` types, this is of kind `(* -> *) -> *`. Unless you're developing your own Snap Extension which has its own internal `HeistState`, the type argument you want to pass to `HeistState` is your application's monad, which should be `SnapExtend` wrapped around your application's state.

Instances

MonadSnap m => InitializerState (HeistState m) |

class MonadSnap m => HasHeistState m s | s -> m where

For your application's monad to be a `MonadHeist`, your application's state needs to be an instance of `HasHeistState`. Minimal complete definition: `getHeistState`, `setHeistState`.

Unlike other `HasState` type classes, this is a type class has two parameters. Among other things, this means that you will need to enable the `FlexibleInstances` and `MultiParameterTypeClasses` language extensions to be able to create an instance of `HasHeistState`. In most cases, the last parameter will as usual be your application's state, and the additional first one will be the monad formed by wrapping `SnapExtend` around your application's state.

However, if you are developing your own Snap Extension which uses its own internal `HeistState`, the last parameter will be your Snap Extension's internal state, and the additional first parameter will be any monad formed by wrapping `SnapExtend` around a type which has an instance of the `HasState` class for your monad. These two use cases are subtly different, which is why `HasHeistState` needs two type parameters.

Methods

getHeistState :: s -> HeistState m

setHeistState :: HeistState m -> s -> s

modifyHeistState :: (HeistState m -> HeistState m) -> s -> s

heistInitializer

Arguments

:: MonadSnap m |
=> FilePath | Path to a template directory containing `.tpl` files
-> (TemplateState m -> TemplateState m) | Function to modify the initial template state
-> Initializer (HeistState m) |

The `Initializer` for `HeistState`.

# The MonadHeist Interface

class (Monad n, MonadSnap m) => MonadHeist n m | m -> n where

The `MonadHeist` type class. Minimal complete definition: `render`, `heistLocal`.

Methods

render :: ByteString -> m ()

Renders a template as text/html. If the given template is not found, this returns `empty`.

renderAs :: ByteString -> ByteString -> m ()

Renders a template as the given content type. If the given template is not found, this returns `empty`.

heistLocal :: (TemplateState n -> TemplateState n) -> m a -> m a

Runs an action with a modified `TemplateState`. You might want to use this if you had a set of splices which were customised for a specific action. To do that you would do:

     heistLocal (bindSplices mySplices) $ render "myTemplate"

heistServe :: m ()

Analogous to `fileServe`. If the template specified in the request path is not found, it returns `empty`.

heistServeSingle :: ByteString -> m ()

Analogous to `fileServeSingle`. If the given template is not found, this throws an error.

Instances

HasHeistState m s => MonadHeist m (ReaderT s m) |
HasHeistState (SnapExtend s) s => MonadHeist (SnapExtend s) (SnapExtend s) |

# Convenience Functions

registerSplices

Arguments

:: (MonadSnap m, MonadIO n) |
=> HeistState m | Heist state that you are going to embed in your application's state.
-> [(Text, Splice m)] | Your splices.
-> n () |

Take your application's state and register these splices in it so that you don't have to re-list them in every handler. Should be called from inside your application's `Initializer`. The splices registered by this function do not persist through template reloads. Those splices must be passed as a parameter to heistInitializer.

(NOTE: In the future we may decide to deprecate registerSplices in favor of the heistInitializer argument.)

Typical use cases are dynamically generated components that are present in many of your views.

Example Usage:

     appInit :: Initializer AppState
     appInit = do
      hs <- heistInitializer "templates"
      registerSplices hs $
       [ ("tabs", tabsSplice)
       , ("loginLogout", loginLogoutSplice) ]