added dont-show-unset-slots mixin, should work with any mewa-presentation
[clinton/lisp-on-lines.git] / doc / lisp-on-lines.lyx
1 #LyX 1.3 created this file. For more info see http://www.lyx.org/
2 \lyxformat 221
3 \textclass article
4 \language english
5 \inputencoding auto
6 \fontscheme default
7 \graphics default
8 \paperfontsize default
9 \spacing single
10 \papersize a4paper
11 \paperpackage widemarginsa4
12 \use_geometry 0
13 \use_amsmath 0
14 \use_natbib 0
15 \use_numerical_citations 0
16 \paperorientation portrait
17 \secnumdepth 3
18 \tocdepth 3
19 \paragraph_separation indent
20 \defskip medskip
21 \quotes_language english
22 \quotes_times 2
23 \papercolumns 1
24 \papersides 1
25 \paperpagestyle default
26
27 \layout Title
28
29 LISP-ON-LINES
30 \layout Author
31
32
33 \noun on
34 Drew Crampsie
35 \noun default
36 ,
37 \noun on
38 José Pablo Ezequiel
39 \begin_inset Quotes eld
40 \end_inset
41
42 Pupeno
43 \begin_inset Quotes erd
44 \end_inset
45
46 Fernández Silva
47 \layout Abstract
48
49
50 \noun on
51 Lisp-On-Lines
52 \noun default
53 is a very useful module that works on top of the
54 \noun on
55 UnCommon Web
56 \noun default
57 framework to do rapid developing of complex data-driven web appilcations
58 (on
59 \noun on
60 Common Lisp
61 \noun default
62 , of course).
63 \layout Section
64
65 Introduction
66 \layout Standard
67
68
69 \noun on
70 Lisp-On-Lines
71 \noun default
72 was founded and developed and continues to be developed and mantained by
73
74 \noun on
75 Drew Crampsie
76 \noun default
77 .
78 \layout Subsection
79
80 Conventions
81 \layout Standard
82
83 The conventions used in this manual are:
84 \layout Itemize
85
86 Code is shown in a monospace font.
87 When it is expected that the user is working in an interactive environment
88 what the user should type appears as bold, while the computer result appears
89 non-bold, for example:
90 \begin_deeper
91 \layout LyX-Code
92
93 >
94 \series bold
95 (+ 5 10)
96 \layout LyX-Code
97
98 15
99 \end_deeper
100 \layout Itemize
101
102 Names of people or products are show as small caps, like
103 \noun on
104 Drew Crampsie
105 \noun default
106 or
107 \noun on
108 Lisp-On-Lines
109 \noun default
110 .
111 \layout Itemize
112
113 Sections marked with
114 \color red
115 ToDo
116 \color default
117 require further revision.
118 \layout Standard
119
120
121 \color red
122 ToDo: Add more conventions as they are needed, possible classes of text:
123 names of concepts, name of programming entities, like variables, functions,
124 etc (which are embedded in text, should they be shown monospaced ?).
125 \layout Section
126
127 Components
128 \layout Description
129
130 Meta\SpecialChar ~
131 Model\SpecialChar ~
132 Protocol A Protocol for introspection on relational objects.
133 \layout Description
134
135 Mewa\SpecialChar ~
136 Presentations A Mewa-like
137 \begin_inset Foot
138 collapsed true
139
140 \layout Standard
141
142 http://www.adrian-lienhard.ch/files/mewa.pdf
143 \end_inset
144
145 layer for UncommonWeb
146 \begin_inset Foot
147 collapsed true
148
149 \layout Standard
150
151 http://common-lisp.net/project/ucw/
152 \end_inset
153
154 Presentations.
155 \layout Section
156
157 Example
158 \layout Standard
159
160 First we start with the data model.
161 The Meta Model Protocol (MMP) is used to provide information on the data
162 objects and how they relate to one another.
163 Its is currently implemented as a layer over CLSQL
164 \begin_inset Foot
165 collapsed true
166
167 \layout Standard
168
169 http://clsql.b9.com/
170 \end_inset
171
172 , although support is planned for other backends (
173 \noun on
174 CLOS
175 \noun default
176 ,
177 \noun on
178 Elephant
179 \noun default
180 [4], whatever).
181 \layout Standard
182
183 The MMP shares its definition syntax with
184 \emph on
185 \noun on
186 CLSQL
187 \emph default
188 \noun default
189 's Object Oriented Data Definition Language (OODDL)
190 \begin_inset Foot
191 collapsed true
192
193 \layout Standard
194
195 http://clsql.b9.com/manual/ref-ooddl.html
196 \begin_inset Note
197 collapsed true
198
199 \layout Standard
200
201 Shouldn't this footnote be a bibliographical entry ? or something like that
202 ?
203 \end_inset
204
205
206 \end_inset
207
208 .
209 The macro to define view-classes is named DEF-VIEW-CLASS/META, and takes
210 the same arguments as DEF-VIEW-CLASS from CLSQL.
211 For the purposes of this simple example, we will only need two functions
212 from the MMP beyond what CLSQL provides : LIST-SLOTS and LIST-SLOT-TYPES[5].
213 \layout Standard
214
215 We'll define a simple class to hold a user.
216 \layout LyX-Code
217
218 >
219 \series bold
220 (def-view-class/meta user ()
221 \layout LyX-Code
222
223
224 \series bold
225 ((userid :initarg :userid :accessor userid :type integer :db-kind :key)
226 \layout LyX-Code
227
228
229 \series bold
230 (username :initarg :username :accessor username :type string :db-kind
231 :base)
232 \layout LyX-Code
233
234
235 \series bold
236 (password :initarg :password :accessor password :type string :db-kind
237 :base)))
238 \layout Standard
239
240 and now we create a user:
241 \layout LyX-Code
242
243 >
244 \series bold
245 (defparameter user (make-instance 'user :userid 1
246 \layout LyX-Code
247
248
249 \series bold
250 :username "drewc"
251 \layout LyX-Code
252
253
254 \series bold
255 :password "p@ssw0rd"))
256 \layout Standard
257
258 We can see the slots of users running:
259 \layout LyX-Code
260
261 >
262 \series bold
263 (lisp-on-lines::list-slots user)
264 \layout LyX-Code
265
266 (USERID USERNAME PASSWORD)
267 \layout Standard
268
269 or the types with:
270 \layout LyX-Code
271
272 >
273 \series bold
274 (lisp-on-lines::list-slot-types user)
275 \layout LyX-Code
276
277 ((USERID INTEGER) (USERNAME STRING) (PASSWORD STRING))
278 \layout Standard
279
280 To see the default attributes of a class
281 \begin_inset Marginal
282 collapsed true
283
284 \layout Standard
285
286 Is this correct ? Drew, please, check.
287 \end_inset
288
289 we run.
290 \layout LyX-Code
291
292 >
293 \series bold
294 (lisp-on-lines::default-attributes user)
295 \layout LyX-Code
296
297 ((USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
298 \layout LyX-Code
299
300 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
301 \layout LyX-Code
302
303 (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD))
304 \layout Standard
305
306 To set the attributes of a class to the default values we use:
307 \layout LyX-Code
308
309 >
310 \series bold
311 (lisp-on-lines::set-default-attributes user)
312 \layout LyX-Code
313
314 ((USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
315 \layout LyX-Code
316
317 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
318 \layout LyX-Code
319
320 (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD))
321 \layout Standard
322
323 which takes an object of the class we are working with.
324 This is going to be change so we can do this action directly on the class.
325 It is on the TODO file.
326 \layout Standard
327
328 Class attributes?
329 \layout LyX-Code
330
331 >
332 \series bold
333 (lisp-on-lines::find-class-attributes user)
334 \layout LyX-Code
335
336 (USER (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
337 \layout LyX-Code
338
339 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
340 \layout LyX-Code
341
342 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
343 \layout LyX-Code
344
345 NIL)
346 \layout Standard
347
348 note that the mewa functions (find-attribute, set-attribute etc) can take
349 either an instance, or a class-name as a symbol:
350 \layout LyX-Code
351
352 >
353 \series bold
354 (lisp-on-lines::find-class-attributes 'user)
355 \layout LyX-Code
356
357 (USER (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
358 \layout LyX-Code
359
360 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
361 \layout LyX-Code
362
363 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
364 \layout LyX-Code
365
366 NIL)
367 \layout LyX-Code
368
369 >
370 \series bold
371 (lisp-on-lines::find-class-attributes (make-instance 'user))
372 \layout LyX-Code
373
374 (USER (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
375 \layout LyX-Code
376
377 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
378 \layout LyX-Code
379
380 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
381 \layout LyX-Code
382
383 NIL)
384 \layout Standard
385
386 Using that information, we have enough to create an interface to the object.
387
388 \noun on
389 UnCommon Web
390 \noun default
391 includes a powerful presentation system
392 \begin_inset Foot
393 collapsed true
394
395 \layout Standard
396
397 To see this system in action, we strongly recomend to study the presentations
398 example which comes with
399 \noun on
400 UnCommon Web
401 \noun default
402 .
403 Reading components/presentations.lisp can help understand a lot about how
404 presentations are built.
405 \end_inset
406
407 , but it is not dynamic enough for some of the most advanced applications.
408 Mewa defines an approach to presentations that solves that problem, but
409 the paper is written from a
410 \noun on
411 Smalltalk
412 \noun default
413 point of view.
414 A mixture of the two , Mewa Presentations(MP), is described here.
415 \layout Standard
416
417 MP introduces to
418 \noun on
419 UnCommon Web
420 \noun default
421 the concept of
422 \emph on
423 attributes
424 \emph default
425 .
426 An attribute is essentially a named version of the DEFPRESENTATION slot-like
427 arguments, for example in :
428 \layout LyX-Code
429
430 >
431 \series bold
432 (defpresentation person-editor (object-presentation)
433 \layout LyX-Code
434
435
436 \series bold
437 ((string :label "First Name" :slot-name 'first-name :max-length 30)))
438 \layout Standard
439
440 the (string :label "First Name" ...) form is an attribute definiton.
441 Attributes are accessed through FIND-ATTIRIBUTES, and are composed at run
442 time (where the
443 \noun on
444 UnCommon Web
445 \noun default
446 's presentation system is done at compile time) to display the object.
447 This allows a very flexible system of displaying objects which is reminiscent
448 of
449 \noun on
450 CSS
451 \noun default
452
453 \begin_inset Foot
454 collapsed false
455
456 \layout Standard
457
458
459 \noun on
460 Drew Crampsie
461 \noun default
462 discovered this, rather than invent or design it, so there are some rough
463 edges, but its a good start.
464 Exploration baby yeah!
465 \end_inset
466
467 .
468 \layout Standard
469
470 Its much easier to show this than to tell.
471 Lets present our user class.
472 Currently in
473 \noun on
474 UnCommon Web
475 \noun default
476 , you'd define a presentation as such :
477 \layout LyX-Code
478
479 >
480 \series bold
481 (defpresentation user-presentation (object-presentation)
482 \layout LyX-Code
483
484 ((INTEGER :LABEL "USERID" :SLOT-NAME USERID)
485 \layout LyX-Code
486
487 (STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
488 \layout LyX-Code
489
490 (STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)))
491 \layout Standard
492
493 which could be presented using PRESENT-OBJECT :
494 \layout LyX-Code
495
496 >
497 \series bold
498 (present-object user :using 'user-presentation)
499 \layout Standard
500
501 The equivalent approach using mewa presentations is actually longer and
502 more verbose(!) but it serves to demonstrate how the MP system works.
503 \layout Standard
504
505 Mewa Presentations adds a set of attributes to a class, keyed off the class
506 name.
507 Attributes are inherited, so if you define an attribute on T, you can use
508 it with any class.
509 \layout Standard
510
511 MP stores named attributes keyed on a class name.
512 To achieve the same functionality as the above using mp would look like
513 this :
514 \layout LyX-Code
515
516 >
517 \series bold
518 (setf (lisp-on-lines::find-attribute 'user :viewer)
519 \begin_inset Marginal
520 collapsed true
521
522 \layout Standard
523
524 Isn't this too imperative (in contrast to functional, lispy).
525 \end_inset
526
527
528 \layout LyX-Code
529
530
531 \series bold
532 '(lisp-on-lines::mewa-object-presentation
533 \layout LyX-Code
534
535
536 \series bold
537 :attributes (userid username password)
538 \layout LyX-Code
539
540
541 \series bold
542 :global-properties (:editablep nil)))
543 \layout LyX-Code
544
545 (:VIEWER MEWA-OBJECT-PRESENTATION
546 \layout LyX-Code
547
548 :ATTRIBUTES
549 \layout LyX-Code
550
551 (USERID USERNAME PASSWORD)
552 \layout LyX-Code
553
554 :GLOBAL-PROPERTIES
555 \layout LyX-Code
556
557 (:EDITABLEP NIL))
558 \layout LyX-Code
559
560 >
561 \series bold
562 (setf (lisp-on-lines::find-attribute 'user 'userid)
563 \begin_inset Marginal
564 collapsed true
565
566 \layout Standard
567
568 Are this setfs to 'userid, 'username and 'password needed ? I (Pupeno) inspected
569 they contents at of this moment and they seem to already contain what they
570 are being set to.
571 \end_inset
572
573
574 \layout LyX-Code
575
576
577 \series bold
578 '(integer :label "userid" :slot-name userid))
579 \layout LyX-Code
580
581 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
582 \layout LyX-Code
583
584 >
585 \series bold
586 (setf (lisp-on-lines::find-attribute 'user 'username)
587 \layout LyX-Code
588
589
590 \series bold
591 '(STRING :LABEL "USERNAME" :SLOT-NAME USERNAME))
592 \layout LyX-Code
593
594 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
595 \layout LyX-Code
596
597 >
598 \series bold
599 (setf (lisp-on-lines::find-attribute 'user 'password)
600 \layout LyX-Code
601
602
603 \series bold
604 '(STRING :LABEL "USERNAME" :SLOT-NAME PASSWORD))
605 \layout LyX-Code
606
607 (PASSWORD STRING :LABEL "USERNAME" :SLOT-NAME PASSWORD)
608 \layout LyX-Code
609
610 >
611 \series bold
612 (lisp-on-lines::find-class-attributes 'user)
613 \layout LyX-Code
614
615 (USER
616 \layout LyX-Code
617
618 (:VIEWER MEWA-OBJECT-PRESENTATION
619 \layout LyX-Code
620
621 :ATTRIBUTES
622 \layout LyX-Code
623
624 (USERID USERNAME PASSWORD)
625 \layout LyX-Code
626
627 :GLOBAL-PROPERTIES
628 \layout LyX-Code
629
630 (:EDITABLEP NIL))
631 \layout LyX-Code
632
633 (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
634 \layout LyX-Code
635
636 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
637 \layout LyX-Code
638
639 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
640 \layout LyX-Code
641
642 NIL)
643 \layout Standard
644
645 this is all turned into a
646 \noun on
647 UnCommon Web
648 \noun default
649 presentation at runtime using MAKE-PRESENTATION, for example, the following
650 code should be enough to show what's built so far attached to the examples
651 application:
652 \layout LyX-Code
653
654 >
655 \series bold
656 (defcomponent lol-example (window-component)
657 \layout LyX-Code
658
659
660 \series bold
661 ())
662 \layout LyX-Code
663
664 >
665 \series bold
666 (defmethod render-on ((res response) (lol-example lol-example))
667 \layout LyX-Code
668
669
670 \series bold
671 (<:h1 "User")
672 \layout LyX-Code
673
674
675 \series bold
676 (<ucw:render-component :component (lisp-on-lines::make-presentation
677 user :type :viewer)))
678 \layout LyX-Code
679
680 >
681 \series bold
682 (defentry-point "lol.ucw" (:application *example-application*) ()
683 \layout LyX-Code
684
685
686 \series bold
687 (call 'lol-example))
688 \layout Standard
689
690 As you'll see, nothing is exported from the LISP-ON-LINES package.
691 If you wish to use LOL in your own package (or in UCW-USER or whatever),
692 you simply need to use the MEWA and META-MODEL packages.
693 \layout Standard
694
695 SET-ATTRIBUTE can be used in place of (setf (find-attribute ...)) when you
696 want to "inherit" the properties of an existing attribute definition :
697 \layout LyX-Code
698
699 LISP-ON-LINES>
700 \series bold
701 (set-attribute 'user 'password '(string :label "password: (must be at least
702 8 chars)"))
703 \layout LyX-Code
704
705 (PASSWORD STRING
706 \layout LyX-Code
707
708 :LABEL
709 \layout LyX-Code
710
711 "password: (must be at leat 8 chars)"
712 \layout LyX-Code
713
714 :SLOT-NAME
715 \layout LyX-Code
716
717 PASSWORD)
718 \layout Standard
719
720 Now we want to create a presentation with which to edit the username.
721 we will use the existing attributes on a subclass of mewa-object-presetation
722 :
723 \layout LyX-Code
724
725 >
726 \series bold
727 (defcomponent user-editor (mewa-object-presentation)
728 \layout LyX-Code
729
730
731 \series bold
732 ()
733 \layout LyX-Code
734
735
736 \series bold
737 (:default-initargs
738 \layout LyX-Code
739
740
741 \series bold
742 :attributes '((username :label "Enter your New Username") password)
743 \layout LyX-Code
744
745
746 \series bold
747 :global-properties '(:editablep t)))
748 \layout LyX-Code
749
750 USER-EDITOR
751 \layout LyX-Code
752
753 LISP-ON-LINES>
754 \series bold
755 (setf (find-attribute 'user :editor) '(user-editor))
756 \layout LyX-Code
757
758 (:EDITOR USER-EDITOR)
759 \layout Standard
760
761 which we then can display below our earlier example :
762 \layout LyX-Code
763
764
765 \series bold
766 (defmethod render-on ((res response) (e presentations-index))
767 \layout LyX-Code
768
769
770 \series bold
771 "
772 \layout LyX-Code
773
774
775 \series bold
776 As you'll see, nothing is exported from the LISP-ON-LINES package.
777
778 \layout LyX-Code
779
780
781 \series bold
782 if you wish to use LOL in your own package (or in UCW-USER or whatever),
783 \layout LyX-Code
784
785
786 \series bold
787 you simply need to use the MEWA and META-MODEL packages"
788 \layout LyX-Code
789
790
791 \series bold
792 (<ucw:render-component :component (lisp-on-lines::make-presentation lisp-on-line
793 s::user :type :viewer))
794 \layout LyX-Code
795
796
797 \series bold
798 (<ucw:render-component :component (lisp-on-lines::make-presentation lisp-on-line
799 s::user :type :editor)))
800 \layout Standard
801
802 that should give you some idea on how it works ..
803 ask me when you get confused :)
804 \layout Section
805
806 Pupeno's Example
807 \layout Standard
808
809 This is Pupeno's view of how to do rapid developing of a database-driven
810 web application.
811 It currently is going to assume a very specific case but latter it may
812 be made bigger.
813 \layout Standard
814
815 We first start with a
816 \noun on
817 PostgreSQL
818 \noun default
819 connection of CLSQL which is set up with one line:
820 \layout LyX-Code
821
822 >
823 \series bold
824 (clsql:connect '("localhost" "geo" "geo" "geogeo"))
825 \layout Standard
826
827 which connect us to the server on
828 \family typewriter
829 localhost
830 \family default
831 , to the database
832 \family typewriter
833 geo
834 \family default
835 as user
836 \begin_inset Quotes eld
837 \end_inset
838
839 geo
840 \begin_inset Quotes erd
841 \end_inset
842
843 with password
844 \begin_inset Quotes eld
845 \end_inset
846
847 geogeo
848 \begin_inset Quotes erd
849 \end_inset
850
851 (this is not a smart way to generate password, don't do this).
852 To have a nice SQL environment, we also want:
853 \layout LyX-Code
854
855 >
856 \series bold
857 (clsql:locally-enable-sql-reader-syntax)
858 \layout LyX-Code
859
860 >
861 \series bold
862 (setf clsql:*default-caching* nil)
863 \layout Standard
864
865 Actually, it is more than a nice environmnet, without those lines the rest
866 of the code won't work.
867 \layout Standard
868
869 On the
870 \family typewriter
871 geo
872 \family default
873 database, there's a table called
874 \family typewriter
875 product
876 \family default
877 which has the following structure:
878 \layout LyX-Code
879
880
881 \series bold
882 CREATE TABLE product (
883 \layout LyX-Code
884
885
886 \series bold
887 id serial NOT NULL,
888 \layout LyX-Code
889
890
891 \series bold
892 name text NOT NULL,
893 \layout LyX-Code
894
895
896 \series bold
897 details text,
898 \layout LyX-Code
899
900
901 \series bold
902 description text,
903 \layout LyX-Code
904
905
906 \series bold
907 cost double precision,
908 \layout LyX-Code
909
910
911 \series bold
912 CONSTRAINT product_cost_check CHECK ((cost > (0)::double precision))
913 \layout LyX-Code
914
915
916 \series bold
917 );
918 \layout LyX-Code
919
920
921 \series bold
922 ALTER TABLE ONLY product ADD CONSTRAINT product_name_key UNIQUE (name);
923 \layout LyX-Code
924
925
926 \series bold
927 ALTER TABLE ONLY product ADD CONSTRAINT product_pkey PRIMARY KEY (id);
928 \layout Standard
929
930
931 \color red
932 ToDo: express the table structure in a better way.
933 \layout Standard
934
935 Now we'll create the class that represents a product, mirroring the database
936 structure:
937 \layout LyX-Code
938
939 >
940 \series bold
941 (lisp-on-lines::def-view-class/table "product")
942 \layout Standard
943
944 and then we generate the default attributes (from
945 \family typewriter
946 product
947 \family default
948 's slots) and assign it to
949 \family typewriter
950 product
951 \family default
952 :
953 \layout LyX-Code
954
955 >
956 \series bold
957 (lisp-on-lines::set-default-attributes (make-instance 'product))
958 \begin_inset Marginal
959 collapsed true
960
961 \layout Standard
962
963 set-default-attributes is marked to be renamed to set-generated-attributes.
964 \end_inset
965
966
967 \layout Standard
968 \align left
969 As you can see, we instantiate
970 \family typewriter
971 product
972 \family default
973 to pass it to
974 \family typewriter
975 set-default-attributes
976 \family default
977 , because it expects an object instead of a class.
978 We don't need the object anymore, so we don't save any reference to it.
979 In the future we might have a
980 \family typewriter
981 set-default-attributes
982 \family default
983 that can use a class directly.
984 Now we set a the attribute
985 \family typewriter
986 :viewer
987 \family default
988 to contain the
989 \family typewriter
990 mewa-object-presentation
991 \family default
992 exposing the attributes we like the user to work with:
993 \layout LyX-Code
994
995 >
996 \series bold
997 (setf (lisp-on-lines::find-attribute (make-instance 'product) :viewer)
998 \layout LyX-Code
999
1000
1001 \series bold
1002 '(lisp-on-lines::mewa-object-presentation
1003 \layout LyX-Code
1004
1005
1006 \series bold
1007 :attributes (name details description cost)
1008 \layout LyX-Code
1009
1010
1011 \series bold
1012 :global-properties (:editablep nil)))
1013 \layout Standard
1014
1015 The last parameter is a list of properties that will be applied to each
1016 attribute.
1017 \layout Section
1018
1019 Yet Another Example .
1020 \layout Standard
1021
1022 Drew Crampsie Posted the following to comp.lang.lisp ..
1023 it just might help until he writes some real documentation.
1024
1025 \layout Standard
1026
1027 I've written a system that generates presentations for database objects
1028 based on the type and relation information in the system catalog.
1029 Its based on Mewa
1030 \begin_inset Foot
1031 collapsed true
1032
1033 \layout Standard
1034
1035 Mewa : Meta-level Architecture for Generic Web-Application Construction
1036 \layout Standard
1037
1038 http://map1.squeakfoundation.org/sm/package/32c5401f-fa30-4a2b-80c8-1006dd462859
1039 \end_inset
1040
1041 clsql + postgres and the UCW presentation components.
1042 \layout Standard
1043
1044 This is the code to add a new contact to the system.
1045 (screenshot pr0n follows).
1046 \layout Standard
1047
1048 In the RENDER-ON method of my front-page i have :
1049 \layout LyX-Code
1050
1051 (let ((p (make-instance 'person :person-type-code nil)))
1052 \layout LyX-Code
1053
1054 (<:as-html "Add Person :")
1055 \layout LyX-Code
1056
1057 (<ucw:render-component
1058 \layout LyX-Code
1059
1060 :component (make-presentation
1061 \layout LyX-Code
1062
1063 p
1064 \layout LyX-Code
1065
1066 :type :one-line
1067 \layout LyX-Code
1068
1069 :initargs '(:attributes
1070 \layout LyX-Code
1071
1072 ((person-type-code :editablep t)))))
1073 \layout LyX-Code
1074
1075 (<ucw:submit :action (new-person self p) :value "add"))
1076 \layout LyX-Code
1077
1078 \layout Standard
1079
1080 This creates a drop-down list of person-types and an "add" button which
1081 calls NEW-PERSON :
1082 \layout LyX-Code
1083
1084 (defaction new-person ((self component) person)
1085 \layout LyX-Code
1086
1087 "
1088 \layout LyX-Code
1089
1090 Take a PERSON with a user-defined PERSON-TYPE-CODE,
1091 \layout LyX-Code
1092
1093 * Prompt the user for a FIRST-NAME, LAST-NAME and/or COMPANY-NAME
1094 \layout LyX-Code
1095
1096 * Search for similar PERSONs in the database.
1097 \layout LyX-Code
1098
1099 * If they exist, ask the user to select one or continue
1100 \layout LyX-Code
1101
1102 * otherwise, just continue editing the person"
1103 \layout LyX-Code
1104
1105 (let ((named-person
1106 \layout LyX-Code
1107
1108 (call-component self (make-presentation
1109 \layout LyX-Code
1110
1111 person
1112 \layout LyX-Code
1113
1114 :type 'new-person
1115 \layout LyX-Code
1116
1117 :initargs '(:global-properties
1118 \layout LyX-Code
1119
1120 (:size 25 :editablep t))))))
1121 \layout LyX-Code
1122
1123 (when named-person
1124 \layout LyX-Code
1125
1126 (call-component self (make-presentation
1127 \layout LyX-Code
1128
1129 (find-or-return-named-person self named-person)
1130 \layout LyX-Code
1131
1132 :type :editor)))))
1133 \layout LyX-Code
1134
1135 \layout LyX-Code
1136
1137 (defaction find-or-return-named-person ((self component) person)
1138 \layout LyX-Code
1139
1140 "
1141 \layout LyX-Code
1142
1143 If any similiar contacts exist in the database,
1144 \layout LyX-Code
1145
1146 select one or continue with the current person
1147 \layout LyX-Code
1148
1149 PERSON must have FIRST-NAME, LAST-NAME and COMPANY-NAME bound."
1150 \layout LyX-Code
1151
1152 (let ((instances (sql-word-search person 'first-name 'last-name 'company-name)
1153 ))
1154 \layout LyX-Code
1155
1156 (if instances
1157 \layout LyX-Code
1158
1159 (call-component self (make-presentation
1160 \layout LyX-Code
1161
1162 person
1163 \layout LyX-Code
1164
1165 :type 'person-chooser
1166 \layout LyX-Code
1167
1168 :initargs
1169 \layout LyX-Code
1170
1171 `(:instances ,instances)))
1172 \layout LyX-Code
1173
1174 person)))
1175 \layout LyX-Code
1176
1177 \layout Standard
1178
1179 You can hardly tell it's a web application ...
1180 there is no checking of CGI params etc...
1181 just nice code in the order i wanted to write it.
1182 \layout Standard
1183
1184 Screenshots :
1185 \layout Itemize
1186
1187 http://tech.coop/img/screenshots/select-person-type.jpg
1188 \layout Itemize
1189
1190 http://tech.coop/img/screenshots/enter-person-name.jpg
1191 \layout Itemize
1192
1193 http://tech.coop/img/screenshots/select-similar-contacts.jpg
1194 \layout Itemize
1195
1196 http://tech.coop/img/screenshots/edit-person-details.jpg
1197 \layout Itemize
1198
1199 http://tech.coop/img/screenshots/view-recent-changes.jpg
1200 \layout Standard
1201
1202 All of the code used to create the presentations for this is below my sig.
1203 I do eventually plan to release the presentation system as Free Software,
1204 it just needs a little cleaning up.
1205 E-mail me for a sneak peak.
1206 \layout LyX-Code
1207
1208 --
1209 \layout LyX-Code
1210
1211 Drew Crampsie
1212 \layout LyX-Code
1213
1214 drewc at tech dot coop
1215 \layout LyX-Code
1216
1217 "Never mind the bollocks -- here's the sexp's tools."
1218 \layout LyX-Code
1219
1220 -- Karl A.
1221 Krueger on comp.lang.lisp
1222 \layout LyX-Code
1223
1224 \layout LyX-Code
1225
1226 (def-view-class/table "person")
1227 \layout LyX-Code
1228
1229 \layout LyX-Code
1230
1231 (set-default-attributes (make-instance 'person)
1232 \layout LyX-Code
1233
1234 \layout LyX-Code
1235
1236 (defcomponent person-display (mewa::two-column-presentation)
1237 \layout LyX-Code
1238
1239 ())
1240 \layout LyX-Code
1241
1242 \layout LyX-Code
1243
1244 (defcomponent one-line-person (mewa::mewa-one-line-presentation)
1245 \layout LyX-Code
1246
1247 ()
1248 \layout LyX-Code
1249
1250 (:default-initargs :attributes '(first-name last-name company-name)))
1251 \layout LyX-Code
1252
1253 \layout LyX-Code
1254
1255 (setf (find-attribute 'person :one-line) '(one-line-person))
1256 \layout LyX-Code
1257
1258 \layout LyX-Code
1259
1260 (set-attribute 'person 'person-type-code '(code-select :category 1))
1261 \layout LyX-Code
1262
1263 \layout LyX-Code
1264
1265 (set-attribute 'person 'province-state-code '(code-select :category 2))
1266 \layout LyX-Code
1267
1268 \layout LyX-Code
1269
1270 (setf (find-attribute 'person :viewer) '(person-display :global-properties
1271 (:editablep nil)))
1272 \layout LyX-Code
1273
1274 \layout LyX-Code
1275
1276 (set-attribute 'person :editor '(person-display :global-properties (:editablep
1277 t)))
1278 \layout LyX-Code
1279
1280 \layout LyX-Code
1281
1282 (setf (find-attribute 'person 'claim->adjuster-id) '(ucw::has-very-many
1283 :label "Claims as Adjuster" :slot-name claim->adjuster-id ) )
1284 \layout LyX-Code
1285
1286 \layout LyX-Code
1287
1288 (set-attribute 'person 'policy->agent-id '(ucw::has-very-many :label "Policies
1289 as Agent"))
1290 \layout LyX-Code
1291
1292 \layout LyX-Code
1293
1294 (defcomponent new-person (person-display)
1295 \layout LyX-Code
1296
1297 ()
1298 \layout LyX-Code
1299
1300 (:default-initargs
1301 \layout LyX-Code
1302
1303 :attributes '(first-name last-name company-name)))
1304 \layout LyX-Code
1305
1306 \layout LyX-Code
1307
1308 (defcomponent person-chooser (mewa::mewa-list-presentation)
1309 \layout LyX-Code
1310
1311 ()
1312 \layout LyX-Code
1313
1314 (:default-initargs
1315 \layout LyX-Code
1316
1317 :attributes '(first-name
1318 \layout LyX-Code
1319
1320 last-name
1321 \layout LyX-Code
1322
1323 company-name
1324 \layout LyX-Code
1325
1326 address
1327 \layout LyX-Code
1328
1329 city
1330 \layout LyX-Code
1331
1332 person-type-code)
1333 \layout LyX-Code
1334
1335 :global-properties '(:editablep nil)
1336 \layout LyX-Code
1337
1338 :editablep nil
1339 \layout LyX-Code
1340
1341 :deleteablep nil))
1342 \layout LyX-Code
1343
1344 \layout LyX-Code
1345
1346 (defmethod render-on :wrapping ((res response) (self person-chooser))
1347 \layout LyX-Code
1348
1349 (<:p (<:as-html "Similar contact(s) in database.
1350 You can :")
1351 \layout LyX-Code
1352
1353 (<:ul
1354 \layout LyX-Code
1355
1356 (<:li (<:as-html "Select one of the contacts below"))
1357 \layout LyX-Code
1358
1359 (<:li (<ucw:a :action (answer (instance self))
1360 \layout LyX-Code
1361
1362 (<:as-html "Continue, adding a new contact")))))
1363 \layout LyX-Code
1364
1365 (call-next-method))
1366 \layout LyX-Code
1367
1368 \layout LyX-Code
1369
1370 (defaction ok ((self new-person) &optional arg)
1371 \layout LyX-Code
1372
1373 (declare (ignore arg))
1374 \layout LyX-Code
1375
1376 (answer (instance self)))
1377 \layout LyX-Code
1378
1379 \layout LyX-Code
1380
1381 (defmethod sql-word-search ((instance standard-db-object) &rest slots)
1382 \layout LyX-Code
1383
1384 (let ((names
1385 \layout LyX-Code
1386
1387 (loop for slot in slots
1388 \layout LyX-Code
1389
1390 nconc (split-sequence #
1391 \backslash
1392 Space (slot-value instance slot)))))
1393 \layout LyX-Code
1394
1395 (select (class-name (class-of instance))
1396 \layout LyX-Code
1397
1398 :where (sql-or (mapcar #'(lambda (x)
1399 \layout LyX-Code
1400
1401 (when (< 0 (length x))
1402 \layout LyX-Code
1403
1404 (apply #'sql-or
1405 \layout LyX-Code
1406
1407 (mapcar #'(lambda (y)
1408 \layout LyX-Code
1409
1410 (sql-uplike
1411 \layout LyX-Code
1412
1413 (sql-slot-value 'person y)
1414 \layout LyX-Code
1415
1416 (format nil
1417 "%~a%" x)))
1418 \layout LyX-Code
1419
1420 slots))))
1421 \layout LyX-Code
1422
1423 names))
1424 \layout LyX-Code
1425
1426 :flatp t)))
1427 \layout LyX-Code
1428
1429 \the_end