fb50e621 |
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
2 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
3 | <html xmlns="http://www.w3.org/1999/xhtml" |
4 | lang="en" xml:lang="en"> |
5 | <head> |
6 | <title>Lisp on Lines : The Missing Manual.</title> |
7 | <meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/> |
8 | <meta name="generator" content="Org-mode"/> |
9 | <meta name="generated" content="2009/07/27 01:46:25 PM"/> |
10 | <meta name="author" content="Drew Crampsie"/> |
11 | <style type="text/css"> |
12 | html { |
13 | font-family: Times, serif; |
14 | font-size: 12pt; |
15 | } |
16 | .title { text-align: center; } |
17 | .todo { color: red; } |
18 | .done { color: green; } |
19 | .timestamp { color: grey } |
20 | .timestamp-kwd { color: CadetBlue } |
21 | .tag { background-color:lightblue; font-weight:normal } |
22 | .target { } |
23 | pre { |
24 | border: 1pt solid #AEBDCC; |
25 | background-color: #F3F5F7; |
26 | padding: 5pt; |
27 | font-family: courier, monospace; |
28 | font-size: 90%; |
29 | } |
30 | table { border-collapse: collapse; } |
31 | td, th { |
32 | vertical-align: top; |
33 | <!--border: 1pt solid #ADB9CC;--> |
34 | } |
35 | dt { font-weight: bold; } |
36 | </style> |
37 | </head><body> |
38 | <h1 class="title">Lisp on Lines : The Missing Manual.</h1> |
39 | <i>Abstract</i>: Lisp on Lines is a Common Lisp based framework for rapid |
40 | development of data-driven applications. It is particularly useful |
41 | for producing Web based applications, but is also useful elsewhere. |
42 | |
43 | |
44 | |
45 | <div id="table-of-contents"> |
46 | <h2>Table of Contents</h2> |
47 | <div id="text-table-of-contents"> |
48 | <ul> |
49 | <li><a href="#sec-1">1 Introduction</a></li> |
50 | <li><a href="#sec-2">2 Installation</a></li> |
51 | <li><a href="#sec-3">3 Describing the domain with the MAO protocol.</a> |
52 | <ul> |
53 | <li><a href="#sec-3.1">3.1 Descriptions</a></li> |
54 | <li><a href="#sec-3.2">3.2 Attributes and Properties</a></li> |
55 | <li><a href="#sec-3.3">3.3 Contexts</a></li> |
56 | </ul> |
57 | </li> |
58 | <li><a href="#sec-4">4 Defining and Using Descriptions</a> |
59 | <ul> |
60 | <li><a href="#sec-4.1">4.1 Defining a simple description </a></li> |
61 | <li><a href="#sec-4.2">4.2 Using descriptions as and with contexts.</a></li> |
62 | <li><a href="#sec-4.3">4.3 T : The root of all descriptions.</a></li> |
63 | <li><a href="#sec-4.4">4.4 DESCRIPTION-OF : Permanently Associate a description with a class.</a></li> |
64 | </ul> |
65 | </li> |
66 | <li><a href="#sec-5">5 The DISPLAY Protocol</a></li> |
67 | <li><a href="#sec-6">6 Automatic Descriptions for CLOS classes.</a> |
68 | <ul> |
69 | <li><a href="#sec-6.1">6.1 Described CLOS objects an the EDITABLE description</a></li> |
70 | <li><a href="#sec-6.2">6.2 Extending the generated description</a></li> |
71 | </ul> |
72 | </li> |
73 | <li><a href="#sec-7">7 Using Lisp-on-Lines for the Web.</a></li> |
74 | </ul> |
75 | </div> |
76 | </div> |
77 | |
78 | <div id="outline-container-1" class="outline-2"> |
79 | <h2 id="sec-1">1 Introduction</h2> |
80 | <div id="text-1"> |
81 | |
82 | |
83 | <p> |
84 | Lisp on Lines (LoL) is a framework for rapid development of data-driven |
85 | applications, with a particular focus on web-based applications. It |
86 | builds on the UncommonWeb engine and Contextl, and uses CLOS and the |
87 | MOP extensively. Most of LoL can be used both at the REPL and through |
88 | the browser, offering many options for development and testing. |
89 | </p> |
90 | <p> |
91 | While the target audience for LoL is developers experienced with both |
92 | web technologies and common lisp, a good programmer with a little |
93 | experience in either should be able to pick things up fairly quickly. |
94 | </p> |
95 | </div> |
96 | |
97 | </div> |
98 | |
99 | <div id="outline-container-2" class="outline-2"> |
100 | <h2 id="sec-2">2 Installation</h2> |
101 | <div id="text-2"> |
102 | |
103 | |
104 | <p> |
105 | LoL has a load of dependencies, which themselves depend on others, |
106 | etc. The best way to deal with this is to use <a href="http://common-lisp.net/project/clbuild/">clbuild</a>, a library |
107 | management tool. |
108 | </p> |
109 | <p> |
110 | If you'd prefer to manage your libraries manually, the dependencies, |
111 | according to clbuild, are : |
112 | </p> |
113 | <p> |
114 | alexandria arnesi bordeaux-threads cl-base64 cl-fad cl-mime cl-ppcre |
115 | cl-qprint closer-mop contextl iterate lift local-time lw-compat |
116 | net-telent-date parenscript parse-number portable-threads puri rfc2109 |
117 | slime split-sequence trivial-garbage ucw usocket yaclml |
118 | </p> |
119 | <p> |
120 | All libraries should be installed from version control where available. |
121 | </p> |
122 | </div> |
123 | |
124 | </div> |
125 | |
126 | <div id="outline-container-3" class="outline-2"> |
127 | <h2 id="sec-3">3 Describing the domain with the MAO protocol.</h2> |
128 | <div id="text-3"> |
129 | |
130 | |
131 | <p> |
132 | LoL uses a protocol it calls Meta-Attributed Objects, or MAO, as the |
133 | basis of its display mechanism. In MAO, we create context-aware |
134 | DESCRIPTIONs of objects, and those descriptions are used to generate |
135 | the display of the object itself. By having these external |
136 | descriptions change based on the context in which they are used, a few |
137 | generic components can come together to create complex interfaces. |
138 | </p> |
139 | |
140 | </div> |
141 | |
142 | <div id="outline-container-3.1" class="outline-3"> |
143 | <h3 id="sec-3.1">3.1 Descriptions</h3> |
144 | <div id="text-3.1"> |
145 | |
146 | <p>Descriptions are a similar conceptually to classes. Every Lisp object |
147 | has one, and the root description that all descriptions inherit from |
148 | is known as T. FIND-DESCRIPTION is used to, well, find descriptions. |
149 | </p> |
150 | |
151 | |
152 | <pre class="src"> (find-description t) |
153 | => #<DESCRIPTION T {B7B9861}> |
154 | </pre> |
155 | |
156 | |
157 | </div> |
158 | |
159 | </div> |
160 | |
161 | <div id="outline-container-3.2" class="outline-3"> |
162 | <h3 id="sec-3.2">3.2 Attributes and Properties</h3> |
163 | <div id="text-3.2"> |
164 | |
165 | <p>A description is a collection of ATTRIBUTEs, among other things. Each |
166 | attribute describes a part of an object, and any number of attributes |
167 | may or may not be active. The ATTRIBUTES function is used to find a |
168 | the list attributes that are both active and applicable in the current |
169 | context. |
170 | </p> |
171 | |
172 | |
173 | <pre class="src">(attributes (find-description t)) |
174 | =>(#<ATTRIBUTE IDENTITY {BBC9691}> |
175 | #<ATTRIBUTE TYPE {BBC96A1}> |
176 | #<ATTRIBUTE CLASS {BBC96B1}>) |
177 | </pre> |
178 | |
179 | |
180 | <p> |
181 | The functions DESCRIPTION-ATTRIBUTES, DESCRIPTION-ACTIVE-ATTRIBUTES |
182 | and DESCRIPTION-CURRENT-ATTRIBUTES return all the descriptions |
183 | attributes, Attributes that are currently active regardless of |
184 | context, and attributes that exist in the current context but may or |
185 | may not be active, respectively. |
186 | </p> |
187 | <p> |
188 | Attributes have properties, for example ATTRIBUTE-LABEL and |
189 | ATTRIBUTE-VALUE. By simply iterating through the attributes of a |
190 | described object, we can create a generic display for any lisp |
191 | object. This is very similar, and was inspired by the technique |
192 | outlined by Adrian Lienhard in <a href="http://www.adrian-lienhard.ch/files/mewa.pdf">MEWA: A Meta-level Architecture for Generic Web-Application Construction_</a>. |
193 | </p> |
194 | |
195 | <p> |
196 | For attribute properties to be useful, the description must be |
197 | associated with the object it is meant to describe. |
198 | </p> |
199 | <p> |
200 | The function FUNCALL-WITH-DESCRIBED-OBJECT takes care of setting up |
201 | the proper context. There is some syntax for it in the form of |
202 | WITH-DESCRIBED-OBJECT : |
203 | </p> |
204 | |
205 | |
206 | <pre class="src"> |
207 | (<span style="color: #a020f0;">let</span> ((description (find-description t)) |
208 | (object <span style="color: #bc8f8f;">"Hello World"</span>)) |
209 | (<span style="color: #a020f0;">with-described-object</span> (object description) |
210 | (<span style="color: #a020f0;">dolist</span> (a (attributes description)) |
211 | (format t <span style="color: #bc8f8f;">"~@[~A: ~]~A~%"</span> |
212 | (attribute-label a) |
213 | (attribute-value a))))) |
214 | => |
215 | Hello World |
216 | Type: (SIMPLE-ARRAY CHARACTER (11)) |
217 | Class: #<BUILT-IN-CLASS SB-KERNEL::SIMPLE-CHARACTER-STRING> |
218 | |
219 | NIL |
220 | </pre> |
221 | |
222 | |
223 | <p> |
224 | FUNCALL-WITH-DESCRIBED-OBJECT binds two specials, <b>DESCRIPTION</b> and |
225 | <b>OBJECT</b>, to its arguments. Knowing this, we can shorten our code |
226 | somewhat. Later on we'll be far away from the lexical bindings of |
227 | description and object, so these special variables are essential. |
228 | </p> |
229 | <p> |
230 | Another reason for the <b>description</b> variable is that |
231 | WITH-DESCRIBED-OBJECT will use DESCRIPTION-OF to determine the |
232 | description if the DESCRIPTION argument is NIL |
233 | </p> |
234 | |
235 | |
236 | <pre class="src">(<span style="color: #a020f0;">with-described-object</span> (<span style="color: #bc8f8f;">"Hello World"</span> nil) |
237 | (<span style="color: #a020f0;">dolist</span> (a (attributes *description*)) |
238 | (format t <span style="color: #bc8f8f;">"~@[~A: ~]~A~%"</span> |
239 | (attribute-label a) |
240 | (attribute-value a)))) |
241 | |
242 | Lets wrap that up in a function that we can re-use. LoL includes an |
243 | entire DISPLAY mechanism that is slightly more involved, but this |
244 | serves as an excellent example with not bogging us down in details. |
245 | |
246 | <span style="color: #b22222;">#+BEGIN_SRC lisp</span> |
247 | (<span style="color: #a020f0;">defun</span> <span style="color: #0000ff;">present</span> (object <span style="color: #228b22;">&optional</span> description) |
248 | (<span style="color: #a020f0;">with-described-object</span> (object description) |
249 | (<span style="color: #a020f0;">dolist</span> (a (attributes *description*)) |
250 | (format t <span style="color: #bc8f8f;">"~@[~A: ~]~A~%"</span> |
251 | (attribute-label a) |
252 | (attribute-value a))))) |
253 | </pre> |
254 | |
255 | |
256 | </div> |
257 | |
258 | </div> |
259 | |
260 | <div id="outline-container-3.3" class="outline-3"> |
261 | <h3 id="sec-3.3">3.3 Contexts</h3> |
262 | <div id="text-3.3"> |
263 | |
264 | |
265 | <p> |
266 | MAO adds to MEWA the concept of dynamic context. By changing the |
267 | context in which an object is described, we combine and specialize the |
268 | generic displays, ultimately creating different views of our |
269 | objects. LoL uses ContextL extensively. Descriptions are contextl |
270 | layers, and attributes themselves are layered classes. Most of the |
271 | exported functions are layered methods, and the idea of dynamic |
272 | context-sensitivity is used throughout LoL. If you're not familiar |
273 | with contextl, don't worry, LoL mostly stands on its own. Still, |
274 | reading through the material on contextl won't hurt. |
275 | </p> |
276 | <p> |
277 | Descriptions may have different attributes dependant on what |
278 | description contexts (or layers) are currently active. Attributes |
279 | themselves might have different properties. |
280 | </p> |
281 | <p> |
282 | When an object is being described (using WITH-DESCRIBED-OBJECT), it is |
283 | also activated as a layer context. One can also activate/deactivate |
284 | contexts manually, using WITH-ACTIVE-DESCRIPTIONS and |
285 | WITH-INACTIVE-DESCRIPTIONS. |
286 | </p> |
287 | <p> |
288 | Hopefully a little code will make this more clear : |
289 | </p> |
290 | |
291 | |
292 | <pre class="src">(present <span style="color: #bc8f8f;">"Hello World"</span>) |
293 | => |
294 | Hello World |
295 | Type: (SIMPLE-ARRAY CHARACTER (11)) |
296 | Class: #<BUILT-IN-CLASS SB-KERNEL::SIMPLE-CHARACTER-STRING> |
297 | Simple character string |
298 | |
299 | <span style="color: #b22222;">;; </span><span style="color: #b22222;">Now we'll activate a built-in description, INLINE. |
300 | </span> |
301 | (<span style="color: #a020f0;">with-active-descriptions</span> (<span style="color: #a020f0;">inline</span>) |
302 | (present <span style="color: #bc8f8f;">"Hello World"</span>)) |
303 | => |
304 | Hello World |
305 | </pre> |
306 | |
307 | |
308 | <p> |
309 | You can see that the behavior of PRESENT changed when the INLINE |
310 | context was activated. This is the key innovation that makes LoL so |
311 | useful. In the next chapter we'll create our own descriptions and |
312 | demonstrate this further. |
313 | </p> |
314 | </div> |
315 | </div> |
316 | |
317 | </div> |
318 | |
319 | <div id="outline-container-4" class="outline-2"> |
320 | <h2 id="sec-4">4 Defining and Using Descriptions</h2> |
321 | <div id="text-4"> |
322 | |
323 | |
324 | |
325 | </div> |
326 | |
327 | <div id="outline-container-4.1" class="outline-3"> |
328 | <h3 id="sec-4.1">4.1 Defining a simple description </h3> |
329 | <div id="text-4.1"> |
330 | |
331 | <p>The basics of the MAO should now (hopefully) be clear, so lets start |
332 | using it. First, we'll create our very own description. |
333 | </p> |
334 | |
335 | |
336 | <pre class="src">(<span style="color: #a020f0;">define-description</span> hello-world () |
337 | ((title <span style="color: #da70d6;">:value</span> <span style="color: #bc8f8f;">"Lisp on Lines Demo"</span>) |
338 | (identity <span style="color: #da70d6;">:label</span> <span style="color: #bc8f8f;">"Message"</span>) |
339 | (length <span style="color: #da70d6;">:label</span> <span style="color: #bc8f8f;">"Length"</span> <span style="color: #da70d6;">:function</span> #'length) |
340 | (active-attributes <span style="color: #da70d6;">:value</span> '(title identity length)))) |
341 | </pre> |
342 | |
343 | |
344 | <p> |
345 | Descriptions are defined very much like CLOS classes, and are in fact |
346 | implemented that way, inheritance rules apply. The object returned |
347 | from FIND-DESCRIPTION is best described as a prototype-based |
348 | singleton. In other words, there is only one instance, and it inherits |
349 | attributes and properties from further up its hierarchy unless |
350 | specifically overridden. |
351 | </p> |
352 | <p> |
353 | Attributes can have any number of properties, (see the class |
354 | STANDARD-ATTRIBUTE), but the three most important are accessed via the |
355 | methods ATTRIBUTE-LABEL, ATTRIBUTE-VALUE and ATTRIBUTE-FUNCTION,and |
356 | named (in DEFINE-DESCRIPTION forms and elsewhere) |
357 | by the :label, :value, and :function keywords. |
358 | </p> |
359 | <p> |
360 | ATTRIBUTE-LABEL is simply a textual label that describes the |
361 | attribute. ATTRIBUTE-VALUE is defined to return the result of calling |
362 | ATTRIBUTE-FUNCTION with the object as its argument. If |
363 | ATTRIBUTE-FUNCTION is NIL, the value of the :value property is returned |
364 | directly. |
365 | </p> |
366 | <p> |
367 | In the example above, the IDENTITY and ACTIVE-ATTRIBUTES attributes |
368 | are inherited from T, and we are simply overriding the default |
369 | properties for our description. LENGTH and TITLE are specific to this |
370 | description. A look at src/standard-descriptions/t.lisp may be |
371 | instructive at this point. |
372 | </p> |
373 | <p> |
374 | Now, we can present our object using our new description. |
375 | </p> |
376 | |
377 | |
378 | <pre class="src">(present <span style="color: #bc8f8f;">"Hello World"</span> (find-description 'hello-world)) |
379 | => |
380 | Lisp on Lines Demo |
381 | Message: Hello World |
382 | Length: 11 |
383 | |
384 | NIL |
385 | </pre> |
386 | |
387 | |
388 | </div> |
389 | |
390 | </div> |
391 | |
392 | <div id="outline-container-4.2" class="outline-3"> |
393 | <h3 id="sec-4.2">4.2 Using descriptions as and with contexts.</h3> |
394 | <div id="text-4.2"> |
395 | |
396 | |
397 | <p> |
398 | A we mentioned earlier, when an object is being described, the |
399 | 'description context' is also made active. On top of that, one can |
400 | define partial descriptions that are only active when other |
401 | description contexts have been activated. |
402 | </p> |
403 | <p> |
404 | We'll make a ONE-LINE description similar to the INLINE description |
405 | demonstrated earlier. |
406 | </p> |
407 | |
408 | |
409 | <pre class="src">(<span style="color: #a020f0;">define-description</span> one-line ()) |
410 | |
411 | (<span style="color: #a020f0;">define-description</span> hello-world () |
412 | ((identity <span style="color: #da70d6;">:label</span> nil) |
413 | (active-attributes <span style="color: #da70d6;">:value</span> '(identity))) |
414 | (<span style="color: #da70d6;">:in-description</span> one-line)) |
415 | |
416 | </pre> |
417 | |
418 | |
419 | <p> |
420 | Here we've defined a new description, ONE-LINE, and a |
421 | context-sensitive extension to our HELLO-WORLD description. This |
422 | partial desription will be active only when in the context of a |
423 | one-line description. One can have attributes that only exist in |
424 | certain description contexts, and attributes can have different |
425 | properties. |
426 | </p> |
427 | |
428 | |
429 | <pre class="src">(<span style="color: #a020f0;">let</span> ((message <span style="color: #bc8f8f;">"Hello World!"</span>) |
430 | (description (find-description 'hello-world))) |
431 | (print <span style="color: #da70d6;">:normal</span>)(terpri) |
432 | (present message description) |
433 | (print <span style="color: #da70d6;">:one-line</span>)(terpri) |
434 | (<span style="color: #a020f0;">with-active-descriptions</span> (one-line) |
435 | (present message description))) |
436 | => |
437 | <span style="color: #da70d6;">:NORMAL</span> |
438 | Lisp on Lines Demo |
439 | Message: Hello World! |
440 | Length: 12 |
441 | |
442 | <span style="color: #da70d6;">:ONE-LINE</span> |
443 | Hello World! |
444 | |
445 | NIL |
446 | </pre> |
447 | |
448 | |
449 | <p> |
450 | By activating the description ONE-LINE, we've changed the context in |
451 | which our object is displayed. We can create any number of |
452 | descriptions and contexts and activate/deactivate them in any order. |
453 | </p> |
454 | <p> |
455 | Descriptions are implemented as ContextL 'layers', so if all |
456 | this seems weird, reading the ContextL papers might help. |
457 | </p> |
458 | </div> |
459 | |
460 | </div> |
461 | |
462 | <div id="outline-container-4.3" class="outline-3"> |
463 | <h3 id="sec-4.3">4.3 T : The root of all descriptions.</h3> |
464 | <div id="text-4.3"> |
465 | |
466 | |
467 | <p> |
468 | Because all descriptions inherit from T, we can define contexts for T |
469 | and they will apply to every description. The INLINE description can |
470 | be found in standard-descriptions/inline.lisp, where we define |
471 | a desription for T in the context of the INLINE description : |
472 | </p> |
473 | |
474 | |
475 | <pre class="src"><span style="color: #b22222;">;; </span><span style="color: #b22222;">Defined by LoL in inline.lisp : |
476 | </span>(<span style="color: #a020f0;">define-description</span> t () |
477 | ((identity <span style="color: #da70d6;">:label</span> nil) |
478 | (active-attributes <span style="color: #da70d6;">:value</span> '(identity)) |
479 | (attribute-delimiter <span style="color: #da70d6;">:value</span> <span style="color: #bc8f8f;">", "</span>) |
480 | (label-formatter <span style="color: #da70d6;">:value</span> (curry #'format nil <span style="color: #bc8f8f;">"~A: "</span>)) |
481 | (value-formatter <span style="color: #da70d6;">:value</span> (curry #'format nil <span style="color: #bc8f8f;">"~A"</span>))) |
482 | (<span style="color: #da70d6;">:in-description</span> inline))} |
483 | |
484 | </pre> |
485 | |
486 | |
487 | <p> |
488 | The does for the LoL DISPLAY mechanism what ONE-LINE did for PRESENT, |
489 | only with more magic. By exetending T in this way, it's easy to create |
490 | contexts the redefine the behavior of LoL while still reusing the basics. |
491 | </p> |
492 | </div> |
493 | |
494 | </div> |
495 | |
496 | <div id="outline-container-4.4" class="outline-3"> |
497 | <h3 id="sec-4.4">4.4 DESCRIPTION-OF : Permanently Associate a description with a class.</h3> |
498 | <div id="text-4.4"> |
499 | |
500 | |
501 | <p> |
502 | The LAYERED-FUNCTION DESCRIPTION-OF will return the description |
503 | associated with an object. |
504 | </p> |
505 | |
506 | |
507 | <pre class="src"> |
508 | (description-of nil) |
509 | => |
510 | #<DESCRIPTION NULL {AA04F49}> |
511 | |
512 | (description-of t) |
513 | => |
514 | #<DESCRIPTION SYMBOL {AA04541}> |
515 | |
516 | (description-of '(1 2 3)) |
517 | => |
518 | #<DESCRIPTION CONS {AA04C29}> |
519 | |
520 | <span style="color: #b22222;">;;</span><span style="color: #b22222;">etc |
521 | </span> |
522 | </pre> |
523 | |
524 | |
525 | </div> |
526 | </div> |
527 | |
528 | </div> |
529 | |
530 | <div id="outline-container-5" class="outline-2"> |
531 | <h2 id="sec-5">5 The DISPLAY Protocol</h2> |
532 | <div id="text-5"> |
533 | |
534 | |
535 | <p> |
536 | Our function, PRESENT, is very basic, though pretty powerful when |
537 | combined with descriptions and contexts. LoL includes a superset of |
538 | such functionality built-in. |
539 | </p> |
540 | <p> |
541 | The main entry point into this protocol is the DISPLAY |
542 | function. The signature for this functions is : |
543 | </p> |
544 | |
545 | |
546 | <pre class="src">(display DISPLAY OBJECT <span style="color: #228b22;">&REST</span> ARGS <span style="color: #228b22;">&KEY</span> DEACTIVATE ACTIVATE <span style="color: #228b22;">&ALLOW-OTHER-KEYS</span>) |
547 | </pre> |
548 | |
549 | |
550 | <p> |
551 | The first argument, DISPLAY, is the place where we will display |
552 | to/on/in/with. It could be a stream, a UCW component, a CLIM gadget, |
553 | or anything else you might want to use. |
554 | </p> |
555 | <p> |
556 | One can specialize on this argument (though it's better to specialize |
557 | DISPLAY-USING-DESCRIPTION… more on that later) to use generic |
558 | descriptions to display objects in different environments. |
559 | </p> |
560 | <p> |
561 | The second argument is simply the object to be displayed. Here's a |
562 | simple example : |
563 | </p> |
564 | |
565 | |
566 | <pre class="src">(display t t) |
567 | => |
568 | T |
569 | Type:BOOLEAN |
570 | Class:#<BUILT-IN-CLASS SYMBOL> |
571 | Symbol |
572 | Name:T |
573 | Value:T |
574 | Package:#<PACKAGE <span style="color: #bc8f8f;">"COMMON-LISP"</span>> |
575 | Function:<UNBOUND> |
576 | <span style="color: #b22222;">; </span><span style="color: #b22222;">No value |
577 | </span></pre> |
578 | |
579 | |
580 | <p> |
581 | The two arguments specified in the lambda-list, ACTIVATE and |
582 | DEACTIVATE, are used to activate and deactivate description contexts in |
583 | the scope of the display function. |
584 | </p> |
585 | |
586 | |
587 | <pre class="src"> |
588 | (display nil t <span style="color: #da70d6;">:activate</span> '(<span style="color: #a020f0;">inline</span>)) |
589 | => |
590 | <span style="color: #bc8f8f;">"t"</span> |
591 | (<span style="color: #a020f0;">with-active-descriptions</span> (<span style="color: #a020f0;">inline</span>) |
592 | (display nil t <span style="color: #da70d6;">:deactivate</span> '(<span style="color: #a020f0;">inline</span>))) |
593 | => |
594 | <span style="color: #bc8f8f;">"T |
595 | Type:BOOLEAN |
596 | Class:#<BUILT-IN-CLASS SYMBOL> |
597 | Symbol |
598 | Name:T |
599 | Value:T |
600 | Package:#<PACKAGE \"COMMON-LISP\"> |
601 | Function:<UNBOUND>"</span> |
602 | |
603 | </pre> |
604 | |
605 | |
606 | <p> |
607 | Any other keyword arguments passed will be used to set the value of an |
608 | attribute with a :keyword property, in the dynamic context of the |
609 | DISPLAY function call. Once such attribute, and a very useful one is |
610 | ACTIVE-ATTRIBUTES with its :attributes keyword : |
611 | </p> |
612 | |
613 | |
614 | <pre class="src"> |
615 | (display t t <span style="color: #da70d6;">:attributes</span> '(class package)) |
616 | => |
617 | Class:#<BUILT-IN-CLASS SYMBOL> |
618 | Package:#<PACKAGE <span style="color: #bc8f8f;">"COMMON-LISP"</span>> |
619 | |
620 | </pre> |
621 | |
622 | |
623 | <p> |
624 | The properties of attributes that do not have a :keyword property can |
625 | also be set dynamically. Since :attributes is the :keyword property of |
626 | the ACTIVE-ATTRIBUTES attribute, the following form is equivalent to |
627 | the previous : |
628 | </p> |
629 | |
630 | |
631 | <pre class="src">(display t t <span style="color: #da70d6;">:attributes</span> '((active-attributes |
632 | <span style="color: #da70d6;">:value</span> (class package)))) |
633 | => |
634 | Class:#<BUILT-IN-CLASS SYMBOL> |
635 | Package:#<PACKAGE <span style="color: #bc8f8f;">"COMMON-LISP"</span>> |
636 | </pre> |
637 | |
638 | |
639 | <p> |
640 | Setting the attributes this way is almost like creating an anonymous |
641 | description context… you can express just about anything you would |
642 | in a DEFINE-DESCRIPTION. Here's a more involved example : |
643 | </p> |
644 | |
645 | |
646 | <pre class="src">(display t t <span style="color: #da70d6;">:attributes</span> `((identity <span style="color: #da70d6;">:label</span> <span style="color: #bc8f8f;">"The Object"</span>) |
647 | (class <span style="color: #da70d6;">:label</span> <span style="color: #bc8f8f;">"CLOS Class"</span>) |
648 | (package <span style="color: #da70d6;">:value</span> <span style="color: #bc8f8f;">"COMMON LISP"</span> <span style="color: #da70d6;">:function</span> nil) |
649 | (type <span style="color: #da70d6;">:value-formatter</span> |
650 | ,(<span style="color: #a020f0;">lambda</span> (a) |
651 | (format nil <span style="color: #bc8f8f;">"Got a value? ~A"</span> a))))) |
652 | => |
653 | |
654 | The Object:T |
655 | CLOS Class:#<BUILT-IN-CLASS SYMBOL> |
656 | Package:COMMON LISP |
657 | Type:Got a value? BOOLEAN |
658 | |
659 | </pre> |
660 | |
661 | |
662 | <p> |
663 | I hope that serves well to demonstrate the concepts behind LoL, as |
664 | there is no API documentation available at the moment… use the |
665 | source luke! |
666 | </p> |
667 | |
668 | </div> |
669 | |
670 | </div> |
671 | |
672 | <div id="outline-container-6" class="outline-2"> |
673 | <h2 id="sec-6">6 Automatic Descriptions for CLOS classes.</h2> |
674 | <div id="text-6"> |
675 | |
676 | |
677 | <p> |
678 | Lisp-on-Lines includes a compose-able metaclass, DESCRIBED-CLASS. It |
679 | can be combined with <u>any</u> other metaclass without affecting the |
680 | behavior of that class. DESCRIBED-CLASS has been used with the |
681 | metaclasses provided by CLSQL, ROFL, Rucksack and UCW simply by |
682 | defining a class that inherits from both metaclasses. |
683 | </p> |
684 | <p> |
685 | DESCRIBED-CLASS creates a base description for the class, named |
686 | DESCRIPTION-FOR-<class>, and another description with the same name |
687 | as the class that has the previous description as a superclass. The |
688 | then defines a method on DESCRIPTION-OF that returns the second |
689 | description. |
690 | </p> |
691 | <p> |
692 | LoL includes DESCRIBED-STANDARD-CLASS, which is subclass of |
693 | STANDARD-CLASS and DESCRIBED-CLASS. We'll use this to create a class |
694 | and its description. |
695 | </p> |
696 | |
697 | |
698 | <pre class="src"> |
699 | (<span style="color: #a020f0;">defclass</span> <span style="color: #228b22;">person</span> () |
700 | (first-name last-name company-name |
701 | date-of-birth phone fax email |
702 | address city province postal-code) |
703 | (<span style="color: #da70d6;">:metaclass</span> described-standard-class)) |
704 | => |
705 | #<DESCRIBED-STANDARD-CLASS PERSON> |
706 | |
707 | (display t (make-instance 'person)) |
708 | => |
709 | First name:#<UNBOUND> |
710 | Last name:#<UNBOUND> |
711 | Company name:#<UNBOUND> |
712 | Date of birth:#<UNBOUND> |
713 | Phone:#<UNBOUND> |
714 | Fax:#<UNBOUND> |
715 | Email:#<UNBOUND> |
716 | Address:#<UNBOUND> |
717 | City:#<UNBOUND> |
718 | Province:#<UNBOUND> |
719 | Postal code:#<UNBOUND> |
720 | |
721 | </pre> |
722 | |
723 | |
724 | |
725 | </div> |
726 | |
727 | <div id="outline-container-6.1" class="outline-3"> |
728 | <h3 id="sec-6.1">6.1 Described CLOS objects an the EDITABLE description</h3> |
729 | <div id="text-6.1"> |
730 | |
731 | |
732 | <p> |
733 | The slots of an object are SETF'able places, and LoL takes |
734 | advantage of that to provide EDITABLE descriptions |
735 | automatically. When the EDITABLE description is active, and editor |
736 | will be presented. The REPL based editor is pretty basic, but still |
737 | useful. The HTML based editor will be described later. |
738 | </p> |
739 | |
740 | |
741 | |
742 | <pre class="src">(<span style="color: #a020f0;">defun</span> <span style="color: #0000ff;">edit-object</span> (object <span style="color: #228b22;">&rest</span> args) |
743 | (<span style="color: #a020f0;">with-active-descriptions</span> (editable) |
744 | (apply #'display t object args))) |
745 | |
746 | (<span style="color: #a020f0;">let</span> ((object (make-instance 'person))) |
747 | (edit-object object) |
748 | (terpri) |
749 | (display t object)) |
750 | |
751 | <span style="color: #b22222;">;; </span><span style="color: #b22222;">What follows are prompts and the information i entered |
752 | </span> |
753 | First name:Drew |
754 | |
755 | Last name:Crampsie |
756 | |
757 | Company name:The Tech Co-op |
758 | |
759 | Date of birth:1978-07-31 |
760 | |
761 | Phone:555-5555 |
762 | |
763 | Fax:555-5555 |
764 | |
765 | Email:drewc@tech.coop |
766 | |
767 | Address:s/v Kanu, Lower Fraser River |
768 | |
769 | City:Richmond |
770 | |
771 | Province:BC |
772 | |
773 | Postal code:V1V3T6 |
774 | |
775 | <span style="color: #b22222;">;; </span><span style="color: #b22222;">And this is what was displayed. |
776 | </span> |
777 | First name:Drew |
778 | Last name:Crampsie |
779 | Company name:The Tech Co-op |
780 | Date of birth:1978-07-31 |
781 | Phone:555-5555 |
782 | Fax:555-5555 |
783 | Email:drewc@tech.coop |
784 | Address:s/v Kanu, Lower Fraser River |
785 | City:Richmond |
786 | Province:BC |
787 | Postal code:V1V3T6 |
788 | </pre> |
789 | |
790 | |
791 | </div> |
792 | |
793 | </div> |
794 | |
795 | <div id="outline-container-6.2" class="outline-3"> |
796 | <h3 id="sec-6.2">6.2 Extending the generated description</h3> |
797 | <div id="text-6.2"> |
798 | |
799 | |
800 | <p> |
801 | We mentioned earlier that DESCRIBED-CLASS creates two descriptions : |
802 | </p> |
803 | |
804 | |
805 | <pre class="src"> |
806 | (find-description 'description-for-person) |
807 | => |
808 | #<DESCRIPTION DESCRIPTION-FOR-PERSON {D296DE1}> |
809 | |
810 | (find-description 'person) |
811 | => |
812 | #<DESCRIPTION PERSON {ADFEDB1}> |
813 | |
814 | (description-of (make-instance 'person)) |
815 | => |
816 | #<DESCRIPTION PERSON {ADFEDB1}> |
817 | |
818 | </pre> |
819 | |
820 | |
821 | |
822 | <p> |
823 | The reason for this is so we can redefine the description PERSON while |
824 | keeping all the generated information from DESCRIPTION-FOR-PERSON. |
825 | </p> |
826 | <p> |
827 | In this case, we will add an attribute, PERSON-AGE, that calculates |
828 | a persons age based on the data in the date-of-birth slot. |
829 | </p> |
830 | |
831 | |
832 | |
833 | |
834 | |
835 | |
836 | |
837 | |
838 | |
839 | |
840 | |
841 | |
842 | </div> |
843 | </div> |
844 | |
845 | </div> |
846 | |
847 | <div id="outline-container-7" class="outline-2"> |
848 | <h2 id="sec-7">7 Using Lisp-on-Lines for the Web.</h2> |
849 | <div id="text-7"> |
850 | |
851 | |
852 | <p> |
853 | LoL was developed, and is primarily used, for implementing |
854 | data-driven web applications. As such, it comes with a host of |
855 | features for doing just that. |
856 | </p> |
857 | <p> |
858 | LoL, by default, implements its web portion on top of the wonderful |
859 | UnCommon Web meta-framework. The LISP-ON-LINES-UCW ASDF system |
860 | should be loaded, as it provides the features we're going to |
861 | discuss. |
862 | </p> |
863 | |
864 | |
865 | |
866 | |
867 | |
868 | |
869 | |
870 | |
871 | |
872 | |
873 | |
874 | |
875 | |
876 | |
877 | </div> |
878 | </div> |
879 | <div id="postamble"><p class="author"> Author: Drew Crampsie |
880 | <a href="mailto:Drew Crampsie <drewc@tech.coop>"><Drew Crampsie <drewc@tech.coop>></a> |
881 | </p> |
882 | <p class="date"> Date: 2009/07/27 01:46:25 PM</p> |
883 | <p>HTML generated by org-mode 6.05 in emacs 22<p> |
884 | </div></body> |
885 | </html> |