<html><head><style type="text/css"><!-- DIV {margin:0px;} --></style></head><body><div style="font-family:times new roman, new york, times, serif;font-size:12pt"><div>Hello all,<br><br>I propose that the types for easy-handlers be extensible by the users. I have pieces of markup which are used throughout our site which collect information from several fields into a class (in our case tied to a database with clsql). The names of the fields are related, but diffierent from the lists, arrays and hashes of the easy-handlers, Dates and addresses are two good examples, but there are others. I would like to be able to teach the easy handler to collect these for me and pass them as parameters. This cannot be done with functions as the :parameter-type because the functions passed as :parameter-type do not take the parameter name.<br><br>There are two ways I think this could be done:<br><br>- The easier way: add a :paramater-reader arg to the parameter
description, and if passed use it in lieu of the ((post|get)-)?parameter functions in compute-parameter. The following might do it (untested):<br><br>(defun compute-parameter (parameter-name parameter-type request-type <br> &optional parameter-reader) ; <=====<br> "Computes and returns the parameter\(s) called PARAMETER-NAME<br>and converts it/them according to the value of PARAMETER-TYPE.<br>REQUEST-TYPE is one of :GET, :POST, or :BOTH."<br> (when (member parameter-type '(list array hash-table))<br> (setq parameter-type (list parameter-type 'string)))<br> (let ((parameter-reader (or parameter-reader ;
<====<br> (ecase request-type<br> (:get #'get-parameter)<br> (:post #'post-parameter)<br> (:both #'parameter))) )<br> (parameters (and (listp
parameter-type)<br> (case request-type<br> (:get (get-parameters))<br> (:post (post-parameters))<br> (:both (append (get-parameters) (post-parameters)))))))<br> (cond ((atom parameter-type)<br> (compute-simple-parameter parameter-name parameter-type
parameter-reader))<br> ((and (null (cddr parameter-type))<br> (eq (first parameter-type) 'list))<br> (compute-list-parameter parameter-name (second parameter-type) parameters))<br> ((and (null (cddr parameter-type))<br> (eq (first parameter-type) 'array))<br> (compute-array-parameter parameter-name (second parameter-type) parameters))<br> ((and (null (cddddr parameter-type))<br> (eq (first parameter-type)
'hash-table))<br> (compute-hash-table-parameter parameter-name (second parameter-type) parameters<br> (or (third parameter-type) 'string)<br> (or (fourth parameter-type) 'equal)))<br> (t (error "Don't know what to do with parameter type ~S." parameter-type)))))<br><br>(defun make-defun-parameter (description default-parameter-type default-request-type)<br> "Creates a keyword parameter
to be used by DEFINE-EASY-HANDLER.<br>DESCRIPTION is one of the elements of DEFINE-EASY-HANDLER's<br>LAMBDA-LIST and DEFAULT-PARAMETER-TYPE and DEFAULT-REQUEST-TYPE<br>are the global default values."<br> (when (atom description)<br> (setq description (list description)))<br> (destructuring-bind (parameter-name &key (real-name (compute-real-name parameter-name))<br> parameter-type init-form request-type parameter-reader ) ; <====<br> description<br> `(,parameter-name (or (and (boundp
'*request*)<br> (compute-parameter ,real-name<br> ,(or parameter-type default-parameter-type)<br> ,(or request-type
default-request-type)))<br> ,init-form))))<br><br>(This just occurred to me: request-type could be a function, with an obvious change to the ecase. This is a little more confusing but consistent with what parameter-type does---so it has the force of precedent---and requires a smaller change to the code.).<br><br>- The extensive way: Change the cond in compute-parameter to a switch via a hash table, whose values are the conversion handlers (or a cons with reader and converter). It may need two hash tables: one for simple type names (type is a symbol) and one for aggregates, (type is a cons, and switch on the first element). Create a macro, define-easy-type, or something, to populate the tables, and use it within easy-handlers.lisp to populate it with those which are now hardcoded in the cond
and case switches. Users can then use the macro to define their own types.<br><br>- Another way: like above, but use methods instead of hash tables. This seems possible, but I'd have to think some more about it.<br><br><br>BTW: why the checks for null CDDRs and CDDDDRs in compute-parameter? Is this just nice, or are they essential?<br><br>If your interested in the second, I will work something up and send in a patch. I do not think it would break any existing code which did not peak too far into the easy-handlers stuff.<br><br>Let me know what you think.<br><br>Tim S<br><br>P.S.:<br>Hunchentoot is a pleasure to work with!<br> </div></div></body></html>