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.'"