Carlos Konstanski on 19 Aug 2005 03:20:58 -0000 |
I am a software developer who has, up until now, used pay-dirt languages exclusively (java, php, perl, other "hot" languages in today's workaday world). I have come to the realization that lisp is the only language that matters. I'm gobbling it up like a greedy child. With any luck, I'll find a way to use it at my paying job. I have just written my first useful macro. There is one small problem with it that I do not have the lisp knowledge to solve. I need to know more about symbols vs. strings when used unquoted (preceded by ",") in a macro (or, really, in a backticked list). Among other tasks, this macro writes a (defclass) and a (defmethod). The name of the class I am creating is currently passed in as a symbol (not a string). Another argument of the macro is a URL (string). I would like to be able to do away with the class name argument, since the calling code does not need to know this bit of information. I would rather use the URL (a unique string) to derive a class name, inside the macro definition. Here's the relevant code (I'm using SBCL): (defvar *document-root-url* nil "This is the public URL of the site. Example: \"http://localhost:3000\".") (setf *document-root-url* (let ((fqdn #+sbcl(sb-bsd-sockets:host-ent-name (sb-bsd-sockets:get-host-by-name (machine-instance))) #-sbcl (format nil "localhost"))) (make-url :scheme "http" : host fqdn : port *tcp-port*))) (defvar *website-url* nil) (setf *website-url* (urlstring (merge-url *document-root-url* "/jewelery"))) (defvar *title* "Pippi's Jewelery") (defun make-absolute-url(url) "Prepends *WEBSITE-URL* to the given URL and returns the full URL as a string." (concatenate 'string *website-url* url)) (defmacro publish-page (handler-class-name url &rest body) "Macro to do the grunt work of creating and installing a subclass of HANDLER for each page you wish to publish. Publishing a page entails 3 actions: - defining a class for the page that is a subclass of HANDLER; - implementing the handle-request-response method on this class; - installing an instance of the handler into the listener. This macro automates the production of all this code." `(progn (defclass ,handler-class-name (handler) ()) (defmethod handle-request-response ((handler ,handler-class-name) method request) (request-send-headers request) (html-stream (request-stream request) ,@body)) (install-handler (http-listener-handler *listener*) (make-instance ',handler-class-name) (make-absolute-url ,url) t))) (publish-page jewelery-home "/home" `(html (head (title ,*title*)) (body ((h1 :align "center") "Hello Pip"))))
The code I didn't show you (because it works and has nothing to do with the problem) supplies an instance of an araneida LISTENER class in the constant *listener*. *listener* has a slot to hold a single DISPATCHING-HANDLER object, which is the container for the collection of HANDLER instances. This alist of HANDLER objects is keyed by URL string. A HANDLER is nothing more than a class with no slots and a single method, HANDLE-REQUEST-RESPONSE. The URL is used at request time to look up the corresponding subcless of HANDLER, and calling the HANDLE-REQUEST-RESPONSE method specialized on that subclass gets us to the right function to render the page. That is all done by the araneida API. To use the API, all we need to do is populate DISPATCHING-HANDLER with HANDLER subclasses. Another user-written lisp file is responsible for creating the *listener* instance and putting the singeton root DISPATCHING-HANDLER in it. The code supplied above is what adds the HANDLER instances to the DISPATCHING-HANDLER using INSTALL-HANDLER. PUBLISH-PAGE is the macro that automates the writing of the code for creating and installing a page handler. It creates a subclass of HANDLER. Then it overrides the HANDLE-REQUEST-RESPONSE method, which will get called by araneida when a request to the matching URL is made. Then it calls INSTALL-HANDLER to place the sublassed HANDLER into the DISPATCHING-HANDLER. This macro is where I need help. There are 2 places where I run up against my limited lisp knowledge. Both involve the class name: (defclass ,handler-class-name (handler) ()) (defmethod handle-request-response ((handler ,handler-class-name) method request) I shouldn't be passing in handler-class-name, since the code outside this macro has no reason to care about the name of the class. I should be generating the class name somehow. I can use the URL string for this. If my goal were to simply make another string that is based off the URL, that would be easy. I'm sure it will be the first step of any solution to my problem. Ultimately, I need the class name to be a symbol though, not a string. The places where I put ",handler-class-name" need to be symbols. That is why it looks like this when I call the macro: (publish-page jewelery-home "/home" `(html (head (title ,*title*)) (body ((h1 :align "center") "Hello Pip")))) jewelery-home is not quoted or stringified. It must be through some magic of DEFMACRO argument lists that I am able to use this uninterned symbol with no value in this way withoug a compiler error. Is there a way to turn a string into a symbol, or get a symbol representation of a string? If so, I could quote jewelery-home and treat it like a string. Or better yet, I could transform the URL into a class name using string handling functions. I looked at INTERN and FIND-SYMBOL as a way of converting a string to a symbol and back again. I'm guessing, however, that there is a common idiom for what I am trying to do, and I just need it to be brought to my attention. The question again, stated clearly this time: In lisp, how do you convert a string into a symbol and place it, unquoted, in a quoted list (as in a macro body)? Carlos ___________________________________________________________________________ Philadelphia Linux Users Group -- http://www.phillylinux.org Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce General Discussion -- http://lists.phillylinux.org/mailman/listinfo/plug
|
|