Snap.Extension.Heist.Impl
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.
- 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 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.
Instances
| MonadSnap m => InitializerState (HeistState m) |
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.
Methods
getHeistState :: s -> HeistState mSource
setHeistState :: HeistState m -> s -> sSource
modifyHeistState :: (HeistState m -> HeistState m) -> s -> sSource
Arguments
| :: MonadSnap m | |
| => FilePath | Path to a template directory containing |
| -> (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 whereSource
The MonadHeist type class. Minimal complete definition: render,
heistLocal.
Methods
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.
Instances
| HasHeistState m s => MonadHeist m (ReaderT s m) | |
| HasHeistState (SnapExtend s) s => MonadHeist (SnapExtend s) (SnapExtend s) |
Convenience Functions
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) ]