From: Gene Michael Stover
Subject: new tutorial on lisp-p.org
Date: 
Message-ID: <qd2cndLRJOouVaOiXTWc-g@speakeasy.net>
I've posted a new tutorial for beginning Lisp programmers.
"Generating HTML with Lisp"
http://lisp-p.org/lh/

This is a tutorial for new Lisp programmers, but not total
beginners. I assume you know some basic Lisp, like the
syntax, lists, and what car & cdr mean.

Things I discuss or show in this tutorial include

     * A simple, but representative, use of macros,

     * Refactoring Lisp code as we develop,

     * Moving code into a package,

     * Optimization session with the help of a profiler
       written in Lisp itself & discussion of effective use
       of a profiler,

     * Another programmer's thought processes as he develops
       some software. It's not that my thought processes are
       models for a good programmer; it's that it is
       sometimes useful to see how another practitioner of
       the same craft thinks.

This is not a CGI tutorial, though I do a tiny bit of CGI
near the end. It's just an HTML tutorial.

From: Rainer Joswig
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <joswig-6FDD19.03352217082003@news.fu-berlin.de>
In article <······················@speakeasy.net>,
 Gene Michael Stover <·······@speakeasy.net> wrote:

> I've posted a new tutorial for beginning Lisp programmers.
> "Generating HTML with Lisp"
> http://lisp-p.org/lh/
> 
> This is a tutorial for new Lisp programmers, but not total
> beginners. I assume you know some basic Lisp, like the
> syntax, lists, and what car & cdr mean.
> 
> Things I discuss or show in this tutorial include
> 
>      * A simple, but representative, use of macros,
> 
>      * Refactoring Lisp code as we develop,
> 
>      * Moving code into a package,
> 
>      * Optimization session with the help of a profiler
>        written in Lisp itself & discussion of effective use
>        of a profiler,
> 
>      * Another programmer's thought processes as he develops
>        some software. It's not that my thought processes are
>        models for a good programmer; it's that it is
>        sometimes useful to see how another practitioner of
>        the same craft thinks.
> 
> This is not a CGI tutorial, though I do a tiny bit of CGI
> near the end. It's just an HTML tutorial.
> 

Please, don't show stuff like that to the kids ;-) :

(defun encode (str)
  "Scan a string, converting the unsafe characters to entities
for HTML.  Return the new, safe, HTML string."
  (let ((html ""))
    (map nil #'(lambda (c)
       (setq html (format nil "~A~A" html
                (gethash c *html-translations* c))))
    str)
    html))

1) This conses like hell. 
2) using format to repeatedly concatenate strings and characters
   is REALLY BAD style.

Maybe use something like:

(defun encode (str)
  "Scan a string, converting the unsafe characters to entities
for HTML.  Return the new, safe, HTML string."
  (with-output-to-string (stream)
    (loop for character across str
          do (princ (gethash character *html-translations* character)
                    stream))))

Just as a comparison - this is what the HTML generating
example code might look like using the HTML4.0 package of CL-HTTP:

