Pretty good template function

Started by Jeff, April 10, 2007, 05:16:28 PM

Previous topic - Next topic

Jeff

It's a first draft, and I'd appreciate any ideas to tighten the code, but here it is:


(context 'TEMPLATE)

(define (render template ctx)
  (set 'ctx (eval ctx))
  (context ctx)
  (set 'expanded-template "")
  (set 'blocks (parse template "{|}" 4))
  (dolist (block blocks)
    (if (not (regex "% .+? %" block 0))
      (push (format "(print [text]%s[/text])" (replace "%" block "" 0))
            expanded-template -1)
      (push (replace "s*%s*" block "" 0) expanded-template -1)))
  (eval-string expanded-template)
  (exit))

(context MAIN)


It reads in the string 'template (which you would most likely get from a template file) and interprets lisp code between {% (do something...) %} tags.  It is important to have a space between the tag borders and the command, and also it is important to keep an eye on your parenthesis in the template.  Anything outside of the tags gets sent to print.  This means that you can have:


{% (if (not (null? some-value)) (begin %}
<p>This is where you print {% (print some-value) %}</p>
{% )) %}


This becomes:


(if (not (null? some-value))
  (begin
    (print "<p>This is where you print ")
    (print some-value)
    (print "</p>")))


...although it is not pretty and indented.  Note that I used begin to encapsulate the text, "This is where...," because it gets put into a print expression.  If there were no begin statement, it would treat the (print some-value) as the else form to the if statement.



This sort of emulates PHP in that anything between your outer parenthesis will be placed logistically inside of the parenthesis in the eval'd code.



The second argument to render is a context in which variables that will be considered local to the template are defined.  This forces the template to explicitly call values from MAIN if it wishes to do so; a sort of chair against the door (not impossible to bypass, but you have to really want to) to keep from accidentally exposing important data from MAIN.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

Jeff

#1
Actually, this is not good at all.  Since I used curly braces, it is now going to nuke any javascript or css in the page.  I'll work on it some more.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

Jeff

#2
Ok, here is what I *believe* is a fixed version.  I based the code off of Lutz's CGI:put-page since his is more lispy than mine (mine broke the stringed file into string chunks, which is not what newlisp is optimized for).  This one works more like a parser anyway.  The main difference between this one and Lutz's put-page is that mine allows for code blocks interspersed with html, allowing you to iterate over an html block, printing it (and evaluating any lisp code inside it in {%...%}s as well) until another {%...%} block comes with closing parens.  Here she is:


(define (render template ctx , start end expanded-template)
    (set 'ctx (eval ctx))
    (context ctx)
    (set 'expanded-template "")
    (set 'start (find "{%" template))
    (set 'end (find "%}" template))
    (while (and start end)
        (push (format "(print [text]%s[/text])" (slice template 0 start))
              expanded-template -1)
        (push (slice template (+ start 2) (- end start 2))
              expanded-template -1)
        (set 'template (slice template (+ end 2)))
        (set 'start (find "{%" template))
        (set 'end (find "%}" template)))
    ;(println "<textarea>" expanded-template "</textarea>") ;good for debugging in a web browser
    (eval-string expanded-template)
    (exit))
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

Dmi

#3
Hi, Jeff!



My programmer using the same idea. And he has a comment about this:



It's more useful not to directly use "print", but to compose whole template in a buffer (use "write-buffer"), and then to print the buffer.



The advantage is that you can catch errors and prevent the printing of "broken" pages.
WBR, Dmi

Jeff

#4
That's a good idea.  I'm new and didn't know about the write-buffer function; I'll look at that. I was thinking about having it use a catch block to evaluate it.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

rickyboy

#5
Quote from: "Jeff"[It] allows for code blocks interspersed with html, allowing you to iterate over an html block, printing it (and evaluating any lisp code inside it in {%...%}s as well) until another {%...%} block comes with closing parens.  


Very cool.  This is *exactly* the same idea employed by http://brl.sourceforge.net/brl_4.html#SEC19">BRL which I like very much.  --Ricky
(λx. x x) (λx. x x)