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




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.


Heist State Definitions

data MonadSnap m => HeistState m Source

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.

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

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.



:: 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 MonadHeist Interface

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

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


render :: ByteString -> m ()Source

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

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

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 aSource

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 ()Source

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

heistServeSingle :: ByteString -> m ()Source

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

Convenience Functions



:: (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) ]