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.
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.
getHeistState :: s -> HeistState mSource
setHeistState :: HeistState m -> s -> sSource
modifyHeistState :: (HeistState m -> HeistState m) -> s -> sSource
:: 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
.
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.
HasHeistState m s => MonadHeist m (ReaderT s m) | |
HasHeistState (SnapExtend s) s => MonadHeist (SnapExtend s) (SnapExtend s) |
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) ]