From ktilton at nyc.rr.com Tue Sep 6 14:37:01 2005 From: ktilton at nyc.rr.com (Kenny Tilton) Date: Tue, 06 Sep 2005 10:37:01 -0400 Subject: [cells-devel] [Fwd: Re: some dumb? cells questions] Message-ID: <431DA98D.1000000@nyc.rr.com> > From: Friedrich Dominicus > Subject: some dumb? cells questions > To: cells-devel at common-lisp.net > Date: Tue, 06 Sep 2005 15:16:14 +0200 > Organization: Q Software Solutions GmbH > > I'm trying to find my way into decent web-programming, and are now > looking into the following simple? Problem. > > The proofed way of doing web-programming seems the MVC stuff. Now the > model may be a cl-sql class e.g and the view may come from any of the > web"frameworks", however there is a need to get the data cleanly to > the view and back I wonder if that would be a good? usage for cells. > > So here we go with the questions. > How would I tell cells to populate the view with database data? > How would I enforce a "direkt link", will say if the model data > changes the view is modified accordingly and vice versa > How would I write validation functions? > > Regards > Friedrich > ---------- From ktilton at nyc.rr.com Tue Sep 6 15:15:49 2005 From: ktilton at nyc.rr.com (Kenny Tilton) Date: Tue, 06 Sep 2005 11:15:49 -0400 Subject: [cells-devel] [Fwd: Re: some dumb? cells questions] In-Reply-To: <431DA98D.1000000@nyc.rr.com> References: <431DA98D.1000000@nyc.rr.com> Message-ID: <431DB2A5.9070706@nyc.rr.com> Kenny Tilton wrote: > >> From: Friedrich Dominicus >> Subject: some dumb? cells questions >> To: cells-devel at common-lisp.net >> Date: Tue, 06 Sep 2005 15:16:14 +0200 >> Organization: Q Software Solutions GmbH >> >> I'm trying to find my way into decent web-programming, and are now >> looking into the following simple? Problem. >> The proofed way of doing web-programming seems the MVC stuff. Now the >> model may be a cl-sql class e.g and the view may come from any of the >> web"frameworks", however there is a need to get the data cleanly to >> the view and back I wonder if that would be a good? usage for cells. > Yes, it is a perfect fit because of the requirement that the model and view always be in synch. Of course on Windows they have the "refresh view" option so users can go quietly crazy not finding what they know is there, so there /are/ alternatives. :) I did this with Franz's AllegroStore. What is needed is a bottleneck on DB writes, some place to put a custom hook which will cooperate with a Cell-powered mechanism to allow seamless declarative view code...uh, here is an example: a simple list view of all my cutomers. That will be a stack of text labels/controls, each showing the customer name. If the name changes we want the label to change, and if a customer is added or removed we want the list contents to grow or shrink. For the latter, we want to say: (aStack ()... :kids (c? (mapcar #'make-list-cell (^ps-table 'customer)))) ...where ps-table is a layer of code I wrote to make it seems as if the AllegroStore (persistent CLOS) customer class had a cell called ps-table (maybe a bad name) which amounted to a list of all the instances of that class in the persistent DB. The hook I used was easy: because it was a persistent CLOS implementation, I was able to use things like initialize-instance and slot-value-using-class to place hooks on my persistent classes. These hooks simulated Cell-like data propagation from DB writes, effectively gluing DB access to the larger Cell-based application model. >> >> >> So here we go with the questions. >> How would I tell cells to populate the view with database data? > Does SQL have any kind of callback mechanism that lets you detect DB writes? If not, you must create bottleneck functions for DB writes and use them consistently, then do the gluing from there. And you IPC to "announce" DB changes. We used GUIDs to give DB instances object identity that can be shared amongst processes. Please note that this all /does/ involve creating a nice little layer of code to connect SQL with Cells. So it is no free lunch. But I have written a lot of code like this before and after Cells and I can confirm that it is a huge win for this type of DB browser/updater application. The view just stays in synch with the DB with no further effort from the developer than the original one-time effort to glue the DB to the Cells. Hellasweet. >> >> How would I enforce a "direkt link", will say if the model data >> changes the view is modified accordingly and vice versa > "changes the view" I covered above. vice-versa (getting the model to follow the view) is no magic. Well, the output methods probably help a little. But at some point the user has to confirm an update, so the write itself ends up being procedural, not some rule on a persistent model instance slot that automatically copies a changed view instance slot. >> >> How would I write validation functions? > I actually arranged for persistent slots of persistent instances to have rules associated with them. There was an "error" slot that could handle things like DB inconsistency, if one wanted to allow the DB write but raise a flag for the user to address. Otherwise, I was also able to have a non-persistent slot on a persistent class. That could be a validation rule, then the GUI code would refuse to commit the changes of an invalid record. I know SQL does not work like an object database, but if I had to do this I would first look for one of the rough hacks done to fake persistent CLOS with SQL and see if they would work, because CLOS itself offers so many hooks. Or I might do my own perisstent CLOS hack. I think you really need /some/ CLOS correlate of your DB to make this work-- well, not "need", but I think it would be the easiest way to go. kt From frido at q-software-solutions.de Wed Sep 7 07:33:58 2005 From: frido at q-software-solutions.de (Friedrich Dominicus) Date: Wed, 07 Sep 2005 09:33:58 +0200 Subject: [cells-devel] cells in Web applications In-Reply-To: <431DB3DC.8060207@nyc.rr.com> (Kenny Tilton's message of "Tue, 06 Sep 2005 11:21:00 -0400") References: <431DB3DC.8060207@nyc.rr.com> Message-ID: <87vf1dmivt.fsf@flarge.here> Kenny Tilton writes: >>> >>> I'm trying to find my way into decent web-programming, and are now >>> looking into the following simple? Problem. >>> The proofed way of doing web-programming seems the MVC stuff. Now the >>> model may be a cl-sql class e.g and the view may come from any of the >>> web"frameworks", however there is a need to get the data cleanly to >>> the view and back I wonder if that would be a good? usage for >>> cells. >> > Yes, it is a perfect fit because of the requirement that the model and > view always be in synch. Of course on Windows they have the "refresh > view" option so users can go quietly crazy not finding what they know > is there, so there /are/ alternatives. :) > > I did this with Franz's AllegroStore. What is needed is a bottleneck > on DB writes, some place to put a custom hook which will cooperate > with a Cell-powered mechanism to allow seamless declarative view > code...uh, here is an example: a simple list view of all my > cutomers. That will be a stack of text labels/controls, each showing > the customer name. If the name changes we want the label to change, > and if a customer is added or removed we want the list contents to > grow or shrink. For the latter, we want to say: > > (aStack ()... > :kids (c? (mapcar #'make-list-cell (^ps-table 'customer)))) > > ...where ps-table is a layer of code I wrote to make it seems as if > the AllegroStore (persistent CLOS) customer class had a cell called > ps-table (maybe a bad name) which amounted to a list of all the > instances of that class in the persistent DB. Well I just started looking into cells, and have yet not the "slighest" idea on it's usage in any environment, so I wrote down a stripped down example (tested with ucw (actual dev tree), araneida, cl-sql, SBCL 0.9.4.24, on a Debian unstable box) Of course I can not expect anyone having all this things installed, it's just to have "more" concrete example (in-package :qss.web) (defparameter *example-app* (make-instance 'cookie-session-application :url-prefix "/ucw/examples/" :tal-generator (make-instance 'yaclml:file-system-generator :cachep t :root-directories (list *ucw-tal-root*)) :www-roots (list *ucw-tal-root*))) (clsql:def-view-class example-app () ((mid :type integer :db-kind :key :accessor mid :initarg :mid) (mtag :type string :accessor mtag :initarg :mtag) (mdescription :type string :accessor mdescription :initarg :mdescription) (msome-fk :type integer :accessor msome-fk :initarg :msome-fk) (msome-objects :accessor msome-objects :db-kind :join :db-info (:join-class other-class :retrieval :deferred :set nil :foreign-key mexample-id :home-key mid)))) (clsql:def-view-class other-class () ((mexample-id :type integer :accessor mexample-id :initarg :mexample-id) (mval :type string :accessor mval :initarg :mval))) (defun populate-db () (let ((other (make-instance 'other-class :mexample-id 1 :mval "some text"))) (clsql:update-records-from-instance other) (let ((mobj (make-instance 'example-app :mid 1 :mtag "some tag" :mdescription "this is the description" :msome-fk 1))) (setf (msome-objects mobj) other) (clsql:update-records-from-instance mobj)))) ;; ;; (clsql:create-view-from-class 'example-app) ;; (clsql:create-view-from-class 'other-class) ;; (populate-db) (defcomponent example-view (simple-window-component) ((db-obj :accessor db-obj :initarg :db-obj :initform (car (clsql:select 'example-app :where [= [mid] 1] :flatp t))) ;; view link to the database object (vtag :accessor vtag :initarg :vtag :component (text-field :size 20 :maxlength 20)) (vdescription :type string :accessor vdescription :initarg :vdescription :component (text-area-field :width 20 :height 10)) (vother :accessor vother :component (text-field :size 20 :maxlength 20)))) (defun setup-db () (qss.db:db-connect :database "test" :user "user" :password "password") ;; open a connectoin to DB (clsql:enable-sql-reader-syntax)) ;; (setup-db) (defcomponent text (simple-window-component) ((view-text :initarg :view-text :reader view-text) (db-text :initarg :db-text :reader db-text))) (defmethod render-on ((res response) (text text)) (<:p "view data" (<:as-is (view-text text))) (<:p "database data" (<:as-is (db-text text)))) (defmethod populate-view ((view example-view)) (let ((db-obj (db-obj view))) (setf (ucw::client-value (vtag view)) (mtag db-obj) (ucw::client-value (vdescription view)) (mdescription db-obj) (ucw::client-value (vother view)) (mval (msome-objects db-obj))) (values))) (defmethod render-on ((res response) (view example-view)) ;; this is not perfect but for the example it should be enough (populate-view view) ;; (inspect view) ( db and db -> view), the rules are very simple if all will go well but what happens if the link is somehow broken? Regards Friedrich From frido at q-software-solutions.de Thu Sep 8 06:43:50 2005 From: frido at q-software-solutions.de (Friedrich Dominicus) Date: Thu, 08 Sep 2005 08:43:50 +0200 Subject: [cells-devel] files missing in cell-cultures Message-ID: <87aciof49l.fsf@flarge.here> the subdirectroy utils-kt is empty in the cells-culture CVS tree, I guess that is not ok. Regards Friedrich From frido at q-software-solutions.de Thu Sep 8 07:11:59 2005 From: frido at q-software-solutions.de (Friedrich Dominicus) Date: Thu, 08 Sep 2005 09:11:59 +0200 Subject: [cells-devel] [Fwd: Re: some dumb? cells questions] In-Reply-To: <431DB2A5.9070706@nyc.rr.com> (Kenny Tilton's message of "Tue, 06 Sep 2005 11:15:49 -0400") References: <431DA98D.1000000@nyc.rr.com> <431DB2A5.9070706@nyc.rr.com> Message-ID: <8764tcf2yo.fsf@flarge.here> Kenny Tilton writes: > Please note that this all /does/ involve creating a nice little layer > of code to connect SQL with Cells. So it is no free lunch. But I have > written a lot of code like this before and after Cells and I can > confirm that it is a huge win for this type of DB browser/updater > application. The view just stays in synch with the DB with no further > effort from the developer than the original one-time effort to glue > the DB to the Cells. Hellasweet. Well that is exactly what I like to do but, I have no idea on how to do that. what does the "needed" glue look like? Regards Friedrich From frido at q-software-solutions.de Thu Sep 8 10:02:45 2005 From: frido at q-software-solutions.de (Friedrich Dominicus) Date: Thu, 08 Sep 2005 12:02:45 +0200 Subject: [cells-devel] my very first baby steps with cells Message-ID: <871x3zg9mi.fsf@flarge.here> Ok, the learning curve is steep and my idea on what I'm doing is less then basic. However here we go, this is the code (defmodel foobar (model) ((val-1 :cell t :accessor val-1 :initform "" :initarg :val-1) (val-3 :cell t :accessor val-3 :initarg :val-3 :initform (c-in "Initialize")))) (def-c-output val-1 () (format t "val-1 is ~a, val-3 is ~a~%" (val-1 self) (val-3 self))) (defun foo-test () (cell-reset) (let ((obj (make-instance 'foobar :val-1 (c? (if (val-3 self) (setf (val-1 self) (val-3 self)) "val-3 not set"))))) (setf (val-3 obj) "another val-3") (setf (val-3 obj) "yet another val for val-3")) (values)) In this utterly primitive example the val3 slot "steers" the slot-1 slot. Translated to my need to sync db-view and "user-view", I assume I have to write model with the two objects in it do the initialization from one side (e.g populating from the database), I probably also have to write a function to feed to the :unchanged (or so slot), if that yiels true, then the view and database data are in sync if not I have to update the database data from the view. Is this the way to go, or am I overlooking something (I guess I do, just cells is too new for me....) Regards Friedrich From ktilton at nyc.rr.com Thu Sep 8 14:04:35 2005 From: ktilton at nyc.rr.com (Kenny Tilton) Date: Thu, 08 Sep 2005 10:04:35 -0400 Subject: [Fwd: Re: [cells-devel] files missing in cell-cultures] Message-ID: <432044F3.5060109@nyc.rr.com> -------- Original Message -------- Subject: Re: [cells-devel] files missing in cell-cultures Date: Thu, 08 Sep 2005 10:03:56 -0400 From: Kenny Tilton To: Friedrich Dominicus References: <87aciof49l.fsf at flarge.here> Friedrich Dominicus wrote: >the subdirectroy utils-kt is empty in the cells-culture CVS tree, I >guess that is not ok. > Well, the only thing wrong is that I have not gotten around to deleting the cell-cultures tree, which has been deprecated for some time now. utils-kt is a subdirectory of cells: http://common-lisp.net/cgi-bin/viewcvs.cgi/cells/utils-kt/?cvsroot=cells -- Kenny Why Lisp? http://wiki.alu.org/RtL_Highlight_Film "I've wrestled with reality for 35 years, Doctor, and I'm happy to state I finally won out over it." Elwood P. Dowd, "Harvey", 1950 -- Kenny Why Lisp? http://wiki.alu.org/RtL_Highlight_Film "I've wrestled with reality for 35 years, Doctor, and I'm happy to state I finally won out over it." Elwood P. Dowd, "Harvey", 1950 From ktilton at nyc.rr.com Thu Sep 8 14:32:49 2005 From: ktilton at nyc.rr.com (Kenny Tilton) Date: Thu, 08 Sep 2005 10:32:49 -0400 Subject: [cells-devel] my very first baby steps with cells In-Reply-To: <871x3zg9mi.fsf@flarge.here> References: <871x3zg9mi.fsf@flarge.here> Message-ID: <43204B91.3010706@nyc.rr.com> Friedrich Dominicus wrote: >Ok, the learning curve is steep and my idea on what I'm doing is less >then basic. However here we go, this is the code >(defmodel foobar (model) > ((val-1 :cell t :accessor val-1 :initform "" :initarg :val-1) > (val-3 :cell t :accessor val-3 :initarg :val-3 :initform (c-in "Initialize")))) > > > > >(def-c-output val-1 () > (format t "val-1 is ~a, val-3 is ~a~%" > (val-1 self) (val-3 self))) > > > >(defun foo-test () > (cell-reset) > (let ((obj (make-instance 'foobar > :val-1 (c? (if (val-3 self) > (setf (val-1 self) (val-3 self)) > "val-3 not set"))))) > Just use: (c? (or (val-3 self) "val-3 not set")) There is also a handy macro for cells of oneself: (c? (or (^val-3) "val-3 not set")) The Cell engine populates the slot at the right time (long story, but the timing is delicate) initially and as val-3 changes. Note that there is a runtime error generated when you attempt to SETF a ruled Cell, as your rule is doing (SETFing itself!), but I think at some point recently I changed things so the error is enforced only if *c-debug* is non-nil. Recall is fuzzy on why I did that. Anyway, the idea is to have a declarative approach in which one supplies a rule for a slot and then the Cells engine takes over and keeps things in synch. > > (setf (val-3 obj) "another val-3") > (setf (val-3 obj) "yet another val for val-3")) > (values)) > >In this utterly primitive example the val3 slot "steers" the slot-1 >slot. > Think of it as slot-1 "following" val3. Note that there is no val-3 logic to change val-1. val-3 does not know anything about val-1. But val-1 has a rule that uses val-3. val-1 could have also used any number of other vals. This is important, and really constitutes the paradigm shift away from a procedural, manual SETFing of other values to a declarative "just worry about the rule for one value at a time". >Translated to my need to sync db-view and "user-view", I assume >I have to write model with the two objects in it do the >initialization from one side (e.g populating from the database), I >probably also have to write a function to feed to the :unchanged (or >so slot), if that yiels true, then the view and database data are in >sync if not I have to update the database data from the view. > I am afraid you lost me there. "two objects"? "one side"? Maybe once you have absorbed the above correction and otherwise gottten a better understanding of the declarative model we can try some actual unambiguous code using a simple text file as a database, with each line constituting a row in an SQL table. I guess the principle will be the same, and this would be a rather extreme but illuminating Use Case to share with others. Note that the original code I described was proprietary, so we would develop new code from scratch (and I cannot share the old code). -- Kenny Why Lisp? http://wiki.alu.org/RtL_Highlight_Film "I've wrestled with reality for 35 years, Doctor, and I'm happy to state I finally won out over it." Elwood P. Dowd, "Harvey", 1950 From frido at q-software-solutions.de Fri Sep 9 06:38:33 2005 From: frido at q-software-solutions.de (Friedrich Dominicus) Date: Fri, 09 Sep 2005 08:38:33 +0200 Subject: [cells-devel] my very first baby steps with cells In-Reply-To: <43204B91.3010706@nyc.rr.com> (Kenny Tilton's message of "Thu, 08 Sep 2005 10:32:49 -0400") References: <871x3zg9mi.fsf@flarge.here> <43204B91.3010706@nyc.rr.com> Message-ID: <87ll26d9ue.fsf@flarge.here> thanks for your comments. I'll spend some time of the day to implement the idea I have on my mind and will post it then. I'm sure someone using cells will find it "obscurred" programmed and will know a better way on how to approache the problem. I probably will drop the view stuff for now and just use formatted output. But I will use a database as "backend". I hope it won't be all too bad. Regards Friedrich From frido at q-software-solutions.de Mon Sep 12 08:09:50 2005 From: frido at q-software-solutions.de (Friedrich Dominicus) Date: Mon, 12 Sep 2005 10:09:50 +0200 Subject: [cells-devel] my very first baby steps with cells In-Reply-To: <87ll26d9ue.fsf@flarge.here> (Friedrich Dominicus's message of "Fri, 09 Sep 2005 08:38:33 +0200") References: <871x3zg9mi.fsf@flarge.here> <43204B91.3010706@nyc.rr.com> <87ll26d9ue.fsf@flarge.here> Message-ID: <87slwazoz5.fsf@flarge.here> I spend nearly the whole weekend on gettign a bit further. My code is not this: (in-package :qss.web) ;; (use-package :cells) (eval-when (:compile-toplevel :execute) (defparameter *example-app* (make-instance 'cookie-session-application :url-prefix "/ucw/examples/" :tal-generator (make-instance 'yaclml:file-system-generator :cachep t :root-directories (list *ucw-tal-root*)) :www-roots (list *ucw-tal-root*)))) ;; (register-application *default-server* *example-app*) (cells:defmodel controller (cells:model) ((view-obj :accessor view-obj :cell t :initarg :view-obj :initform (cells:c-in nil)) (db-obj :accessor db-obj :initarg :db-obj :cell t :initform (cells:c? (update-from-view cells:self))))) (clsql:def-view-class example-app () ((id :type integer :db-kind :key :accessor id :initarg :id) (tag :type string :accessor tag :initarg :tag) (description :type string :accessor description :initarg :description) (some-fk :type integer :accessor some-fk :initarg :some-fk) (some-objects :accessor some-objects :db-kind :join :db-info (:join-class other-class :retrieval :deferred :set nil :foreign-key example-id :home-key id)))) (clsql:def-view-class other-class () ((example-id :type integer :accessor example-id :initarg :example-id) (val :type string :accessor val :initarg :val))) ;; (clsql:create-view-from-class 'simple-db) (defmethod update-from-view ((controller controller)) (with-accessors ((db-obj db-obj) (view-obj view-obj)) controller (inspect controller) ;; view should steer the database object usually (let ((other (some-objects db-obj))) (setf (tag db-obj) (read-client-value (tag view-obj)) (description db-obj) (read-client-value (description view-obj)) (val other) (read-client-value (other view-obj))) (clsql:update-records-from-instance db-obj)) (values))) (defun populate-db () (let ((other (make-instance 'other-class :example-id 1 :val "some text"))) (clsql:update-records-from-instance other) (let ((mobj (make-instance 'example-app :id 1 :tag "some tag" :description "this is the description" :some-fk 1))) (setf (some-objects mobj) other) (clsql:update-records-from-instance mobj)))) ;; (clsql:drop-view-from-class 'other-class) ;; (clsql:drop-view-from-class 'example-app) ;; ;; (clsql:create-view-from-class 'example-app) ;; (clsql:create-view-from-class 'other-class) ;; (populate-db) (defcomponent example-view (simple-window-component) ((db-obj :initarg :db-obj :reader db-obj) (tag :accessor tag :initarg :tag :component (text-field :size 20 :maxlength 20)) (description :type string :accessor description :initarg :description :component (text-area-field :width 20 :height 10)) (other :accessor other :component (text-field :size 20 :maxlength 20)))) (defun setup-db () ;; open a connectoin to DB (clsql:enable-sql-reader-syntax)) ;; (setup-db) (defcomponent text (simple-window-component) ((view-text :initarg :view-text :reader view-text) (db-text :initarg :db-text :reader db-text))) (defmethod render-on ((res response) (text text)) (inspect text) (<:p "view data: " (<:as-is (view-text text))) (<:p "database data: " (<:as-is (db-text text)))) (defmethod initialize-vfd ((view example-view) (controller controller)) (let ((db-obj (db-obj controller))) (setf (some-objects db-obj) (car (clsql:select 'other-class :where [= [example-id] 1] :flatp t))) ;; (inspect db-obj) (clsql:update-records-from-instance db-obj) (setf (ucw::client-value (tag view)) (tag db-obj) (ucw::client-value (description view)) (description db-obj ) (ucw::client-value (other view )) (val (some-objects db-obj )) (view-obj controller) view) (inspect controller) (values))) (defmethod render-on ((res response) (view example-view)) ;; this is not perfect but for the example it should be enough ;; (inspect view) (let ((controller (make-instance 'controller))) (setf (db-obj controller) (slot-value view 'db-obj)) (initialize-vfd view controller) (inspect controller) ( (Friedrich Dominicus's message of "Mon, 12 Sep 2005 10:09:50 +0200") References: <871x3zg9mi.fsf@flarge.here> <43204B91.3010706@nyc.rr.com> <87ll26d9ue.fsf@flarge.here> <87slwazoz5.fsf@flarge.here> Message-ID: <87mzmizkqd.fsf@flarge.here> I got it (probably ;-), would someone mind to comment on it? (in-package :qss.web) ;; (use-package :cells) (eval-when (:compile-toplevel :execute) (defparameter *example-app* (make-instance 'cookie-session-application :url-prefix "/ucw/examples/" :tal-generator (make-instance 'yaclml:file-system-generator :cachep t :root-directories (list *ucw-tal-root*)) :www-roots (list *ucw-tal-root*)))) ;; (register-application *default-server* *example-app*) (cells:defmodel controller (cells:model) ((view-obj :accessor view-obj :cell t :initarg :view-obj :initform (cells:c-in nil)) (db-obj :accessor db-obj :initarg :db-obj :cell t :initform (cells:c? (update-from-view cells:self))))) (clsql:def-view-class example-app () ((id :type integer :db-kind :key :accessor id :initarg :id) (tag :type string :accessor tag :initarg :tag) (description :type string :accessor description :initarg :description) (some-fk :type integer :accessor some-fk :initarg :some-fk) (some-objects :accessor some-objects :db-kind :join :db-info (:join-class other-class :retrieval :deferred :set nil :foreign-key example-id :home-key id)))) (clsql:def-view-class other-class () ((example-id :type integer :accessor example-id :initarg :example-id) (val :type string :accessor val :initarg :val))) ;; (clsql:create-view-from-class 'simple-db) (defmethod update-from-view ((controller controller)) (print "in update-from-view" *error-output*) (unless (slot-value controller 'db-obj) (print "in unless " *error-output*) ;; (inspect (db-obj (view-obj controller))) (setf (slot-value controller 'db-obj) (db-obj (view-obj controller)))) ;; (inspect controller) ;; view should steer the database object usually (let* ((db-obj (slot-value controller 'db-obj)) (view (view-obj controller)) (other (some-objects db-obj))) (setf (tag db-obj) (read-client-value (tag view)) (description db-obj) (read-client-value (description view)) (val other) (read-client-value (other view))) (clsql:update-records-from-instance db-obj) (print "in update-from-view before inspect" *error-output*) (inspect controller) ;; (setf (slot-value controller 'db-obj) db-obj)) (slot-value controller 'db-obj))) (defun populate-db () (let ((other (make-instance 'other-class :example-id 1 :val "some text"))) (clsql:update-records-from-instance other) (let ((mobj (make-instance 'example-app :id 1 :tag "some tag" :description "this is the description" :some-fk 1))) (setf (some-objects mobj) other) (clsql:update-records-from-instance mobj)))) ;; (clsql:drop-view-from-class 'other-class) ;; (clsql:drop-view-from-class 'example-app) ;; ;; (clsql:create-view-from-class 'example-app) ;; (clsql:create-view-from-class 'other-class) ;; (populate-db) (defcomponent example-view (simple-window-component) ((db-obj :initarg :db-obj :reader db-obj) (tag :accessor tag :initarg :tag :component (text-field :size 20 :maxlength 20)) (description :type string :accessor description :initarg :description :component (text-area-field :width 20 :height 10)) (other :accessor other :component (text-field :size 20 :maxlength 20)))) (defun setup-db () (clsql:enable-sql-reader-syntax)) ;; (setup-db) (defcomponent text (simple-window-component) ((view-text :initarg :view-text :reader view-text) (db-text :initarg :db-text :reader db-text))) (defmethod render-on ((res response) (text text)) (inspect text) (<:p "view data: " (<:as-is (view-text text))) (<:p "database data: " (<:as-is (db-text text)))) (defmethod init-view ((view example-view)) (let ((db-obj (db-obj view))) (setf (some-objects db-obj) (car (clsql:select 'other-class :where [= [example-id] 1] :flatp t))) ;; (inspect db-obj) (clsql:update-records-from-instance db-obj) (setf (ucw::client-value (tag view)) (tag db-obj) (ucw::client-value (description view)) (description db-obj ) (ucw::client-value (other view )) (val (some-objects db-obj ))) view)) (defmethod render-on ((res response) (view example-view)) ;; this is not perfect but for the example it should be enough ;; (inspect view) (let ((controller (make-instance 'controller :view-obj (cells:c-in (init-view view))))) ;;(inspect controller) ( References: <871x3zg9mi.fsf@flarge.here> <43204B91.3010706@nyc.rr.com> <87ll26d9ue.fsf@flarge.here> <87slwazoz5.fsf@flarge.here> <87mzmizkqd.fsf@flarge.here> Message-ID: <4325DE9E.1030802@nyc.rr.com> Friedrich Dominicus wrote: >I got it (probably ;-), would someone mind to comment on it? > >(in-package :qss.web) > >;; (use-package :cells) >(eval-when (:compile-toplevel :execute) >(defparameter *example-app* > (make-instance 'cookie-session-application > :url-prefix "/ucw/examples/" > :tal-generator (make-instance 'yaclml:file-system-generator > :cachep t > :root-directories (list *ucw-tal-root*)) > :www-roots (list *ucw-tal-root*)))) > >;; (register-application *default-server* *example-app*) > >(cells:defmodel controller (cells:model) > ((view-obj :accessor view-obj :cell t > :initarg :view-obj :initform (cells:c-in nil)) > Later on in the render-on method you instantiate a controller thus: (make-instance 'controller :view-obj (cells:c-in (init-view view))) But I do not see any place in the code where you SETF the view-obj slot, so you could just: (make-instance 'controller :view-obj (init-view view)) C-IN (or C-INPUT) is used only where, in brief, the application will be using SETF to change the value in a sempahoric slot. This is partly because a dataflow model needs to get the original dataflow from somewhere, usually from operating system events or a socket. One can also sometimes get simpler and more efficient code by skipping the declarative aspect (in which a slot like view-obj would have a rule) and just make the slot C-In and then setf that slot from output methods on on other slots. But like I said, that loses the advantages of a declarative approach. Now in this case I further do not see view-obj getting involved in any cell-mediated dataflow, so I do not think it even needs to be a cell. > (db-obj :accessor db-obj :initarg :db-obj :cell t > :initform (cells:c? (update-from-view cells:self))))) > The opening bit of update-from-view says: (unless (slot-value self 'db-obj) .....) Actually, the c? macro offers any existing value as a read macro: (db-obj :accessor db-obj :initarg :db-obj :cell t :initform (cells:c? (unless .cache. (update-from-view cells:self)))) ...and then do not check for an existing slot-value in u-f-v. Now I do have rare occasion to write code like that, but the interesting thing here is that this rule only runs once, after which it would always return the same value. So there is no dataflow here, where one thing changes (by a SETF of some c-input) and then a bunch of other things get updated automatically in a cascade of rule evaluations. Maybe I missed something. My first question, does this code work for you? If so, what are the things you see happening that tell you it work? Just give me a simple scenario, such as "I start by reading in this stuff. Then I change this description field, then I exit, and when I look at the DB I see the new description text." Provide the sample code and explain where necessary which code does which step. A big problem here is that I do not know SQL or cl-sql. For example, is a view just in-memory, or does it refer to a screen view? I know a relational view is just an abstraction built atop physical tables, so maybe you are just talking about that. Well, I do see: (defcomponent example-view (simple-window-component) ((db-obj :initarg :db-obj :reader db-obj) (tag :accessor tag :initarg :tag :component (text-field :size 20 :maxlength 20)) (description :type string :accessor description :initarg :description :component (text-area-field :width 20 :height 10)) (other :accessor other :component (text-field :size 20 :maxlength 20)))) ...and that looks like a GUI view component. Maybe the term is used both ways? if you are updating a description field in a GUI view and then seeing it written back out to the DB, maybe you could lay out for me the code path by which that happens. >I this a decent use of 'cells and is it cells-ish? > Pending a better understanding of the above questions, as I said, I do not see Cells doing very much, and so I would be surprised if they help in this case. But let's see what your feedback is on the above. kt From frido at q-software-solutions.de Tue Sep 13 06:50:56 2005 From: frido at q-software-solutions.de (Friedrich Dominicus) Date: Tue, 13 Sep 2005 08:50:56 +0200 Subject: [cells-devel] my very first baby steps with cells In-Reply-To: <4325DE9E.1030802@nyc.rr.com> (Kenny Tilton's message of "Mon, 12 Sep 2005 16:01:34 -0400") References: <871x3zg9mi.fsf@flarge.here> <43204B91.3010706@nyc.rr.com> <87ll26d9ue.fsf@flarge.here> <87slwazoz5.fsf@flarge.here> <87mzmizkqd.fsf@flarge.here> <4325DE9E.1030802@nyc.rr.com> Message-ID: <87oe6xsbov.fsf@flarge.here> Kenny Tilton writes: > Friedrich Dominicus wrote: > >>I got it (probably ;-), would someone mind to comment on it? Thanks for your time. I try to explain my "convulted" way of getting into celsl a bit ;-) > > (make-instance 'controller > :view-obj (init-view view)) > > C-IN (or C-INPUT) is used only where, in brief, the application will > be using SETF to change the value in a sempahoric slot. This is partly > because a dataflow model needs to get the original dataflow from > somewhere, usually from operating system events or a socket. One can > also sometimes get simpler and more efficient code by skipping the > declarative aspect (in which a slot like view-obj would have a rule) > and just make the slot C-In and then setf that slot from output > methods on on other slots. But like I said, that loses the advantages > of a declarative approach. Well I read the explanations in 01-somwwhat and there I found if you the slot hast to be setf-able you have to use c-in (in short, so I wrote it that way. > > Now in this case I further do not see view-obj getting involved in any > cell-mediated dataflow, so I do not think it even needs to be a cell. > >> (db-obj :accessor db-obj :initarg :db-obj :cell t >> :initform (cells:c? (update-from-view cells:self))))) >> > The opening bit of update-from-view says: > > (unless (slot-value self 'db-obj) > .....) > > Actually, the c? macro offers any existing value as a read macro: > > (db-obj :accessor db-obj :initarg :db-obj :cell t > :initform (cells:c? (unless .cache. > (update-from-view cells:self)))) > I've seen the variable but was quite happy to find out the above way ;-) > ...and then do not check for an existing slot-value in u-f-v. Now I > do have rare occasion to write code like that, but the interesting > thing here is that this rule only runs once, after which it would > always return the same value. So there is no dataflow here, where one >thing changes (by a SETF of some c-input) and then a bunch of other > things get updated automatically in a cascade of rule evaluations. I do not understand that. If the view changes e.g if I use the back button of my browser I'll be back to the old view. The data will get filled from the then actual Database view, if I change something again it will get propagated again from the View to the Backend. > > Maybe I missed something. My first question, does this code work for > you? If so, what are the things you see happening that tell you it > work? Just give me a simple scenario, such as "I start by reading in > this stuff. Then I change this description field, then I exit, and > when I look at the DB I see the new description text." Provide the > sample code and explain where necessary which code does which step. See above, the back button of the browser makes it possible to return to the view. > > A big problem here is that I do not know SQL or cl-sql. For example, is a view just in-memory, or does it refer to a screen view? I know a relational view is just an abstraction built atop physical tables, so maybe you are just talking about that. Well, I do see: > > (defcomponent example-view (simple-window-component) > ((db-obj :initarg :db-obj :reader db-obj) > (tag :accessor tag :initarg :tag > :component (text-field :size 20 :maxlength 20)) > (description :type string :accessor description :initarg :description > :component (text-area-field :width 20 :height 10)) > (other :accessor other :component (text-field :size 20 :maxlength 20)))) > > ...and that looks like a GUI view component. Maybe the term is used > both ways? if you are updating a description field in a GUI view and > then seeing it written back out to the DB, maybe you could lay out for > me the code path by which that happens. That is the view-component, I just included the db-obj to start the whole thing, I see from you comments that I probably could add it in the model and there the view-obj slot. > > >> I this a decent use of 'cells and is it cells-ish? >> > Pending a better understanding of the above questions, as I said, I do > not see Cells doing very much, and so I would be surprised if they > help in this case. But let's see what your feedback is on the above. Well Cells does the following for me here. I sketch the control-flow. - the first things which is called is a view which shows two textfields and one text area - On the first run the view object should be filled with data from the backend - so I got a view with the slots filled by database values - Now I may change one, two or three fields. Aftar I send the form the database should be updated, this is done by cells here. - After that the content of both the view and the database are shown - Now it happens that I found that I made a bug and hit Back on my browser - the browser will display me the first view again, but with the changed database values - I change them again hit submit and the stuff updates my Database again. Agreed, cells does not do much here, but it's to learn how to let those objects interact. And for that it works quite nicely ;-) Regards Friedrich From ktilton at nyc.rr.com Tue Sep 13 18:04:58 2005 From: ktilton at nyc.rr.com (Kenny Tilton) Date: Tue, 13 Sep 2005 14:04:58 -0400 Subject: [cells-devel] my very first baby steps with cells In-Reply-To: <87oe6xsbov.fsf@flarge.here> References: <871x3zg9mi.fsf@flarge.here> <43204B91.3010706@nyc.rr.com> <87ll26d9ue.fsf@flarge.here> <87slwazoz5.fsf@flarge.here> <87mzmizkqd.fsf@flarge.here> <4325DE9E.1030802@nyc.rr.com> <87oe6xsbov.fsf@flarge.here> Message-ID: <432714CA.6050708@nyc.rr.com> Friedrich Dominicus wrote: >Kenny Tilton writes: > > > >>Friedrich Dominicus wrote: >> >> >> >>>I got it (probably ;-), would someone mind to comment on it? >>> >>> > >Thanks for your time. I try to explain my "convulted" way of getting >into celsl a bit ;-) > > > >> (make-instance 'controller >> :view-obj (init-view view)) >> >>C-IN (or C-INPUT) is used only where, in brief, the application will >>be using SETF to change the value in a sempahoric slot. This is partly >>because a dataflow model needs to get the original dataflow from >>somewhere, usually from operating system events or a socket. One can >>also sometimes get simpler and more efficient code by skipping the >>declarative aspect (in which a slot like view-obj would have a rule) >>and just make the slot C-In and then setf that slot from output >>methods on on other slots. But like I said, that loses the advantages >>of a declarative approach. >> >> >Well I read the explanations in 01-somwwhat and there I found if you >the slot hast to be setf-able you have to use c-in (in short, so I >wrote it that way. > I should have mentioned "...but I do not see any place in your code where you SETF view-obj". Did I miss it? > > >>Now in this case I further do not see view-obj getting involved in any >>cell-mediated dataflow, so I do not think it even needs to be a cell. >> >> >> >>> (db-obj :accessor db-obj :initarg :db-obj :cell t >>>:initform (cells:c? (update-from-view cells:self))))) >>> >>> >>> >>The opening bit of update-from-view says: >> >> (unless (slot-value self 'db-obj) >> .....) >> >>Actually, the c? macro offers any existing value as a read macro: >> >> (db-obj :accessor db-obj :initarg :db-obj :cell t >> :initform (cells:c? (unless .cache. >> (update-from-view cells:self)))) >> >> >> >I've seen the variable but was quite happy to find out the above way >;-) > That is fine if you do not mind "unsupported", ie, your code collapsing in a heap if Cells changes in some relevant way. the larger point is that, either way, after the second time this rule runs there will be no dependencies and the cell (and rule) will get optimized away. So I still do not see Cell-ish dataflow. That said,..... > > > >>...and then do not check for an existing slot-value in u-f-v. Now I >>do have rare occasion to write code like that, but the interesting >>thing here is that this rule only runs once, after which it would >>always return the same value. So there is no dataflow here, where one >>thing changes (by a SETF of some c-input) and then a bunch of other >>things get updated automatically in a cascade of rule evaluations. >> >> > >I do not understand that. If the view changes e.g if I use the back >button of my browser I'll be back to the old view. The data will get >filled from the then actual Database view, if I change something again >it will get propagated again from the View to the Backend. > I believe you! :) I just do not see the back button in the code or how this is working! I have a guess, though. I think somehow each time you are allocating all new instances, so the new cells / rules run once (the initial "awaken" pass started by TO-BE) and things show up nicely. Cells are all about long-lived state, where the same instance would survive back buttons and forward buttons and sideways buttons and still manage to stay current. That said ....... > > >>Maybe I missed something. My first question, does this code work for >>you? If so, what are the things you see happening that tell you it >>work? Just give me a simple scenario, such as "I start by reading in >>this stuff. Then I change this description field, then I exit, and >>when I look at the DB I see the new description text." Provide the >>sample code and explain where necessary which code does which step. >> >> >See above, the back button of the browser makes it possible to return >to the view. > > >>A big problem here is that I do not know SQL or cl-sql. For example, is a view just in-memory, or does it refer to a screen view? I know a relational view is just an abstraction built atop physical tables, so maybe you are just talking about that. Well, I do see: >> >> (defcomponent example-view (simple-window-component) >> ((db-obj :initarg :db-obj :reader db-obj) >> (tag :accessor tag :initarg :tag >> :component (text-field :size 20 :maxlength 20)) >> (description :type string :accessor description :initarg :description >> :component (text-area-field :width 20 :height 10)) >> (other :accessor other :component (text-field :size 20 :maxlength 20)))) >> >>...and that looks like a GUI view component. Maybe the term is used >>both ways? if you are updating a description field in a GUI view and >>then seeing it written back out to the DB, maybe you could lay out for >>me the code path by which that happens. >> >> >That is the view-component, I just included the db-obj to start the >whole thing, I see from you comments that I probably could add it >in the model and there the view-obj slot. > > >> >> >>>I this a decent use of 'cells and is it cells-ish? >>> >>> >>> >>Pending a better understanding of the above questions, as I said, I do >>not see Cells doing very much, and so I would be surprised if they >>help in this case. But let's see what your feedback is on the above. >> >> >Well Cells does the following for me here. I sketch the control-flow. >- the first things which is called is a view which shows two textfields >and one text area >- On the first run the view object should be filled with data from the > backend >- so I got a view with the slots filled by database values >- Now I may change one, two or three fields. Aftar I send the form the >database should be updated, this is done by cells here. >- After that the content of both the view and the database are shown >- Now it happens that I found that I made a bug and hit Back on my >browser >- the browser will display me the first view again, but with the >changed database values >- I change them again hit submit and the stuff updates my Database >again. > >Agreed, cells does not do much here, but it's to learn how to let >those objects interact. And for that it works quite nicely ;-) > I am going to go waaaaaaaaaaay out on a limb here and guess that the only thing Cells did was force you to structure things in a declarative way, or at least a nicely organized way, and that that itself is a big win. So it is not an issue of how long-lived is a model instance, or how many times a Cell rule runs, but how the data structures interact (as you said). I have been doing Cells for ten years, but this is the first time I have encountered this. Interesting result. Thx. -- Kenny Why Lisp? http://wiki.alu.org/RtL_Highlight_Film "I've wrestled with reality for 35 years, Doctor, and I'm happy to state I finally won out over it." Elwood P. Dowd, "Harvey", 1950 From enderx12 at mac.com Wed Sep 21 18:38:32 2005 From: enderx12 at mac.com (Chris Curtis) Date: Wed, 21 Sep 2005 14:38:32 -0400 Subject: [cells-devel] Cells/Cello+OpenMCL status? Message-ID: <52A6156B-FD2D-4F26-9343-8E75CB1FF7CE@mac.com> Hi all... I'm just starting to take a look at cells and cello and am having some problems... The first one is that loading :cells-test fails right after (CELLS::STARTING CELLS::TEST CELLS::MANY-USEDS) with "Array index 16 out of bounds for #*1111111111111111 .", the call in question being (ccl::%sbitset #*1111111111111111 16 1). Is there something I'm doing radically wrong here? Cello also fails to load, but I figured I'd start with Cells and fix one thing at a time. :-) Thanks, --chris From ktilton at nyc.rr.com Wed Sep 21 21:21:31 2005 From: ktilton at nyc.rr.com (Kenny Tilton) Date: Wed, 21 Sep 2005 17:21:31 -0400 Subject: [cells-devel] Cells/Cello+OpenMCL status? In-Reply-To: <52A6156B-FD2D-4F26-9343-8E75CB1FF7CE@mac.com> References: <52A6156B-FD2D-4F26-9343-8E75CB1FF7CE@mac.com> Message-ID: <4331CEDB.1000803@nyc.rr.com> Chris Curtis wrote: > Hi all... > > I'm just starting to take a look at cells and cello and am having > some problems... > > The first one is that loading :cells-test fails right after > (CELLS::STARTING CELLS::TEST CELLS::MANY-USEDS) with "Array index 16 > out of bounds for #*1111111111111111 .", the call in question being > (ccl::%sbitset #*1111111111111111 16 1). I will have to do some digging. FYI, that :cells-test stuff has not been maintained much, there is a test suite right in the Cells package. let me check up on all this and get back to you. kenny ps. Cello will be quite a challenge to build since it is still there for developers/porters/maintainers only. kt From enderx12 at mac.com Wed Sep 21 21:39:30 2005 From: enderx12 at mac.com (Chris Curtis) Date: Wed, 21 Sep 2005 17:39:30 -0400 Subject: [cells-devel] Cells/Cello+OpenMCL status? In-Reply-To: <4331CEDB.1000803@nyc.rr.com> References: <52A6156B-FD2D-4F26-9343-8E75CB1FF7CE@mac.com> <4331CEDB.1000803@nyc.rr.com> Message-ID: <988F346A-4537-4919-88D7-B11F023250A0@mac.com> On Sep 21, 2005, at 5:21 PM, Kenny Tilton wrote: > > > Chris Curtis wrote: > > >> Hi all... >> >> I'm just starting to take a look at cells and cello and am having >> some problems... >> >> The first one is that loading :cells-test fails right after >> (CELLS::STARTING CELLS::TEST CELLS::MANY-USEDS) with "Array index >> 16 out of bounds for #*1111111111111111 .", the call in question >> being (ccl::%sbitset #*1111111111111111 16 1). >> > > I will have to do some digging. FYI, that :cells-test stuff has not > been maintained much, there is a test suite right in the Cells > package. let me check up on all this and get back to you. > > kenny > > ps. Cello will be quite a challenge to build since it is still > there for developers/porters/maintainers only. kt > Thanks for the quick response! I've been kind of wondering what the general status of both Cells & Cello are... they seem really quite interesting. --chris From tfb at OCF.Berkeley.EDU Mon Sep 26 18:20:33 2005 From: tfb at OCF.Berkeley.EDU (Thomas F. Burdick) Date: Mon, 26 Sep 2005 11:20:33 -0700 Subject: [cells-devel] Re: [cells-cvs] CVS update: cells/cells.lpr cells/fm-utilities.lisp cells/md-utilities.lisp In-Reply-To: <20050926150543.60EC088569@common-lisp.net> References: <20050926150543.60EC088569@common-lisp.net> Message-ID: <17208.15345.23013.780018@conquest.OCF.Berkeley.EDU> Kenny Tilton writes: > +(defmacro defparts (partName (partClass &rest partDefArgs) > + &optional customArgs customValuesList > + &rest commonArgPairs) > + (assert (null partDefArgs)) > + (let ((part-no (gensym)) > + (cvls (gensym))) > + `(loop with ,cvls = (list , at customValuesList) > + for ,part-no below ,(max 1 (length customValuesList)) > + for custom-values = (elt ,part-no cvs) > + collecting (make-instance ',partClass > + :md-name ',partName > + ,@(loop for arg in customargs > + for n below (length customargs) > + nconcing (list arg `(elt ,n custom-values))) > + , at commonArgPairs)))) Hmm, not sure I get what this parts stuff is about. Something interesting? -- /|_ .-----------------------. ,' .\ / | Free Mumia Abu-Jamal! | ,--' _,' | Abolish the racist | / / | death penalty! | ( -. | `-----------------------' | ) | (`-. '--.) `. )----'