From edi at agharta.de Mon Dec 11 07:58:39 2006 From: edi at agharta.de (Edi Weitz) Date: Mon, 11 Dec 2006 08:58:39 +0100 Subject: [html-template-devel] Proposed new feature for HTML-TEMPLATE In-Reply-To: (Marijn Haverbeke's message of "Sun, 26 Nov 2006 14:56:15 +0100") References: Message-ID: On Sun, 26 Nov 2006 14:56:15 +0100, "Marijn Haverbeke" wrote: > Support for the TMPL_CALL tag is added. OK, sorry for the /long/ delay, but as I said I'm pretty busy at the moment. Your proposal sounds fine to me and I think we should include it. If you want this to be released quickly, please send a clean patch that not only includes the code with doc string but also updates the test file and the HTML documentation accordingly. Thanks in advance, Edi. From marijnh at gmail.com Mon Dec 11 19:15:26 2006 From: marijnh at gmail.com (Marijn Haverbeke) Date: Mon, 11 Dec 2006 20:15:26 +0100 Subject: [html-template-devel] Proposed new feature for HTML-TEMPLATE In-Reply-To: References: Message-ID: > > Your proposal sounds fine to me and I think we should include it. If > you want this to be released quickly, please send a clean patch that > not only includes the code with doc string but also updates the test > file and the HTML documentation accordingly. Attached is the path which should do all that. I also included a small refactoring which splits up create-simple-printer, but that should be easy to remove if you don't like it. Regards, Marijn -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- Only in html-template.mine/: api.fasl diff -ur html-template-0.7.0/doc/index.html html-template.mine/doc/index.html --- html-template-0.7.0/doc/index.html 2006-09-30 00:36:28.000000000 +0200 +++ html-template.mine/doc/index.html 2006-12-11 04:16:53.000000000 +0100 @@ -31,10 +31,9 @@ for.)

It is loosely modeled after the Perl module HTML::Template and compatible -with a subset of its syntax, i.e. it should be possible to use your -HTML-TEMPLATE templates with HTML::Template as well (but usually not -the other way around). +href="http://html-template.sf.net/">HTML::Template and partially +compatible with a its syntax, though both libraries contain some +extensions that the other does not support.

HTML-TEMPLATE translates templates into efficient closures which can be re-used as often as needed. It uses an intelligent cache @@ -57,9 +56,9 @@ href="http://www.cliki.net/Lisp%20Markup%20Languages">Lisp markup languages but found that HTML::Template's approach usually works best for me: The graphical designers only need to learn a minimal set -of new tags (three of them) and can update their templates -independently from the work done on the backend. It is simple and it -just works. YMMV, of course... +of new tags and can update their templates independently from the work +done on the backend. It is simple and it just works. YMMV, of +course...

HTML-TEMPLATE is intended to be portable and should work with all conforming Common Lisp implementations but is mainly tested and @@ -111,6 +110,8 @@

  • *template-symbol-package*
  • *force-default*
  • *value-access-function* +
  • *call-template-access-function* +
  • *call-value-access-function*
  • *ignore-empty-lines*
  • *warn-on-creation* @@ -398,13 +399,13 @@ where name is one of TMPL_VAR, -TMPL_LOOP, TMPL_REPEAT, TMPL_IF, TMPL_UNLESS, +TMPL_LOOP, TMPL_REPEAT, TMPL_CALL, TMPL_IF, TMPL_UNLESS, TMPL_INCLUDE, /TMPL_LOOP, /TMPL_REPEAT, /TMPL_IF, /TMPL_UNLESS, or TMPL_ELSE. Case doesn't matter, i.e. tmpl_var or Tmpl_Var would also be legal names.

    -If name is one of the first four listed above then +If name is one of the first seven listed above then attribute must follow, otherwise it must not follow where attribute is any sequence of characters delimited by ", ', or by whitespace. There's @@ -465,10 +466,10 @@ "NAME=" notation which is not supported by HTML-TEMPLATE.

    -The TMPL_VAR and TMPL_INCLUDE tags can -appear anywhere and as often as you like in your templates while the -other tags must obey certain rules - they must follow one of these -patterns +The TMPL_VAR, TMPL_INCLUDE, and +TMPL_CALL tags can appear anywhere and as often as you +like in your templates while the other tags must obey certain rules - +they must follow one of these patterns

       <!-- TMPL_IF attribute --> text <!-- /TMPL_IF -->
    @@ -520,7 +521,7 @@
     to fill and print a template.
     

    Each of the template tags TMPL_VAR, TMPL_IF, TMPL_UNLESS, -TMPL_LOOP, and TMPL_REPEAT is associated with a particular symbol at +TMPL_LOOP, TMPL_CALL, and TMPL_REPEAT is associated with a particular symbol at generation time. This symbol is the result of INTERNing the tag's attribute string into the package *TEMPLATE-SYMBOL-PACKAGE*. The @@ -687,6 +688,50 @@ including printer. +

    <!-- TMPL_CALL symbol --> + +

    +The value associated with symbol should be a sequence (as +specified by *SEQUENCES-ARE-LISTS*) +of template calls, each of which specifies a substructure and a +template to apply to that. By default, calls are just lists, with the +CAR specifying the template name and the CDR containing the +substructure. (See *CALL-TEMPLATE-ACCESS-FUNCTION* +and *CALL-VALUE-ACCESS-FUNCTION* +for ways to customize what calls look like.) +

    +TMPL_CALL combines aspects of TMPL_LOOP and +TMPL_INCLUDE, it iterates over a sequence of values the +way loops do, but instead of using part of the current template to +print the values each value contains its own information about which +subtemplate should be applied to it. + +

    +* (with-open-file (s "/tmp/paragraph" :direction :output :if-exists :supersede)
    +    (write-string "<p class='fancy'><!-- TMPL_VAR text --></p>" s))
    +"<p class='fancy'><!-- TMPL_VAR text --></p>"
    +* (with-open-file (s "/tmp/header" :direction :output :if-exists :supersede)
    +    (write-string "<h1><!-- TMPL_VAR text --></h1>" s))
    +"<h1><!-- TMPL_VAR text --></h1>"
    +* (fill-and-print-template "<body><!-- TMPL_CALL parts --></body>"
    +                           '(:parts ((#P"/tmp/header" :text "Chapter 1")
    +                                     (#P"/tmp/paragraph" :text "There once was a platypus...")
    +                                     (#P"/tmp/header" :text "Chapter 5")
    +                                     (#P"/tmp/paragraph" :text "And lived happily ever after."))))
    +<h1>Chapter 1</h1><p class='fancy'>There once was a platypus...</p><h1>Chapter 5</h1><p class='fancy'>And lived happily ever after.</p></body>
    +
    +

    +Note that you do not have to include full pathnames in the call +structures. You can use *DEFAULT-TEMPLATE-PATHNAME* +to specify most of it, or set *CALL-TEMPLATE-ACCESS-FUNCTION* +to a function that creates pathnames any way you like. +

    +
     

    The HTML-TEMPLATE dictionary

    HTML-TEMPLATE exports the following symbols (some of which are also @@ -1037,7 +1082,7 @@ list (symbol values &optional in-loop-p) which is used to associate symbols with their values when a template printer is invoked. in-loop-p is true whenever this -function is called from within a TMPL_LOOP tag. +function is called from within a TMPL_LOOP or TMPL_CALL tag.

    The default value is @@ -1068,6 +1113,35 @@


    [Special variable] +
    *call-template-access-function* + +


    The value of this variable should be a designator +for a function which takes one argument (the call structure) and +returns either a template printer or a value that can be used as the +first argument to create-template-printer. +This function will be used to determine the template that should be +used for a call in a TMPL_CALL tag. +

    The default value +is #'CAR. +This variable takes effect at invocation +time.

    + +


    [Special variable] +
    *call-value-access-function* + +


    The value of this variable should be a designator +for a function which takes one argument (the call structure) and +returns a structure to use as the value for a call in a +TMPL_CALL tag.

    The default value is #'CDR. +This variable takes effect at invocation +time.

    + +


    [Special variable]
    *ignore-empty-lines*


    Only in html-template.mine/: errors.fasl Only in html-template.mine/: packages.fasl diff -ur html-template-0.7.0/packages.lisp html-template.mine/packages.lisp --- html-template-0.7.0/packages.lisp 2006-09-14 13:44:31.000000000 +0200 +++ html-template.mine/packages.lisp 2006-11-19 05:50:14.000000000 +0100 @@ -32,7 +32,9 @@ (defpackage :html-template (:nicknames :template) (:use :cl) - (:export :*convert-nil-to-empty-string* + (:export :*call-template-access-function* + :*call-values-access-function* + :*convert-nil-to-empty-string* :*default-template-output* :*default-template-pathname* :*escape-char-p* Only in html-template.mine/: specials.fasl diff -ur html-template-0.7.0/specials.lisp html-template.mine/specials.lisp --- html-template-0.7.0/specials.lisp 2006-09-14 16:02:00.000000000 +0200 +++ html-template.mine/specials.lisp 2006-12-11 03:59:26.000000000 +0100 @@ -105,6 +105,14 @@ "The function which associates \(attribute) symbols with their values.") +(defvar *call-template-access-function* #'car + "Accessor function for extracting the called template from a +TMPL_CALL form.") + +(defvar *call-value-access-function* #'cdr + "Accessor function for extracting the values from a TMPL_CALL +form.") + (defvar *force-default* nil "The default value for the FORCE keyword argument to CREATE-TEMPLATE-PRINTER.") Only in html-template.mine/: template.fasl diff -ur html-template-0.7.0/template.lisp html-template.mine/template.lisp --- html-template-0.7.0/template.lisp 2006-09-30 00:36:26.000000000 +0200 +++ html-template.mine/template.lisp 2006-12-11 03:59:26.000000000 +0100 @@ -50,49 +50,54 @@ #+:lispworks (editor:setup-indent "with-use-value-restart" 1 2 4) -(defun create-simple-printer (string-list &optional symbol/pathname (next-fn #'no-values)) - "Used internally to create template printers for TMPL_VAR, -TMPL_INCLUDE, and for strings which don't include template -tags. SYMBOL/PATHNAME is the symbol or pathname associated with the -tag. NEXT-FN is the next function to be called in the chain of -closures. STRING-LIST is a list of strings in reverse order to be -printed first." +(defun create-simple-printer (string-list &optional (next-fn #'no-values)) + "Used internally to create template printers for strings which don't +include template tags. NEXT-FN is the next function to be called in +the chain of closures. STRING-LIST is a list of strings in reverse +order to be printed first." (let ((string (list-to-string string-list))) - (etypecase symbol/pathname - (null - ;; no tag, just print STRING - (lambda (values) - (write-string string *template-output*) - (funcall next-fn values))) - (symbol - ;; TMPL_VAR tag - (lambda (values) - (write-string string *template-output*) - (let* ((value (funcall *value-access-function* symbol/pathname values)) - (string (typecase value - (null - (if *convert-nil-to-empty-string* - "" - (with-use-value-restart (symbol/pathname) - (signal-template-missing-value-error - "Value for symbol ~S is NIL" - symbol/pathname)))) - (string value) - (otherwise - (cond (*format-non-strings* (format nil "~A" value)) - (t (with-use-value-restart (symbol/pathname) - (error 'template-not-a-string-error - :value value - :format-control "Value ~S for symbol ~S is not a string" - :format-arguments (list value symbol/pathname))))))))) - (write-string (funcall *string-modifier* string) *template-output*)) - (funcall next-fn values))) - (pathname - ;; TMPL_INCLUDE tag - (lambda (values) - (write-string string *template-output*) - (funcall (car (gethash symbol/pathname *printer-hash*)) values) - (funcall next-fn values)))))) + (lambda (values) + (write-string string *template-output*) + (funcall next-fn values)))) + +(defun create-var-printer (string-list symbol next-fn) + "Used internally to create template printers for TMPL_VAR. SYMBOL is +the symbol associated with the tag. NEXT-FN is the next function to be +called in the chain of closures. STRING-LIST is a list of strings in +reverse order to be printed first." + (let ((string (list-to-string string-list))) + (lambda (values) + (write-string string *template-output*) + (let* ((value (funcall *value-access-function* symbol values)) + (string (typecase value + (null + (if *convert-nil-to-empty-string* + "" + (with-use-value-restart (symbol) + (signal-template-missing-value-error + "Value for symbol ~S is NIL" + symbol)))) + (string value) + (otherwise + (cond (*format-non-strings* (format nil "~A" value)) + (t (with-use-value-restart (symbol) + (error 'template-not-a-string-error + :value value + :format-control "Value ~S for symbol ~S is not a string" + :format-arguments (list value symbol))))))))) + (write-string (funcall *string-modifier* string) *template-output*)) + (funcall next-fn values)))) + +(defun create-include-printer (string-list pathname next-fn) + "Used internally to create template printers for TMPL_INCLUDE. +PATHNAME is the pathname associated with the tag. NEXT-FN is the next +function to be called in the chain of closures. STRING-LIST is a list +of strings in reverse order to be printed first." + (let ((string (list-to-string string-list))) + (lambda (values) + (write-string string *template-output*) + (funcall (car (gethash pathname *printer-hash*)) values) + (funcall next-fn values)))) (defun create-if-printer (string-list symbol if-fn else-fn next-fn unlessp) "Used internally to create template printers for TMPL_IF and @@ -148,6 +153,34 @@ do (funcall body-fn values)))) (funcall next-fn values)))) +(defun create-call-printer (string-list symbol next-fn) + "Used internally to create template printers for TMPL_CALL tags. +SYMBOL is the symbol associated with the tag. BODY-FN is the template +printer for the body of the loop. NEXT-FN is the next function to be +called in the chain of closures. STRING-LIST is a list of strings in +reverse order to be printed first." + (let ((string (list-to-string string-list))) + (cond (*sequences-are-lists* + (lambda (values) + (write-string string *template-output*) + (dolist (call (funcall *value-access-function* + symbol values t)) + (fill-and-print-template + (funcall *call-template-access-function* call) + (funcall *call-value-access-function* call) + :stream *template-output*)) + (funcall next-fn values))) + (t + (lambda (values) + (write-string string *template-output*) + (loop for call across (funcall *value-access-function* + symbol values t) + do (fill-and-print-template + (funcall *call-template-access-function* call) + (funcall *call-value-access-function* call) + :stream *template-output*)) + (funcall next-fn values)))))) + (defun create-template-printer-aux (string-stack end-token) "Reads from *STANDARD-INPUT* and returns a template printer from what it reads. When this function is entered the stream pointer must @@ -227,10 +260,10 @@ ;; then we combine it with the strings before the tag ;; to create a template printer for TMPL_INCLUDE (values - (create-simple-printer (cons (skip-leading-whitespace string) - string-stack) - merged-pathname - next-fn) + (create-include-printer (cons (skip-leading-whitespace string) + string-stack) + merged-pathname + next-fn) else-follows)))) ((string-equal token "TMPL_VAR") ;; TMPL_VAR tag - first read the symbol which has to @@ -245,7 +278,7 @@ ;; to create a template printer for TMPL_VAR - note ;; that we don't skip leading and trailing whitespace ;; here - (create-simple-printer (cons string string-stack) + (create-var-printer (cons string string-stack) symbol next-fn) else-follows)))) @@ -283,6 +316,24 @@ body-fn next-fn) else-follows)))) + ((string-equal token "TMPL_CALL") + ;; TMPL_CALL tag - first read the symbol which has to + ;; follow and intern it + (let ((symbol (read-tag-rest :read-attribute t))) + (multiple-value-bind (next-fn else-follows) + ;; recursively create the template printer for the + ;; rest of the stream + (create-template-printer-aux (skip-trailing-whitespace) + end-token) + ;; create the printer that will output the strings + ;; before this tag and call the templates stored under + ;; SYMBOL + (values (funcall #'create-call-printer + (cons (skip-leading-whitespace string) + string-stack) + symbol + next-fn) + else-follows)))) ((string-equal token "/TMPL_LOOP") (unless (eq end-token :loop) ;; check if we expected /TMPL_LOOP here, i.e. if an open Only in html-template.mine/: test.fasl diff -ur html-template-0.7.0/test.lisp html-template.mine/test.lisp --- html-template-0.7.0/test.lisp 2006-09-30 00:36:26.000000000 +0200 +++ html-template.mine/test.lisp 2006-12-11 04:30:06.000000000 +0100 @@ -121,6 +121,12 @@ (test "2" "1234" '(:foo t :bar nil)) (test "3" "1234" '(:foo nil :baz t)) (test "4" "1234" '(:foo nil :baz nil)) +(test "X" "" '(:foo (("X")))) +(test "QUUX" "" '(:baz "Q" + :foo (("" :bar "U") + ("X" :bar "U")))) +(test "" "" '(:foo (("---")))) +(test nil "" '(:foo 57)) (let ((temp-name (make-pathname :name (format nil "template-test-~A" (random 1000000)) :defaults tmp-dir))) @@ -213,7 +219,11 @@ "[]" '(:vector #((:item "1") (:item "2") - (:item "3"))))) + (:item "3")))) + (test "QUUX" "" + '(:baz "Q" + :foo #(("" :bar "U") + ("X" :bar "U"))))) (let ((*upcase-attribute-strings* nil)) (test "The slow brown fox" Only in html-template.mine/: util.fasl From edi at agharta.de Tue Dec 12 19:33:45 2006 From: edi at agharta.de (Edi Weitz) Date: Tue, 12 Dec 2006 20:33:45 +0100 Subject: [html-template-devel] New version 0.8.0 (Was: Proposed new feature for HTML-TEMPLATE) In-Reply-To: (Marijn Haverbeke's message of "Mon, 11 Dec 2006 20:15:26 +0100") References: Message-ID: On Mon, 11 Dec 2006 20:15:26 +0100, "Marijn Haverbeke" wrote: > Attached is the path which should do all that. I also included a > small refactoring which splits up create-simple-printer, but that > should be easy to remove if you don't like it. Very nice, thanks a lot. I've released a new version with your modifications. Cheers, Edi. From vamlists at gmail.com Mon Dec 25 22:20:03 2006 From: vamlists at gmail.com (Vamsee Kanakala) Date: Tue, 26 Dec 2006 03:50:03 +0530 Subject: [html-template-devel] tmpl_equal needed ? Message-ID: <45904E93.3080606@gmail.com> Hi, I think html-template really needs a templ_equal tag. I am trying to pre-select an option inside a select tag, based on parameters passed. Since the option tags are also being generated through a loop, I think there is no way I can do this unless I can have some comparison mechanism within the template. Kindly correct me if I'm wrong. Thanks, Vamsee. From edi at agharta.de Mon Dec 25 23:09:17 2006 From: edi at agharta.de (Edi Weitz) Date: Tue, 26 Dec 2006 00:09:17 +0100 Subject: [html-template-devel] tmpl_equal needed ? In-Reply-To: <45904E93.3080606@gmail.com> (Vamsee Kanakala's message of "Tue, 26 Dec 2006 03:50:03 +0530") References: <45904E93.3080606@gmail.com> Message-ID: On Tue, 26 Dec 2006 03:50:03 +0530, Vamsee Kanakala wrote: > I think html-template really needs a templ_equal tag. I am trying to > pre-select an option inside a select tag, based on parameters > passed. Since the option tags are also being generated through a > loop, I think there is no way I can do this unless I can have some > comparison mechanism within the template. Kindly correct me if I'm > wrong. Could you provide an example of what you're trying to do? Thanks, Edi. From penguin at ocean.vvo.ru Tue Dec 26 00:39:35 2006 From: penguin at ocean.vvo.ru (Igor Plekhov) Date: Tue, 26 Dec 2006 10:39:35 +1000 Subject: [html-template-devel] tmpl_equal needed ? In-Reply-To: <45904E93.3080606@gmail.com> References: <45904E93.3080606@gmail.com> Message-ID: <20061226003935.GA3567@ocean.vvo.ru> On Tue, 26 Dec, 2006 at 03:50:03 +0530, Vamsee Kanakala wrote: > > I think html-template really needs a templ_equal tag. I am trying to > pre-select an option inside a select tag, based on parameters passed. > Since the option tags are also being generated through a loop, I think > there is no way I can do this unless I can have some comparison > mechanism within the template. Kindly correct me if I'm wrong. You can use parameters passed while generating data to fill the template. And set some variable to T at some particular loop step. That variable will be NIL at all other steps. Then in the template use to emit "selected" inside