198 lines
6 KiB
Haskell
198 lines
6 KiB
Haskell
{-|
|
|
Module : $Header$
|
|
Description : Basic functions for dealing with mustache templates.
|
|
Copyright : (c) Justus Adam, 2015
|
|
License : BSD3
|
|
Maintainer : dev@justus.science
|
|
Stability : experimental
|
|
Portability : POSIX
|
|
|
|
= How to use this library
|
|
|
|
This module exposes some of the most convenient functions for dealing with mustache
|
|
templates.
|
|
|
|
== Compiling with automatic partial discovery
|
|
|
|
The easiest way of compiling a file and its potential includes (called partials)
|
|
is by using the 'automaticCompile' function.
|
|
|
|
@
|
|
main :: IO ()
|
|
main = do
|
|
let searchSpace = [".", "./templates"]
|
|
templateName = "main.mustache"
|
|
|
|
compiled <- automaticCompile searchSpace templateName
|
|
case compiled of
|
|
Left err -> print err
|
|
Right template -> return () -- this is where you can start using it
|
|
@
|
|
|
|
The @searchSpace@ encompasses all directories in which the compiler should
|
|
search for the template source files.
|
|
The search itself is conducted in order, from left to right.
|
|
|
|
Should your search space be only the current working directory, you can use
|
|
'localAutomaticCompile'.
|
|
|
|
The @templateName@ is the relative path of the template to any directory
|
|
of the search space.
|
|
|
|
'automaticCompile' not only finds and compiles the template for you, it also
|
|
recursively finds any partials included in the template as well,
|
|
compiles them and stores them in the 'partials' hash attached to the resulting
|
|
template.
|
|
|
|
The compiler will throw errors if either the template is malformed
|
|
or the source file for a partial or the template itself could not be found
|
|
in any of the directories in @searchSpace@.
|
|
|
|
== Substituting
|
|
|
|
In order to substitute data into the template it must be an instance of the 'ToMustache'
|
|
typeclass or be of type 'Value'.
|
|
|
|
This libray tries to imitate the API of <https://hackage.haskell.org/package/aeson aeson>
|
|
by allowing you to define conversions of your own custom data types into 'Value',
|
|
the type used internally by the substitutor via typeclass and a selection of
|
|
operators and convenience functions.
|
|
|
|
=== Example
|
|
|
|
@
|
|
data Person = { age :: Int, name :: String }
|
|
|
|
instance ToMustache Person where
|
|
toMustache person = object
|
|
[ "age" ~> age person
|
|
, "name" ~> name person
|
|
]
|
|
@
|
|
|
|
The values to the left of the '~>' operator has to be of type 'Text', hence the
|
|
@OverloadedStrings@ can becomes very handy here.
|
|
|
|
Values to the right of the '~>' operator must be an instance of the 'ToMustache'
|
|
typeclass. Alternatively, if your value to the right of the '~>' operator is
|
|
not an instance of 'ToMustache' but an instance of 'ToJSON' you can use the
|
|
'~=' operator, which accepts 'ToJSON' values.
|
|
|
|
@
|
|
data Person = { age :: Int, name :: String, address :: Address }
|
|
|
|
data Address = ...
|
|
|
|
instance ToJSON Address where
|
|
...
|
|
|
|
instance ToMustache Person where
|
|
toMustache person = object
|
|
[ "age" ~> age person
|
|
, "name" ~> name person
|
|
, "address" ~= address person
|
|
]
|
|
@
|
|
|
|
All operators are also provided in a unicode form, for those that, like me, enjoy
|
|
unicode operators.
|
|
|
|
== Manual compiling
|
|
|
|
You can compile templates manually without requiring the IO monad at all, using
|
|
the 'compileTemplate' function. This is the same function internally used by
|
|
'automaticCompile' and does not check if required partial are present.
|
|
|
|
More functions for manual compilation can be found in the 'Text.Mustache.Compile'
|
|
module. Including helpers for finding lists of partials in templates.
|
|
|
|
Additionally the 'compileTemplateWithCache' function is exposed here which you
|
|
may use to automatically compile a template but avoid some of the compilation
|
|
overhead by providing already compiled partials as well.
|
|
|
|
== Fundamentals
|
|
|
|
This library builds on three important data structures/types.
|
|
|
|
['Value'] A data structure almost identical to Data.Aeson.Value extended with
|
|
lambda functions which represents the data the template is being filled with.
|
|
|
|
['ToMustache'] A typeclass for converting arbitrary types to 'Value', similar
|
|
to Data.Aeson.ToJSON but with support for lambdas.
|
|
|
|
['Template'] Contains the 'STree', the syntax tree, which is basically a
|
|
list of text blocks and mustache tags. The 'name' of the template and its
|
|
'partials' cache.
|
|
|
|
=== Compiling
|
|
|
|
During the compilation step the template file is located, read, then parsed in a single
|
|
pass ('compileTemplate'), resulting in a 'Template' with an empty 'partials' section.
|
|
|
|
Subsequenty the 'STree' of the template is scanned for included partials, any
|
|
present 'TemplateCache' is queried for the partial ('compileTemplateWithCache'),
|
|
if not found it will be searched for in the @searchSpace@, compiled and
|
|
inserted into the template's own cache as well as the global cache for the
|
|
compilation process.
|
|
|
|
Internally no partial is compiled twice, as long as the names stay consistent.
|
|
|
|
Once compiled templates may be used multiple times for substitution or as
|
|
partial for other templates.
|
|
|
|
Partials are not being embedded into the templates during compilation, but during
|
|
substitution, hence the 'partials' cache is vital to the template even after
|
|
compilation has been completed. Any non existent partial in the cache will
|
|
rsubstitute to an empty string.
|
|
|
|
=== Substituting
|
|
|
|
|
|
|
|
-}
|
|
{-# LANGUAGE LambdaCase #-}
|
|
module Text.Mustache
|
|
(
|
|
-- * Compiling
|
|
|
|
-- ** Automatic
|
|
automaticCompile, localAutomaticCompile
|
|
|
|
-- ** Manually
|
|
, compileTemplateWithCache, compileTemplate, Template(..)
|
|
|
|
-- * Rendering
|
|
|
|
-- ** Generic
|
|
|
|
, substitute, checkedSubstitute
|
|
|
|
-- ** Specialized
|
|
|
|
, substituteValue, checkedSubstituteValue
|
|
|
|
-- ** In Lambdas
|
|
|
|
, substituteNode, substituteAST, catchSubstitute
|
|
|
|
-- * Data Conversion
|
|
, ToMustache, toMustache, integralToMustache, object, (~>), (~=)
|
|
|
|
-- ** Utilities for lambdas
|
|
|
|
, overText
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Text.Mustache.Compile
|
|
import Text.Mustache.Render
|
|
import Text.Mustache.Types
|
|
import qualified Data.Text as T
|
|
|
|
|
|
-- | Creates a 'Lambda' which first renders the contained section and then applies the supplied function
|
|
overText :: (T.Text -> T.Text) -> Value
|
|
overText f = toMustache $ fmap (f . snd) . catchSubstitute . substituteAST
|