[PLUG] lisp problem: switching packages on the fly

Carlos Konstanski ckonstanski at pippiandcarlos.com
Mon Nov 6 06:28:23 UTC 2006


Been beating my head against the monitor on this lisp problem.  Maybe
someone can help.

The following snippet of lisp code is from my web server.  I have more
than one website running in the server, and the websites have many
shared resources.  For instance, the stylesheet is identical for all the
websites, except the specific values (colors, font names, etc.).  So
each website has its own skin-config list, whereas the stylesheet
generating function itself is shared by all websites.

Each website lives in its own package.  There's a :wrlug-site, a
:jewelry-site, and a :pippiandcarlos-site presently, with more to come.
Each of these sites has its own skin-config, therefore there is a
wrlug-site:skin-config, a jewelry-site:skin-config, and a
pippiandcarlos-site:skin-config.  But there is only one function
(stylesheet-body), which lives in a parent package called :araneida-site.
:araneida-site does not use any of the aforementioned packages.  Indeed,
there would be symbol conflicts aplenty if I attempted this, since each
webapp package has many of the same symbol names, of which skin-config
is just one.  The idea is to have as many shared resources as possible,
and to be able to use these resources without having to pass around a
lot of data and functions in argument lists to make them accessible to
the shared functions.

So when I get to the point in the execution of a page where I'm calling
(araneida-site:stylesheet-body), I need to direct this function to call
upon symbols from the correct package, corresponding to the webapp the
user is in when he sent a request that caused (araneida-site:stylesheet-body)
to be called.  Ideally I would like to switch the current package to
<webapp-package>, execute the code, and (if necessary) switch back to
:araneida-site.  This seems like the cleanest way to make a single body
of code work across a bunch of packages.

This is as far as I got.  The current package does indeed change.  I can
tell this because my REPL prompt changes to the new package name.  But a
condition is signaled: "The variable SKIN-CONFIG is unbound".  However,
if I type "skin-config" in the REPL after the package change, the value of
skin-config is found, and its contents displayed.

If I cannot switch packages on the fly inside a function, I would settle
for a macro that prepends the package name to a symbol, so I could write
something like (prepend-package skin-config), and end up with
jewelry-site:skin-config in its place, though it's less desirable because
I would have to alter many lines of code to do something that should be
possible with one line at the top.

Any ideas would be appreciated.

Here's a complete code listing for a clinical test case.  The expected
output would be a CSS body{} element, with colors and font names
substituted in place of the skin-config queries.  It should be called
like:

(in-package #:araneida-site)
(stylesheet-body "jewelry-site")



;; ====== ;;

(defpackage #:jewelry-site
   (:export #:skin-config)
   (:use #:cl))

(in-package #:jewelry-site)

(defparameter skin-config `(:color-canvas "#539083"
                             :color-background "white"
                             :color-dark "black"
                             :color-medium "#779193"
                             :color-light "#dddddd"
                             :color-white "white"
                             :color-alink "blue"
                             :color-vlink "maroon"
                             :color-error "red"
                             :color-highlight "yellow"
                             :font-family "verdana, tahoma, helvetica, arial, sans"
                             :font-size-default "14px"
                             :font-size-text "12px"
                             :font-size-tinytext "10px"
                             :border "white 0px solid")
   "A list of all style values for the webapp.")

;; ====== ;;

(defpackage #:araneida-site
   (:use #:cl))

(in-package #:araneida-site)

(defun stylesheet-body (webapp-package)
   "Outputs the body of the stylesheet."
   (let ((webapp-package-coerced-to-string (string-upcase (format nil "~a" webapp-package))))
     (setf *package* (find-package webapp-package-coerced-to-string))
     (use-package *package*)    ;; redundant?
     `(,(concatenate 'string
"body {
     background-color: " (getf skin-config :color-canvas) ";
     color: " (getf skin-config :color-dark) ";
     font-family: " (getf skin-config :font-family) ";
     font-size: " (getf skin-config :font-size-default) ";
     font-weight: normal;
     scrollbar-arrow-color: " (getf skin-config :color-medium) ";
     scrollbar-track-color: " (getf skin-config :color-medium) ";
     scrollbar-highlight-color: " (getf skin-config :color-medium) ";
     scrollbar-darkshadow-color: " (getf skin-config :color-medium) ";
     scrollbar-shadow-color: " (getf skin-config :color-medium) ";
     scrollbar-face-color: " (getf skin-config :color-white) ";
     scrollbar-3dlight-color: " (getf skin-config :color-medium) ";
}"))))

Carlos Konstanski



More information about the PLUG mailing list