Source

pico-org / picostache.l

Full commit
# picostache.l Tiny mustache template implementation
# (c) 2012 Joe Bogner 
# https://bitbucket.org/joebo/picostache/

(default *DELIM_S (chop "{{") *DELIM_E (chop "}}"))

(de lookup (Key Model)
	(cdr (assoc Key Model)))

(de context (View Key)
    (setq Func (lookup Key Model))
    (if (pair (fun? Func))
        (Func View)
        (if (= Key ".")
            View
            (lookup Key View) ) ) )

(de section (View Key Rest Inverted)
    (setq Func (lookup Key Model))
    (if (pair (fun? Func))
        (link (Func (pack (make (render View Rest)))))
        (setq Subview (context View Key))
        (ifn Inverted 
            (for X Subview (render X Rest))
            (if (not Subview) (render X Rest) ))))

(de render (View Tree)
    (for X Tree 
        (case (car X) 
            (Name (link (context View (cadr X))))
            (Text (link (cdr X)))
            (Section (section View (cadr X) (cddr X)))
            (NonSection (section View (cadr X) (cddr X) T)))
        (if (pair (cadr X)) (render View (cdr X))) ) ) 

(de renderTree (View Tree)
    (pack (make (render View Tree))) )

(de renderHtml (View Html)
    (renderTree View (parse Html)) )

(de headUntil (Lst Delim)
   (make  
        (let DelimLen (length Delim)
            (for (C Lst C (cdr C))
                (ifn (= Delim (head DelimLen C))
                    (link (car C))
                    (setq C NIL) ) ) ) ) )  

(de addCell (Type Cell Force)
    (when (or Force (<> CurType Type)) 
        (if CurType (queue RootPtr (list CurType (pack (reverse Cur)))))
        (when (or (= CurType "Section") (= CurType "NonSection")) 
						(push 'Levels (last (car RootPtr)))
            (setq RootPtr (list (last (car RootPtr)))))
        (setq CurType Type)
        (setq Cur NIL) )
    (push 'Cur Cell))  

(de parse (Html)
    (setq Root (list))
    (setq RootPtr Root)
    (setq Cur NIL)
		(setq Levels NIL)
    (for (C (chop Html) C (cdr C))
        (ifn (= *DELIM_S (head 2 C))
            (addCell 'Text (car C))
            (let (TokenStart (nth C 3) Token (headUntil TokenStart *DELIM_E))
                (case (car Token)
                    ("#" (addCell 'Section (cdr Token) T)) 
                    ("~" (addCell 'NonSection (cdr Token) T)) 
                    ("/" (addCell NIL (cdr Token) T ) (pop 'Levels) (setq RootPtr Levels))
                    (T (addCell 'Name Token T)) )
                (setq C (nth C (+ (length *DELIM_S) (length Token) (length *DELIM_E))))) ) ) 
    (addCell NIL NIL T)
    (car Root) )

(de testParse ()
    (setq Html "hello {{name}}{{#names}}^J- {{.}}{{/#names}}")
    (setq Template (parse Html))
    (setq Expected '((Text "hello ") (Name "name") (Section "names" (Text "^J- ") (Name "."))))
    (test Expected Template)
    (push 'Model (cons "name" "joe"))
    (setq Names '(names . ("joe" "bob" "frank")))
    (push 'Model Names)
    (test "hello joe^J- joe^J- bob^J- frank" (renderTree Model Template)) 
    (test "sleep,eat," (renderHtml '((todos ((todo . "sleep")) ((todo . "eat")))) "{{#todos}}{{todo}},{{/todos}}"))
)

(de testRender ()
    (setq Tree (quote 
        (Text "hello ") 
        (Name "name") 
        (Text "^J") 
        (NonSection "missing" (Text "nothing here^J")) 
        (Section "names" (Text " - ") (Section "Upper" (Name ".")) (Text "^J"))))
    (push 'Model (cons "name" "joe"))
    (setq Names '(names . ("joe" "bob" "frank")))
    (push 'Model Names)
    (push 'Model (cons "Upper" '((X) (uppc X))))
    (test "hello joe^Jnothing here^J - JOE^J - BOB^J - FRANK^J" (renderTree Model Tree)) 
) 


# (testRender)
# (testParse)