Peter Siebel - Practical Common Lisp

Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Practical Common Lisp: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать
Figure 269 httplocalhost2001showcookies after setting a cookie A - фото 19

Figure 26-9. http://localhost:2001/show-cookies after setting a cookie

A Small Application Framework

Although AllegroServe provides fairly straightforward access to all the basic facilities you need to write server-side Web code (access to query parameters from both the URL's query string and the post data; the ability to set cookies and retrieve their values; and, of course, the ability to generate the response sent back to the browser), there's a fair bit of annoyingly repetitive code.

For instance, every HTML-generating function you write is going to take the arguments requestand entityand then will contain calls to with-http-response, with-http-response, and—if you're going to use FOO to generate HTML— with-html-output. Then, in functions that need to get at query parameters, there will be a bunch of calls to request-query-valueand then more code to convert the string returned to whatever type you actually want. Finally, you need to remember to publishthe function.

To reduce the amount of boilerplate you have to write, you can write a small framework on top of AllegroServe to make it easier to define functions that handle requests for a particular URL.

The basic approach will be to define a macro, define-url-function, that you'll use to define functions that will automatically be published via publish. This macro will expand into a DEFUN that contains the appropriate boilerplate as well as code to publish the function under a URL of the same name. It'll also take care of generating code to extract values from query parameters and cookies and to bind them to variables declared in the function's parameter list. Thus, the basic form of a define-url-functiondefinition is this:

(define-url-function name ( request query-parameter *)

body )

where the body is the code to emit the HTML of the page. It'll be wrapped in a call to FOO's htmlmacro, so for simple pages it might contain nothing but s-expression HTML.

Within the body, the query parameter variables will be bound to values of query parameters with the same name or from a cookie. In the simplest case, a query parameter's value will be the string taken from the query parameter or post data field of the same name. If the query parameter is specified with a list, you can also specify an automatic type conversion, a default value, and whether to look for and save the value of the parameter in a cookie. The complete syntax for a query-parameter is as follows:

name | ( name type [ default-value ] [ stickiness ])

The type must be a name recognized by define-url-function. I'll discuss in a moment how to define new types. The default-value must be a value of the given type. Finally, stickiness , if supplied, indicates that the parameter's value should be taken from an appropriately named cookie if no query parameter is supplied and that a Set-Cookie header should be sent in the response that saves the value in the cookie of the same name. Thus, a sticky parameter, after being explicitly supplied a value via a query parameter, will keep that value on subsequent requests of the page even when no query parameter is supplied.

The name of the cookie used depends on the value of stickiness : with a value of :global, the cookie will be named the same as the parameter. Thus, different functions that use globally sticky parameters with the same name will share the value. If stickiness is :package, then the cookie name is constructed from the name of the parameter and the package of the function's name; this allows functions in the same package to share values but not have to worry about stomping on parameters of functions in other packages. Finally, a parameter with a stickiness value of :localwill use a cookie made from the name of the parameter, the package of the function name, and the function name, making it unique to that function.

For instance, you can use define-url-functionto replace the previous eleven-line definition of random-pagewith this five-line version:

(define-url-function random-number (request (limit integer 1000))

(:html

(:head (:title "Random"))

(:body

(:p "Random number: " (:print (random limit))))))

If you wanted the limit argument to be sticky, you could change the limit declaration to (limit integer 1000 :local).

The Implementation

I'll explain the implementation of define-url-functionfrom the top down. The macro itself looks like this:

(defmacro define-url-function (name (request &rest params) &body body)

(with-gensyms (entity)

(let ((params (mapcar #'normalize-param params)))

`(progn

(defun ,name (,request ,entity)

(with-http-response (,request ,entity :content-type "text/html")

(let* (,@(param-bindings name request params))

,@(set-cookies-code name request params)

(with-http-body (,request ,entity)

(with-html-output ((request-reply-stream ,request))

(html ,@body))))))

(publish :path ,(format nil "/~(~a~)" name) :function ',name)))))

Let's take it bit by bit, starting with the first few lines.

(defmacro define-url-function (name (request &rest params) &body body)

(with-gensyms (entity)

(let ((params (mapcar #'normalize-param params)))

Up to here you're just getting ready to generate code. You GENSYM a symbol to use later as the name of the entity parameter in the DEFUN . Then you normalize the parameters, converting plain symbols to list form using this function:

(defun normalize-param (param)

(etypecase param

(list param)

(symbol `(,param string nil nil))))

In other words, declaring a parameter with just a symbol is the same as declaring a nonsticky, string parameter with no default value.

Then comes the PROGN . You must expand into a PROGN because you need to generate code to do two things: define a function with DEFUN and call publish. You should define the function first so if there's an error in the definition, the function won't be published. The first two lines of the DEFUN are just boilerplate.

(defun ,name (,request ,entity)

(with-http-response (,request ,entity :content-type "text/html")

Now you do the real work. The following two lines generate the bindings for the parameters specified in define-url-functionother than requestand the code that calls set-cookie-headerfor the sticky parameters. Of course, the real work is done by helper functions that you'll look at in a moment. [291] You need to use LET* rather than a LET to allow the default value forms for parameters to refer to parameters that appear earlier in the parameter list. For example, you could write this: (define-url-function (request (x integer 10) (y integer (* 2 x))) ...) and the value of y , if not explicitly supplied, would be twice the value of x .

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Practical Common Lisp»

Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Practical Common Lisp»

Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x