From: David J Cooper Jr
Subject: Lisp front-end for generating LaTeX
Date: 
Message-ID: <36464ACF.DA3941DA@genworks.com>
Fellow Lispers:

  I had some marketing letters to prepare, and wasn't real
happy with the lack of openness of the Windows and PC-based
mail merge facilities (plus the fact that I only have a 
Solaris box and a Linux box!). I pretty much want to keep 
my contacts in a simple Oracle database or flat file, and
I want the highest degree of flexibility for creating form
letters and so forth out of them.

  I also have other varied needs to generate finely controlled
printed outputs.

  HTML is great for web publishing and web applications, but 
it is still not really to the point of supporting finely
controlled printed output (and maybe never will be, since 
that was never its original intent).

  So, I decided to go ahead and develop a set of Lisp macros 
and functions for generating LaTeX output, in the spirit of 
the nice CL-HTTP macros for HTML output.

 To make things additionally comfortable for myself, I also
decided to go ahead and develop a macro for declarative specification of
CLOS objects and methods, which looks 
very similar to the Defpart macro I am used to using in 
ICAD. I want my office-automation tools to work in a
non-ICAD Lisp, so I developed a very small subset of a defpart-type
macro, since I am so used to working in that declarative mode.

  Attached is an example of a standard-form-letter defpart
for your preliminary perusal.

  The complete source for the LaTeX synthesis and the DRL (Declarative
Representation Language, my declarative CLOS
abstraction) will soon be GPL'ed and available via anonymous
ftp from

   www.genworks.org/lisp-sources/

  (It's not there now, and documenting and packaging will 
probably not happen until after the Lisp conference next week,
unless I get some specific requests for it sooner than that).
 
  I just wanted to ask this group a few questions:

  1) Has something like this already been done? Am I wasting 
     my time?

  2) Would anyone be so kind as to look through the code I have
     so far and comment on it? My macros are much more primitive
     than the ones in CL-HTTP (I don't understand all Mallery's
     (define-macro) and such). Like I said, the sources aren't
     uploaded yet, but if I hear back from anyone it will 
     light a fire under my butt.

  3) I have a several functions which ``feel'' like they 
     should be ``with-'' macros, but many of the arguments 
     are not defined at compile-time, so I don't know if 
     this is really possible (I haven't started reading 
     On Lisp yet, that's the newest book on my shelf...)

  4) Any other specific or general comments welcome.



  Thanks!

  -djc

<========Cut Here================>

(in-package :drl-user)

(defpart standard-form-letter 
    (base-web-inspectable-object)

  :optional-inputs
  (
   :body-filename 
   "~/office/marketing/autofact-body-1.txt"
   
   :data-filename 
   "~/office/marketing/autofact-leads.lisp"
   
   :name "David J. Cooper Jr."
   
   :signature 
   '("David J. Cooper Jr." 
     "President, Genworks International")
   
   :address '("Genworks International"
	      "5777 West Maple, Suite 130"
	      "West Bloomfield, MI 48125")
   
   :point-size 11
   
   :paper-size :usletter
   
   :make-labels? t)

  
  :attributes
  (
   :recipient-data 
   (with-open-file (instream (the :data-filename))
     (read instream))
   
   :body-string 
   (with-open-file (instream (the :body-filename))
     (read-multi-line-string-from-stream instream)))
  
  :parts
  ((:letters :type 'standard-letter
	     :quantify (:series 
			(length 
			 (rest (the :recipient-data))))

	     :data (rest (the :recipient-data))

	     :body-string (the :body-string)))
  
  :methods
  ((:print-letters-to-stream 
    (&key (stream t))
    (latex2e:document-class 
     :letter
     :point-size (the :point-size)
     :paper-size (the :paper-size)
     :name (the :name)
     :address (the :address)
     :signature (the :signature)
     :make-labels? (the :make-labels?)
     :stream stream)
    (latex2e:with-document (:stream stream)
      (dotimes (n (array-dimension (the :letters) 0))
	(the (:letters n) 
	  (:print-to-stream :stream stream)))))))


(defpart standard-letter (base-web-inspectable-object)

  :inputs
  (:data
   :body-string)
  
  :attributes
  (:my-data 
   (nth (the :index) (the :data)))
  
  :uncached-attributes
  (
   :last-name    
   (first   (the :my-data))
   :first-name   (second  (the :my-data))
   :title        (third   (the :my-data))
   :company-name (fourth  (the :my-data))
   :address      (fifth   (the :my-data))
   :city         (sixth   (the :my-data))
   :state        (seventh (the :my-data))
   :zip          (eighth  (the :my-data))
   :phone        (ninth   (the :my-data))
   :fax          (tenth   (the :my-data))
   :salutation   (nth 11  (the :my-data))
   
   :opening (format nil "Dear ~a ~a:" 
		    (the :salutation)
		    (the :last-name))
   
   :recipient-field (list (concatenate 'string 
			    (the :first-name) 
			    " " 
			    (the :last-name))
			  (the :title)
			  (the :company-name)
			  (the :address)
			  (concatenate 'string
			    (the :city)  ", "
			    (the :state) " "
			    (the :zip))))
  
  :methods
  ((:print-to-stream
    (&key (stream t))
    (latex2e:print-letter :recipient (the :recipient-field) 
			  :opening (the :opening)
			  :closing "Yours Truly,"
			  :body (the :body-string)
			  :stream stream))))

-----
   "Microsoft is not the answer. Microsoft is a question,
    and the answer is `No.'"