added better equality checks for clsql-wall-time slot changes
[clinton/lisp-on-lines.git] / lisp-on-lines.txt
CommitLineData
579597e3 1LISP-ON-LINES 0.1
2
3
4Components:
5
6Meta Model Protocol - A Protocol for introspection on relational objects.
7Mewa Presentations : A Mewa-like[1] layer for UncommonWeb[2] Presentations.
8
9Description:
10
11LISP-ON-LINES (LOL) is a framework for rapid development of complex data-driven web appilcations.
12Introduction:
13
14
15Example:
16
17First we start with the data model. The Meta Model Protocol (MMP) is used to provide information on the data objects and how they relate to one another. Its is currently implemented as a layer over CLSQL[3], although support is planned for other backends (CLOS,Elephant[4], whatever).
18
19The MMP shares its definition syntax with CLSQL's Object Oriented Data Definition Language (OODDL). The macro to define view-classes is named DEF-VIEW-CLASS/META, and takes the same arguments as DEF-VIEW-CLASS from CLSQL. For the purposes of this simple example, we will only need two functions from the MMP beyond what CLSQL provides : LIST-SLOTS and LIST-SLOT-TYPES[5].
20
21We'll define a simple class to hold a user.
22LISP-ON-LINES> (def-view-class/meta user ()
23 ((userid :initarg :userid :accessor userid :type integer :db-kind :key)
24 (username :initarg :username :accessor username :type string :db-kind :base)
25 (password :initarg :password :accessor password :type string :db-kind :base)))
26STYLE-WARNING: redefining META-MODEL.METADATA (USER) in DEFMETHOD
27#<CLSQL-SYS::STANDARD-DB-CLASS USER>
28LISP-ON-LINES> (defparameter user (make-instance 'user :userid 1 :username "drewc" :password "p@ssw0rd"))
29USER
30LISP-ON-LINES> (list-slots user)
31(USERID USERNAME PASSWORD)
32LISP-ON-LINES> (list-slot-types user)
33((USERID INTEGER) (USERNAME STRING) (PASSWORD STRING))
34; compiling file "/tmp/fileQQsHyN" (written 03 JUN 2005 03:20:06 PM):
35
36; /tmp/fileQQsHyN.fasl written
37; compilation finished in 0:00:00
38LISP-ON-LINES> (default-attributes user)
39((USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
40 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
41 (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD))
42LISP-ON-LINES> (set-default-attributes user)
43((USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
44 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
45 (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD))
46LISP-ON-LINES> (find-class-attributes user)
47(USER (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
48 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
49 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
50 COMMON-LISP:NIL)
51LISP-ON-LINES> ;;;; note that the mewa functions (find-attribute, set-attribute etc) can take either an instance, or a class-name as a symbol , ie :
52; No value
53LISP-ON-LINES> (find-class-attributes 'user)
54(USER (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
55 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
56 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
57 COMMON-LISP:NIL)
58LISP-ON-LINES> (find-class-attributes (make-instance 'user))
59(USER (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
60 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
61 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
62 COMMON-LISP:NIL)
63LISP-ON-LINES>
64
65Using that information, we have enough to create an interface to the object. UncommonWeb includes a powerful presentation system, but it is not quite dynamic enough for our needs. Mewa defines an approach to presentations that suits our purposes, but the paper is written from a smalltalk point of view. A mixture of the two , Mewa Presentations(MP), is described here.
66
67MP introduces to UCW the concept of attributes. an attribute is essentially a named version of the defpresentation slot-like arguments. for example in :
68
69(defpresentation person-editor (object-presentation)
70 ((string :label "First Name" :slot-name 'first-name :max-length 30)))
71
72 the (string :label "First Name" ...) form is an attribute definiton. Attributes are accessed through FIND-ATTIRIBUTES, and are composed at run time (where the current system is done at compile time) to display the object. This allows a very flexible system of displaying objects which is reminiscent of CSS. I discovered this, rather than invent or design it, so there are some rough edges, but its a good start.
73
74Its much easier to show this then to tell. Lets present our user class. Currently in UCW, you'd define a presentation as such :
75
76(defpresentation user-presentation (object-presentation)
77((INTEGER :LABEL "USERID" :SLOT-NAME USERID)
78 (STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
79 (STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)))
80
81which could be presented using PRESENT-OBJECT :
82
83(present-object user :using 'user-presentation)
84
85The equiv approach using mewa presentations is actually longer and more verbose(!) but it serves to demonstrate how the MP system works.
86
87Mewa Presentations adds a set of attributes to a class, keyed off the class name. Attributes are inherited, so if you define an attribute on T, you can use it with any class.
88
89MP stores named attributes keyed on a class name. to achieve the same functionality as the above using mp would look like this :
90
91LISP-ON-LINES> (setf (find-attribute 'user :viewer) '(mewa-object-presentation :attributes (userid username password) :global-properties (:editablep nil)))
92(:VIEWER MEWA-OBJECT-PRESENTATION
93 :ATTRIBUTES
94 (USERID USERNAME PASSWORD)
95 :GLOBAL-PROPERTIES
96 (:EDITABLEP NIL))
97LISP-ON-LINES> (setf (find-attribute 'user 'userid) '(INTEGER :LABEL "USERID" :SLOT-NAME USERID))
98(USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
99LISP-ON-LINES> (setf (find-attribute 'user 'username) '(STRING :LABEL "USERNAME" :SLOT-NAME USERNAME))
100(USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
101LISP-ON-LINES> (setf (find-attribute 'user 'password) '(STRING :LABEL "USERNAME" :SLOT-NAME PASSWORD))
102(PASSWORD STRING :LABEL "USERNAME" :SLOT-NAME PASSWORD)
103
104LISP-ON-LINES> (find-class-attributes 'user)
105(USER (PASSWORD STRING :LABEL "PASSWORD" :SLOT-NAME PASSWORD)
106 (USERNAME STRING :LABEL "USERNAME" :SLOT-NAME USERNAME)
107 (USERID INTEGER :LABEL "USERID" :SLOT-NAME USERID)
108 (:VIEWER MEWA-OBJECT-PRESENTATION
109 :ATTRIBUTES
110 (USERID USERNAME PASSWORD)
111 :GLOBAL-PROPERTIES
112 (:EDITABLEP NIL))
113 COMMON-LISP:NIL)
114
115
116this is all turned into a UCW presentation at runtime using MAKE-PRESENTATION :
117
118(defmethod render-on ((res response) (e presentations-index))
119 "
120As you'll see, nothing is exported from the LISP-ON-LINES package.
121if you wish to use LOL in your own package (or in UCW-USER or whatever),
122you simply need to use the MEWA and META-MODEL packages"
123 (<ucw:render-component :component (lisp-on-lines::make-presentation lisp-on-lines::user :type :viewer)))
124
125
126SET-ATTRIBUTE can be used in place of (setf (find-attribute)) when you want to "inherit" the properties of an existing attribute definition :
127
128LISP-ON-LINES> (set-attribute 'user 'password '(string :label "password: (must be at leat 8 chars)"))
129(PASSWORD STRING
130 :LABEL
131 "password: (must be at leat 8 chars)"
132 :SLOT-NAME
133 PASSWORD)
134
135
136Now we want to create a presentation with which to edit the username. we will use the existing attributes on a subclass of mewa-object-presetation :
137
138LISP-ON-LINES> (defcomponent user-editor (mewa-object-presentation)
139 ()
140 (:default-initargs
141 :attributes '((username :label "Enter your New Username") password)
142 :global-properties '(:editablep t)))
143USER-EDITOR
144LISP-ON-LINES> (setf (find-attribute 'user :editor) '(user-editor))
145(:EDITOR USER-EDITOR)
146LISP-ON-LINES>
147
148
149which we then can display below our earlier example :
150
151(defmethod render-on ((res response) (e presentations-index))
152 "
153As you'll see, nothing is exported from the LISP-ON-LINES package.
154if you wish to use LOL in your own package (or in UCW-USER or whatever),
155you simply need to use the MEWA and META-MODEL packages"
156 (<ucw:render-component :component (lisp-on-lines::make-presentation lisp-on-lines::user :type :viewer))
157 (<ucw:render-component :component (lisp-on-lines::make-presentation lisp-on-lines::user :type :editor)))
158
159
160
161that should give you some idea on how it works .. ask me when you get confused :)
162
163
164
165
166
167
168
169
170
171
172