(use-package 'html4.0)

(defun one-row (date miles gallons price)
  "Return a row in an HTML table.  Its columns
are the date, miles, gallons, miles per gallon,
price, & price per mile."
  (with-table-row ()
    (flet ((td (data)
             (with-table-cell (:horizontal-alignment :right)
               (princ data))))
      (td date)
      (td miles)
      (td gallons)
      (td (format nil "~,2F" (/ miles gallons)))
      (td (format nil "~,2F" price))
      (td (format nil "~,2F" (/ price miles))))))

(defun report (lst)
  "Generate a miles per gallon report.  LST
holds the data.  Each element of LST is a
list of four elements: date, gallons, price
(for the entire purchase), & miles.  LST must
be sorted from earliest date to last.  Returns
a string that is the report."
  (with-html-document ()
    (with-document-preamble ()
      (declare-title "Miles per Gallon"))
    (with-document-body ()
      (with-section-heading ("Miles per Gallon" :alignment :center)
        (with-table (:border 1)
          (with-table-row ( )
            (flet ((th (data &key (alignment :right))
                     (with-table-cell (:horizontal-alignment alignment :header-p t)
                       (princ data))))
              (th "date" :alignment :left)
              (map nil #'th '("miles" "gallons" "mpg" "price" "price per gallon"))
              (loop for (nil nil nil price) in lst
                    for  (date miles gallons price2) in (rest lst)
                    do (one-row date (- price2 price) miles gallons)))))
        (with-paragraph (:alignment :center)
          (princ "End."))))))
From: Stefan Scholl
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <1n79efzlzvost.dlg@parsec.no-spoon.de>
Hmm. Why is it that Lisp programmers like it to print HTML
themselves instead of filling templates?
From: Greg Menke
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <m31xvkqwve.fsf@europa.pienet>
Stefan Scholl <······@no-spoon.de> writes:

> Hmm. Why is it that Lisp programmers like it to print HTML
> themselves instead of filling templates?

Well HTML is a language for marking up documents after all.  I'm sure
you wouldn't have problems with people generating their own text
files, so whats the difference?

Gregm
From: Edi Weitz
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <87ada8bgaj.fsf@bird.agharta.de>
On Sun, 17 Aug 2003 13:53:07 +0200, Stefan Scholl <······@no-spoon.de> wrote:

> Hmm. Why is it that Lisp programmers like it to print HTML
> themselves instead of filling templates?

If the main focus is on creating and displaying data dynamically I
find it more convenient to create the bits of markup that are needed
directly in the program (assuming that the program logic outweighs the
markup part significantly). I'd do the same for other languages like
Perl.

If there's a lot of markup involved (probably done by a third party) I
use a template-based approach. Shameless plug: You might want to look
at

  <http://weitz.de/html-template/>

Cheers,
Edi.
From: Eduardo Muñoz
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <u4r0g8hu4.fsf@terra.es>
* Stefan Scholl <······@no-spoon.de>
| Hmm. Why is it that Lisp programmers like it to print HTML
| themselves instead of filling templates?

It's fun and easy and you can reach to a lot of people with
a web page. So I wrote my whole site in lisp (shame on me :)


-- 
Eduardo Mu�oz          | (prog () 10 (print "Hello world!")
http://213.97.131.125/ |          20 (go 10))
From: james anderson
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <3F3F9D65.A4DC3BC6@setf.de>
is the question about the abstraction level of the posted examples, or is it
about something more fundamental?

Stefan Scholl wrote:
> 
> Hmm. Why is it that Lisp programmers like it to print HTML
> themselves instead of filling templates?
From: Joe Marshall
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <ekziyf7g.fsf@ccs.neu.edu>
Stefan Scholl <······@no-spoon.de> writes:

> Hmm. Why is it that Lisp programmers like it to print HTML
> themselves instead of filling templates?

I've wondered why they want to print HTML instead of creating
a document from CLOS classes and asking it to render itself
to a port.
From: c hore
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <ca167c61.0308181730.69838d44@posting.google.com>
Joe Marshall wrote:
> I've wondered why they want to print HTML instead of creating
> a document from CLOS classes and asking it to render itself
> to a port.

I don't recall seeing concept of port in ANSI CL.
Did you mean stream?  Or (implementation-specific
interface to a) TCP/IP port?

Either way, an object could "render itself" by printing
HTML to a stream (or port, assuming whatever-that-is makes
sense).

So "printing HTML" and "calling a generic function to render
thyself" are not necessarily mutually exclusive, are they...
From: Joe Marshall
Subject: Re: new tutorial on lisp-p.org
Date: 
Message-ID: <k799eipe.fsf@ccs.neu.edu>
·······@yahoo.com (c hore) writes:

> Joe Marshall wrote:
>> I've wondered why they want to print HTML instead of creating
>> a document from CLOS classes and asking it to render itself
>> to a port.
>
> I don't recall seeing concept of port in ANSI CL.
> Did you mean stream?  Or (implementation-specific
> interface to a) TCP/IP port?

I meant stream.  (Must've been thinking `TCP port')

> Either way, an object could "render itself" by printing
> HTML to a stream (or port, assuming whatever-that-is makes
> sense).

yes.

> So "printing HTML" and "calling a generic function to render
> thyself" are not necessarily mutually exclusive, are they...

No.

What I meant was that I see far too much code like this:

(format http-port "<p>Here is some <i>marked up</i> text</p>")

instead of something semantically like:

(emit-html http-port
   (paragraph "Here is some " (italic "marked up") " text."))

Where presumably PARAGRAPH and ITALIC are some sort of
constructor.  The idea is that you could go beyond simple
printing of strings:

(let ((info (paragraph "As so and so said:"
                       (blockquote (generate-quote)))))
  (if (< user-age 18)
      (bowdlerize info)
      info))