on master help sign in
Added support for "$if$" statement in templates.
f86b9c5Ivan N. Veselov
src/Hakyll/Web/Template.hs+14−7
@@ -44,7 +44,8 @@ module Hakyll.Web.Template
44
44
45
45
46--------------------------------------------------------------------------------
46--------------------------------------------------------------------------------
47−import Control.Monad (forM, liftM)
47+import Control.Monad (liftM)
48+import Control.Monad.Error (MonadError(..))
48import Data.Monoid (mappend)
49import Data.Monoid (mappend)
49import Prelude hiding (id)
50import Prelude hiding (id)
50
51
@@ -112,11 +113,17 @@ applyAsTemplate context item =
112
113
113--------------------------------------------------------------------------------
114--------------------------------------------------------------------------------
114-- | Overloaded apply template function to work in an arbitrary Monad.
115-- | Overloaded apply template function to work in an arbitrary Monad.
115−applyTemplateWith :: Monad m
116+applyTemplateWith :: MonadError e m
116 => (String -> a -> m String)
117 => (String -> a -> m String)
117 -> Template -> a -> m String
118 -> Template -> a -> m String
118−applyTemplateWith context tpl x = liftM concat $
119+applyTemplateWith context tpl x = go tpl where
119− forM (unTemplate tpl) $ \e -> case e of
120+
121+ go = liftM concat . mapM applyElem . unTemplate
122+
120− Chunk c -> return c
123+ applyElem (Chunk c) = return c
121− Escaped -> return "$"
124+ applyElem Escaped = return "$"
122− Key k -> context k x
125+ applyElem (Key k) = context k x
126+ applyElem (If k t mf) = (context k x >> go t) `catchError` handler where
127+ handler _ = case mf of
128+ Nothing -> return ""
129+ Just f -> go f
src/Hakyll/Web/Template/Internal.hs+7−5
@@ -9,7 +9,7 @@ module Hakyll.Web.Template.Internal
9
9
10
10
11--------------------------------------------------------------------------------
11--------------------------------------------------------------------------------
12−import Control.Applicative ((<$>))
12+import Control.Applicative (pure, (<$>), (<*>))
13import Data.Binary (Binary, get, getWord8, put, putWord8)
13import Data.Binary (Binary, get, getWord8, put, putWord8)
14import Data.Typeable (Typeable)
14import Data.Typeable (Typeable)
15
15
@@ -38,18 +38,20 @@ data TemplateElement
38 = Chunk String
38 = Chunk String
39 | Key String
39 | Key String
40 | Escaped
40 | Escaped
41+ | If String Template (Maybe Template) -- key, then branch, else branch
41 deriving (Show, Eq, Typeable)
42 deriving (Show, Eq, Typeable)
42
43
43−
44--------------------------------------------------------------------------------
44--------------------------------------------------------------------------------
45instance Binary TemplateElement where
45instance Binary TemplateElement where
46− put (Chunk string) = putWord8 0 >> put string
46+ put (Chunk string) = putWord8 0 >> put string
47− put (Key key) = putWord8 1 >> put key
47+ put (Key key) = putWord8 1 >> put key
48 put (Escaped) = putWord8 2
48 put (Escaped) = putWord8 2
49+ put (If key t f) = putWord8 3 >> put key >> put t >> put f
49
50
50 get = getWord8 >>= \tag -> case tag of
51 get = getWord8 >>= \tag -> case tag of
51 0 -> Chunk <$> get
52 0 -> Chunk <$> get
52 1 -> Key <$> get
53 1 -> Key <$> get
53− 2 -> return Escaped
54+ 2 -> pure Escaped
55+ 3 -> If <$> get <*> get <*> get
54 _ -> error $ "Hakyll.Web.Template.Internal: "
56 _ -> error $ "Hakyll.Web.Template.Internal: "
55 ++ "Error reading cached template"
57 ++ "Error reading cached template"
src/Hakyll/Web/Template/Read.hs+46−28
@@ -4,38 +4,56 @@ module Hakyll.Web.Template.Read
4 ( readTemplate
4 ( readTemplate
5 ) where
5 ) where
6
6
7−
8--------------------------------------------------------------------------------
7--------------------------------------------------------------------------------
9−import Data.List (isPrefixOf)
8+import Control.Applicative ((<$>), (<$), (<*>))
10−
9+import Control.Monad (void, mzero, guard)
10+import Text.Parsec
11+import Text.Parsec.String
11
12
12--------------------------------------------------------------------------------
13--------------------------------------------------------------------------------
13import Hakyll.Web.Template.Internal
14import Hakyll.Web.Template.Internal
14
15
15−
16--------------------------------------------------------------------------------
16--------------------------------------------------------------------------------
17−-- | Construct a @Template@ from a string.
17+
18readTemplate :: String -> Template
18readTemplate :: String -> Template
19−readTemplate = Template . readTemplate'
19+readTemplate input =
20− where
20+ case parse template "" input of
21− readTemplate' [] = []
21+ Left err -> error $ "Cannot parse template: " ++ show err
22− readTemplate' string
22+ Right t -> t
23− | "$$" `isPrefixOf` string =
23+
24− Escaped : readTemplate' (drop 2 string)
24+template :: Parser Template
25− | "$" `isPrefixOf` string =
25+template = Template <$>
26− case readKey (drop 1 string) of
26+ (many1 $ chunk <|> escaped <|> conditional <|> key)
27− Just (key, rest) -> Key key : readTemplate' rest
27+
28− Nothing -> Chunk "$" : readTemplate' (drop 1 string)
28+chunk :: Parser TemplateElement
29− | otherwise =
29+chunk = Chunk <$> (many1 $ noneOf "$")
30− let (chunk, rest) = break (== '$') string
30+
31− in Chunk chunk : readTemplate' rest
31+escaped :: Parser TemplateElement
32−
32+escaped = Escaped <$ (try $ string "$$")
33− -- Parse an key into (key, rest) if it's valid, and return
33+
34− -- Nothing otherwise
34+conditional :: Parser TemplateElement
35− readKey string =
35+conditional = try $ do
36− let (key, rest) = span validKeyChar string
36+ void $ string "$if("
37− in if not (null key) && "$" `isPrefixOf` rest
37+ i <- ident
38− then Just (key, drop 1 rest)
38+ void $ string ")$"
39− else Nothing
39+ thenBranch <- template
40−
40+ elseBranch <- optionMaybe $ try (string "$else$") >> template
41− validKeyChar x = x `notElem` ['$', '\n', '\r']
41+ void $ string "$endif$"
42+ return $ If i thenBranch elseBranch
43+
44+ident :: Parser String
45+ident = do
46+ i <- (:) <$> letter <*> (many $ alphaNum <|> oneOf " _-.")
47+ if i `elem` reserved
48+ then mzero
49+ else return i
50+
51+reserved :: [String]
52+reserved = ["if", "else","endif"]
53+
54+key :: Parser TemplateElement
55+key = try $ do
56+ void $ char '$'
57+ k <- ident
58+ void $ char '$'
59+ return $ Key k
tests/data/template.html+1−1
@@ -1,5 +1,5 @@
1<div>
1<div>
2 I'm so rich I have $$3.
2 I'm so rich I have $$3.
3− $echo test!$
3+ $echo test$
4 $body$
4 $body$
5</div>
5</div>
tests/data/template.html.out+1−1
@@ -1,5 +1,5 @@
1<div>
1<div>
2 I'm so rich I have $3.
2 I'm so rich I have $3.
3− test!
3+ test
4 <p>This is an example.</p>
4 <p>This is an example.</p>
5</div>
5</div>