Hastache
Haskell implementation of Mustache templates
Installation
cabal update
cabal install hastache
Usage
Read Mustache documentation for template syntax.
Examples
Variables
import Text.Hastache
import Text.Hastache.Context
import qualified Data.ByteString.Lazy as LZ
main = hastacheStr defaultConfig (encodeStr template) (mkStrContext context)
>>= LZ.putStrLn
template = "Hello, {{name}}!\n\nYou have {{unread}} unread messages."
context "name" = MuVariable "Haskell"
context "unread" = MuVariable (100 :: Int)
Hello, Haskell!
You have 100 unread messages.
With Generics
{-# LANGUAGE DeriveDataTypeable #-}
import Text.Hastache
import Text.Hastache.Context
import qualified Data.ByteString.Lazy as LZ
import Data.Data
import Data.Generics
main = hastacheStr defaultConfig (encodeStr template) context
>>= LZ.putStrLn
data Info = Info {
name :: String,
unread :: Int
} deriving (Data, Typeable)
template = "Hello, {{name}}!\n\nYou have {{unread}} unread messages."
context = mkGenericContext $ Info "Haskell" 100
Lists
template = concat [
"{{#heroes}}\n",
"* {{name}} \n",
"{{/heroes}}\n"]
context "heroes" = MuList $ map (mkStrContext . mkListContext)
["Nameless","Long Sky","Flying Snow","Broken Sword","Qin Shi Huang"]
where
mkListContext name = \"name" -> MuVariable name
* Nameless
* Long Sky
* Flying Snow
* Broken Sword
* Qin Shi Huang
With Generics
data Hero = Hero { name :: String } deriving (Data, Typeable)
data Heroes = Heroes { heroes :: [Hero] } deriving (Data, Typeable)
template = concat [
"{{#heroes}}\n",
"* {{name}} \n",
"{{/heroes}}\n"]
context = mkGenericContext $ Heroes $ map Hero ["Nameless","Long Sky",
"Flying Snow","Broken Sword","Qin Shi Huang"]
Another Generics version
data Heroes = Heroes { heroes :: [String] } deriving (Data, Typeable)
template = concat [
"{{#heroes}}\n",
"* {{.}} \n",
"{{/heroes}}\n"]
context = mkGenericContext $ Heroes ["Nameless","Long Sky","Flying Snow",
"Broken Sword","Qin Shi Huang"]
Functions
template = "Hello, {{#reverse}}world{{/reverse}}!"
context "reverse" = MuLambda (reverse . decodeStr)
Hello, dlrow!
Monadic functions
{-# LANGUAGE FlexibleContexts #-}
import Text.Hastache
import Text.Hastache.Context
import qualified Data.ByteString.Lazy as LZ
import Control.Monad.State
main = run >>= LZ.putStrLn
run = evalStateT stateFunc ""
stateFunc :: StateT String IO LZ.ByteString
stateFunc =
hastacheStr defaultConfig (encodeStr template) (mkStrContext context)
template = "{{#arg}}aaa{{/arg}} {{#arg}}bbb{{/arg}} {{#arg}}ccc{{/arg}}"
context "arg" = MuLambdaM $ arg . decodeStr
arg :: MonadState String m => String -> m String
arg a = do
v <- get
let nv = v ++ a
put nv
return nv
aaa aaabbb aaabbbccc
Generics big example
data Book = Book {
title :: String,
publicationYear :: Integer
} deriving (Data, Typeable)
data Life = Life {
born :: Integer,
died :: Integer
} deriving (Data, Typeable)
data Writer = Writer {
name :: String,
life :: Life,
books :: [Book]
} deriving (Data, Typeable)
template = concat [
"Name: {{name}} ({{life.born}} - {{life.died}})\n",
"{{#life}}\n",
"Born: {{born}}\n",
"Died: {{died}}\n",
"{{/life}}\n",
"Bibliography:\n",
"{{#books}}\n",
" {{title}} ({{publicationYear}})\n",
"{{/books}}\n"
]
context = mkGenericContext Writer {
name = "Mikhail Bulgakov",
life = Life 1891 1940,
books = [
Book "Heart of a Dog" 1987,
Book "Notes of a country doctor" 1926,
Book "The Master and Margarita" 1967]
}
Name: Mikhail Bulgakov (1891 - 1940)
Born: 1891
Died: 1940
Bibliography:
Heart of a Dog (1987)
Notes of a country doctor (1926)
The Master and Margarita (1967)
More examples