From mb at bese.it Tue Dec 7 09:42:49 2004 From: mb at bese.it (Marco Baringer) Date: Tue, 07 Dec 2004 10:42:49 +0100 Subject: [Bese-devel] ucw style, concepts and random info Message-ID: Antonio Menezes Leitao and I had an e-mail exchange in which i ended up writing a lot of stuff about the ucw "mindset" (how things should be looked at) and a couple of details which aren't easily gleanable from the docs. he's attempting to do something very cool and i figured his questions (and my answers) might be of interest to others. ======================================================================== From: "Marco Baringer" Subject: Re: UnCommonWeb/SBCL/x86 To: Antonio Menezes Leitao Date: Sat, 04 Dec 2004 15:30:56 +0100 Antonio Menezes Leitao writes: > The idea is to create a repl that reads one expression at a time, > evaluates it and prints the result...just like your example in the > admin application...but where you can also correctly evaluate an > expression such as > > (+ 1 (read)) > > In this case, during the evaluation of the expression, the client will > get a new page that reads a value and uses it during the computation. > > Even more interesting is the situation > > (+ (read) (read)) > > Here, the full power of continuations will be used as it is necessary > to read a first value, then a second one and, finally, to present the > result to the client. Obviously, we want to be able to go back to > either of the reads and proceed with different values. > > Here is my solution: > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > ;;The application > (defapplication eval-application > (:url-prefix "/ucw/eval/")) > > (defentry-point "index.ucw" (:application eval-application) () > (call 'eval-app)) > > ;;The main window > (defclass eval-app (simple-window-component) > ((body :initarg :body :accessor eval-app-body > :initform nil :component repl)) > (:metaclass standard-component-class) > (:default-initargs :title "UCW Evaluator")) [this sequence of forms really deserves a macro or something...] what do you think about adding an :entry-point initarg to the standard-component-class class? > (defmethod render-on ((res response) (app eval-app)) > (<:html > (<:head > (<:title "UCW Evaluator.")) > (<:body > (<:h1 "UCW Evaluator.") > (<:hr) > (render-on res (eval-app-body app)) > (<:hr) > (<:A :href "index.ucw" "Start again.")))) since eval-app is a simple-window-component you don't need (and really shouldn't) output <:html and <:head on its render-on method. something like this is more appropiate: (defmethod render-on ((res response) (app eval-app)) (<:h1 "UCW Evaluator") (<:hr) (render-on res (eval-app-body app)) (<:hr) (<:a :href "index.ucw" "Start again.")) thanks to simple-window-component's render-on :wrapping method this will actually get called "within" a tag and the will get set thanks to the :title initarg you passed. > ;;The read-eval-print component > (defclass repl (component) > ((form :accessor repl-form :initarg :form :initform nil) > (value :accessor repl-value :initarg :value :initform "")) > (:metaclass standard-component-class)) > > (defmethod render-on ((res response) (app repl)) > (<:div > (<:h2 "REPL") > (<ucw:form :action (evaluate-form app) > (<:p "The form: " > (<ucw:input :accessor (repl-form app)) > " " > (<:input :type "submit" :value "Evaluates to") > " " > (<:as-is (repl-value app)))))) this is exactly what i'd do. > ;;The action that is executed when we ask for the evaluation of an > ;;expression. Unfortunately, we cannot use eval because it doesn't > ;;mix with the CPS framework so we build a new one named eval/cc. > ;;Note that it is also necessary to pass the self argument. > (defaction evaluate-form ((app repl)) > (let ((expr (read-from-string (repl-form app)))) > (setf (repl-value app) > (princ-to-string > (eval/cc self expr))))) minor comment: i'd set (repl-value app) to the actual value returned by eval/cc and then convert it to a string in the render-on method (just so that you can inspect and reuse returned values). > ;;Here is our (extremely simple) eval. > (defun/cc eval/cc (self expr) > (cond ((numberp expr) expr) > ((atom expr) "Can't eval other atoms") > (t (case (first expr) > ((read) (call 'reader)) ;;special treatment of the read function > (t (apply (first expr) > (evlist/cc self (rest expr)))))))) > > (defun/cc evlist/cc (self exprs) > (if (endp exprs) > (list) > (cons (eval/cc self (first exprs)) > (evlist/cc self (rest exprs))))) this is the right idea, but will unfortunely fail with something like: (eval/cc self '(if (whatever) (read) (something-else))) since if isn't a function you can't apply it. you don't really want to have to write a code-walker, and ucw already has one, so you can (if you know about ucw internals) use the underlying machinery. before i write the code let me explain what i want to accomplish: we have a form (the result of (read-from-string (repl-form app))) which we want to eval. we also want this form to be able to use the normal call/answer machinery (hidden under the uses of read). in other words we want to evaluate an action whose body is only know at runtime, we'll use eval, but we need to put much of the action body, and some internal ucw machinery, in the eval: (defaction evaluate-form ((app repl)) (let ((expr (read-from-string (repl-form app)))) (eval `(with-call/cc (let ((self ,app)) (macrolet ((read () '(call 'reader))) (setf (repl-value ,app) (princ-to-string ,expr)))))))) let me break that apart: - we want the code in expr te be able to make calls to CALL, in order for that to work we need 2 things: the with-call/cc which will setup the proper continuations and the binding of app to self so that call-component gets the right calling-component argument. - we want the read "function" to actually call a component, instead of definig a new function (via defun/cc) we just setup a macrolet whcih transforms (read) into (CALL 'READER). - finally we do whatever the user inputed and set the value slot of app. NB: the setf form _must_ be within the with-call/cc form. this is because, deep down underneath ucw, the body of with-call/cc forms always return, if we did: (setf (repl-value app) (eval (with-call/cc ...))) then we'd have repl-value set to various components (when read was actually called) and when the reader component finally returned they wouldn't actually change the value slot. this is because the continuation created by with-call/cc can only extend as far as the with-call/cc form, since setf is outside of the with-call/cc we never manage to return from the eval. does that make any sense? > ;;Finally, the reader component. > (defclass reader (component) > ((form :accessor reader-form :initarg :form :initform nil)) > (:metaclass standard-component-class)) > > (defmethod render-on ((res response) (app reader)) > (<:div > (<:h2 "READING A VALUE") > (<ucw:form > :action (read-it app) > (<ucw:input :accessor (reader-form app)) > " " > (<:input :type "submit" :value "Take that!")))) > > ;;After reading an expression, just return it to the caller > (defaction read-it ((app reader)) > (answer (read-from-string (reader-form app)))) > ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; > > If you still have patience to read, I would like to hear your comments > on the following issues: > > - Is my application correctly done? Should I use something else? i think, other than the minor misunderstanding about simple-window-component (due a lack of documentation on my part) that's exactly what i'd do. > - It seems to me that we always need to invoke the call and answer > operations from within actions...unless we take special measures > (see below). The good thing is that we get the proper behaviour for > the 'back' button. yes, call and answer MUST be used within a defaction form. this is due to: 1) call and answer expand into uses of the defmethod/cc methods call-component and answer-component which require the presence af a lexical variable named SELF. 2) call and answer must be made within the lexical scope of with-call/cc if we want the continuation parameter to be passed automagically. you could directly use call-component and answer-component (even outside of actions) but you will have to manully set the continuation and the calling-component it the call'd component. i've occasianly used answer-component outside of defaction (mainly in render-on methods to not have to create a simple action which just does answer-component), though now i generally use the OK action. > - However, I'm not so concerned about that (admitidly nice) behavior > as I am regarding the code style I want to use (which is the usual > direct style that will be translated to CPS. I really want to be > able to invoke a "function" that demands more data from the client > without disturbing the application (even if it needs to present > another page, collect results and return them to the point that > "called" it. > > - This direct style entails that I want to be able to define all sorts > of functions and, somewhere in the middle of all those functions, > call and answer operations will be used. I presume that, in this > case, we need to define all those functions in CPS (that is, using > defun/cc and such) and, moreover, we need to pass the extra argument > self in order for call to work. That's the reason why I needed to > define my own pseudo-eval and a special read function. Is there a > workaround? In particular, it doesn't seem logical to define a > function with an extra parameter 'self' that is never used except in > some invisible transformation of a (call ...) form. unfortunetly you're hitting a hard limitiation. since ucw fakes continuations, and does not actually examine the stack, you have to put call/answer directly in the defaction (or defentry-point) and can't put calls to functions without using defun/cc (or defaction or defmethod/cc). this also requires that the defun/cc function adhere to the cps transformer's limitations (no unwind-protect around call/cc, etc.) what could be done is make self a dynamic variable, and the current binding would be captured by call-component, this would aliviate the need to pass a slef argument, but wouldn't remove the fundamental limitation. now, let's say you have an application which does a lot of "stuff," some of this "stuff" requires input from the user. what i'd do is split up the "stuff" into small enough pieces so that each user operation is handled by a single component and then tie the componets together with actions (as opposed to defun/cc). if you have a complex operation which requires a lot of input i'd do something like this: (defaction complex-operation ((app application-window)) (call 'show-result :result (do-complex-op (call 'get-arg1) (call 'get-arg2) ...)) now the (relativly) simple get-arg components can do whatever they want, once we've gotten all the input we then pass the values to a regular lisp function. if we want the user to have a menu of the options for do-complex-op and we don't want to require them to set all the values (and we provide defaults), i'd do: (defcomponent complex-operation (container) ((arg1 :component get-arg1-with-defaults) (arg2 :component get-arg2-with-defaults) ... (result :accessor result :component 'show-result)) (:metaclass standard-component-class)) (defaction do-complex-op ((op complex-operation)) (setf (value (result op)) (do-it (value (arg1 op)) (value (arg2 op)) ...))) (defmethod render-on ((res response) (op complex-operation)) (render-argument-menu) (render-do-complex-op-button) (if (have-result (result op)) (render-on res (result op)) (<:p "Output not yet available."))) basically i'd have a component which allowed the user to set the input for the operation and, when there's some output, shows the output with the supplied args. i'd have a component for every parameter which knows how to transform the user's input into a lisp value suitable for passing to the do-it function. i'd also setup the result componet so that it knows when its ready to be rendered and when it isn't. you could just as well not have result be a slot of the componet put call a show-result component from the do-complex-op action, whatever. > Thanks a lot for your time and, once again, congratulations for your > excelent framework. I'm looking forward to develop more interesting > applications. here's your example with my edits: ------------------------------------------------------------------------ (in-package :it.bese.ucw-user) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;The application (defapplication eval-application (:url-prefix "/ucw/eval/")) (defentry-point "index.ucw" (:application eval-application) () (call 'eval-app-window)) ;;The main window (defclass eval-app-window (simple-window-component) ((body :initarg :body :accessor eval-app-body :initform nil :component repl)) (:metaclass standard-component-class) (:default-initargs :title "UCW Evaluator")) (defmethod render-on ((res response) (app eval-app-window)) (<:h1 "UCW Evaluator.") (<:hr) (render-on res (eval-app-body app)) (<:hr) (<:A :href "index.ucw" "Start again.")) ;;The read-eval-print component (defclass repl (component) ((form :accessor repl-form :initarg :form :initform nil) (value :accessor repl-value :initarg :value :initform "")) (:metaclass standard-component-class)) (defmethod render-on ((res response) (app repl)) (<:div (<:h2 "REPL") (<ucw:form :action (evaluate-form app) (<:p "The form: " (<ucw:input :accessor (repl-form app)) " " (<:input :type "submit" :value "Evaluates to") " " (<:as-is (repl-value app)))))) (defaction evaluate-form ((app repl)) (let ((expr (read-from-string (repl-form app)))) (eval `(with-call/cc (let ((self ,app)) (macrolet ((read () '(call 'reader))) (setf (repl-value ,app) (princ-to-string ,expr)))))))) ;;Finally, the reader component. (defclass reader (component) ((form :accessor reader-form :initarg :form :initform nil)) (:metaclass standard-component-class)) (defmethod render-on ((res response) (app reader)) (<:div (<:h2 "READING A VALUE") (<ucw:form :action (read-it app) (<ucw:input :accessor (reader-form app)) " " (<:input :type "submit" :value "Take that!")))) ;;After reading an expression, just return it to the caller (defaction read-it ((app reader)) (answer (read-from-string (reader-form app)))) ------------------------------------------------------------------------ hope this helps. ======================================================================== -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From mb at bese.it Tue Dec 7 17:10:42 2004 From: mb at bese.it (Marco Baringer) Date: Tue, 07 Dec 2004 18:10:42 +0100 Subject: [Bese-devel] UCW 0.3.4 - learning to climb up trees Message-ID: <m2vfbec9v1.fsf@bese.it> UnCommon Web version 0.3.4 - learning to climb up trees Released 2004-12-07 * Home page http://common-lisp.net/project/ucw/ * Download ftp://ftp.common-lisp.net/pub/project/ucw/ucw_0.3.4.tar.gz * Prerequisites ** Prerequisites included in the distribution - arnesi - yaclml - cl-icu - iterate - mod_lisp ** Prerequisites you must download and install manually - a recent CVS version of SLIME. You must have the new inspector for the ucw-inspector to work. - portableaserve 1.2.35 should you want the aserve backend. * Changes (since 0.3.3) * Components - A new class, simple-window-component, provides the convience render-on method and slots. The window-component class is now used for call/answer logic only. Previously these two jobs were both handled by the window-component class, this made template based window-components impossible. - window-component now properly deals with the case where it _does_ have a calling component. This makes call'ing window-components from regular actions meaningfull. - range-view component has new cleaner api. variosu bugs and off-by-one errors have been fixed. * Component Rendering - User errors during the rendering phase are now properly dealt with (iow they don't cause an internal server error). - *print-level*, *print-length* and now set to low values when printing the backtrace (this avoids 500Kb backtrace pages). The entire data structure is still availabe by inspecting the objects. - template-component-environment now uses nconc method combination. * Component Control Flow - CALL and ANSWER can now be used in defentry-point with the "expected" semantics. The only restriction is that the called components must be subclasse of window-component. * RERL - session frames are now stored in a hash table and are never removed. this change is required to support window cloning (whethere this change should be appiled globally or a sub class of standard-session-frame should be created is still up for debate). - Errors during find-application now show an error page instead of killing the server. * Other - Created a new ucwctl script which, once properly edited for the site, can be used in /etc/init.d to control a ucw server. - UCW now loads the init.lisp file. This provides a convient place to put site specific startup code. - Obselete method definitions in the example app have been removed. - A tla config has been added to the libs directory which makes getting arnesi et al. easier. - A good deal of work has gone into the manual. * Known Issues - The transaction example does not work. - CMUCL and SBCL have a bug in the handling of :default-initargs, which UCW makes heavy use of. * Supported Platforms OpenMCL and CMUCL (with mod_lisp) backend have been tested throughly. SBCL and mod_lisp have been tested lightly. aserver backend has not been tested. -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From mb at bese.it Wed Dec 8 12:58:55 2004 From: mb at bese.it (Marco Baringer) Date: Wed, 08 Dec 2004 13:58:55 +0100 Subject: [Bese-devel] ucw with aserve Message-ID: <m2r7m19ca8.fsf@bese.it> i just want to let everyone know that ucw (0.3.3 at least) is infact being used with the aserve backend on sbcl+linux. -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From mb at bese.it Thu Dec 9 13:26:00 2004 From: mb at bese.it (Marco Baringer) Date: Thu, 09 Dec 2004 14:26:00 +0100 Subject: [Bese-devel] planning ucw 0.4.0 Message-ID: <m23byf7gd3.fsf@bese.it> i was thinking about finishing off the remaining sections of the manual, fixing the transaction example and thne tagging the current ucw as 0.4.0. there really isn't much more i'd like to add in the short term and there's a _lot_ of new stuff since 0.3.0. are there any major issues with the current ucw that i've missed? -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From ml13 at onlinehome.de Wed Dec 15 13:41:31 2004 From: ml13 at onlinehome.de (ml13 at onlinehome.de) Date: Wed, 15 Dec 2004 14:41:31 +0100 Subject: [Bese-devel] fiveam Message-ID: <078378D3-4E9F-11D9-97CA-00039345C8B0@onlinehome.de> Hi, I am just wondering whether it is intended behaviour of fiveam that tests with identical name are overwritten, even if they are in different test suites. (def-suite suite1) (in-suite suite1) (test mytest (is (= 1 2 ))) (def-suite suite2) (in-suite suite2) (test mytest (is (= 1 1))) (run! 'suite1) would result in 1 Pass, as well as (run 'suite2) Thanks for listening, Peter From mb at bese.it Wed Dec 15 16:23:27 2004 From: mb at bese.it (Marco Baringer) Date: Wed, 15 Dec 2004 17:23:27 +0100 Subject: [Bese-devel] fiveam In-Reply-To: <078378D3-4E9F-11D9-97CA-00039345C8B0@onlinehome.de> (ml's message of "Wed, 15 Dec 2004 14:41:31 +0100") References: <078378D3-4E9F-11D9-97CA-00039345C8B0@onlinehome.de> Message-ID: <m2u0qn7cow.fsf@bese.it> ml13 at onlinehome.de writes: > Hi, > > I am just wondering whether it is intended behaviour of fiveam that > tests with identical name are overwritten, even if they are in > different test suites. > [snip] > (run! 'suite1) would result in 1 Pass, as well as (run 'suite2) this is because both suites contain the same test. suites contain test names, not test objects (redefinition of tests wouldn't be as convieneint if it weren't so). tests are named by symbols, and all tests (and suites) are put into the same hash tabel, so not only can you not have two tests name mytest (in different suites) you can't even have a test and a suite with the same name. if i think about it this is probably counter intuitive, however if tests were named by their name and the name of their suite (like symbols have a name and a home package) then the value of fivam:*suite* would affect the test run by (run! 'my-test). this goes against the way i usually use fiveam (lots of relativly small suites and test which are generally run singularly). if you can convince me to change this i'll do it. if you supply a patch i'll apply it (your expectations are probably a bit more reasonable than mine). -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From pdf23ds at gmail.com Mon Dec 20 00:03:20 2004 From: pdf23ds at gmail.com (Chris Capel) Date: Sun, 19 Dec 2004 18:03:20 -0600 Subject: [Bese-devel] entry points other than index.ucw Message-ID: <737b61f304121916032b301ea1@mail.gmail.com> Hmm... I have an application with a entry point "diary.ucw". All actions lead the page to "index.ucw?blahblahblah". I think standard-action-url-generator should probably be taken out completely, as people wanting custom behavior can just define a method around generate-action-url. And then generate-action-url should probably extract the xxxx.ucw portion from the request URL. Curiously, the actions *work*, until the session expires (or something else), at which point clicking any further gives errors about a non-existent entry point. Chris Capel -- "What is it like to be a bat? What is it like to bat a bee? What is it like to be a bee being batted? What is it like to be a batted bee?" -- The Mind's I (Hofstadter, Dennet) From pdf23ds at gmail.com Mon Dec 20 00:46:02 2004 From: pdf23ds at gmail.com (Chris Capel) Date: Sun, 19 Dec 2004 18:46:02 -0600 Subject: [Bese-devel] login component question Message-ID: <737b61f3041219164637ac80d6@mail.gmail.com> Do I understand it correctly that the proper way to use the login component is to subclass it and define methods on check-credentials and login-successful (if necessary) with the new subclass? It's possible to simply define a method on check-credentials, but then it might conflict with other uses of the component elsewhere in the lisp image, and you have to subclass (I think) to use a custom login-successful. Chris Capel -- "What is it like to be a bat? What is it like to bat a bee? What is it like to be a bee being batted? What is it like to be a batted bee?" -- The Mind's I (Hofstadter, Dennet) From mb at bese.it Tue Dec 21 09:31:56 2004 From: mb at bese.it (Marco Baringer) Date: Tue, 21 Dec 2004 10:31:56 +0100 Subject: [Bese-devel] login component question In-Reply-To: <737b61f3041219164637ac80d6@mail.gmail.com> (Chris Capel's message of "Sun, 19 Dec 2004 18:46:02 -0600") References: <737b61f3041219164637ac80d6@mail.gmail.com> Message-ID: <m2acs8c7zn.fsf@bese.it> Chris Capel <pdf23ds at gmail.com> writes: > Do I understand it correctly that the proper way to use the login > component is to subclass it and define methods on check-credentials > and login-successful (if necessary) with the new subclass? It's > possible to simply define a method on check-credentials, but then it > might conflict with other uses of the component elsewhere in the lisp > image, and you have to subclass (I think) to use a custom > login-successful. correct, though nothing stops you from defining a method for check-credentials on login (and redefinig login-successful). in case anyone is curious: i do not expect anyone to directly use any of the standard components (ever). my personal expectation is that people will want to customize at least the render-on method of any compoent they use (expect maybe simple-window-component) and so will generally use subclasses of the standard components. i'll add a note to the docs saying so. -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From mb at bese.it Tue Dec 21 11:46:31 2004 From: mb at bese.it (Marco Baringer) Date: Tue, 21 Dec 2004 12:46:31 +0100 Subject: [Bese-devel] entry points other than index.ucw In-Reply-To: <737b61f304121916032b301ea1@mail.gmail.com> (Chris Capel's message of "Sun, 19 Dec 2004 18:03:20 -0600") References: <737b61f304121916032b301ea1@mail.gmail.com> Message-ID: <m2hdmfc1rc.fsf@bese.it> Chris Capel <pdf23ds at gmail.com> writes: > Hmm... > > I have an application with a entry point "diary.ucw". All actions lead > the page to "index.ucw?blahblahblah". > > I think standard-action-url-generator should probably be taken out > completely, as people wanting custom behavior can just define a method > around generate-action-url. And then generate-action-url should > probably extract the xxxx.ucw portion from the request URL. yeah, that's probably the best solution for now. what i'd like, eventually, is to allow each component to chose what the links it (or a nested component) generate. this will require a component dependency protocol (ala clim's grafting/adopting protocol), which still requires some thought. > Curiously, the actions *work*, until the session expires (or something > else), at which point clicking any further gives errors about a > non-existent entry point. that's the expected behaviour. since those urls contaion session, frame and actian parameters ucw will look at the parameters first, only when the parameters don't provide a vaild action to call (like when the session has expired) does ucw fall back on the query path (in this case "/index.ucw") and attempt to cal the entry point. -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From mb at bese.it Tue Dec 21 16:07:14 2004 From: mb at bese.it (Marco Baringer) Date: Tue, 21 Dec 2004 17:07:14 +0100 Subject: [Bese-devel] entry points other than index.ucw In-Reply-To: <737b61f30412210742588089f@mail.gmail.com> (Chris Capel's message of "Tue, 21 Dec 2004 09:42:14 -0600") References: <737b61f304121916032b301ea1@mail.gmail.com> <m2hdmfc1rc.fsf@bese.it> <737b61f30412210742588089f@mail.gmail.com> Message-ID: <m2652vab4d.fsf@bese.it> Chris Capel <pdf23ds at gmail.com> writes: >> yeah, that's probably the best solution for now. what i'd like, >> eventually, is to allow each component to chose what the links it (or >> a nested component) generate. this will require a component >> dependency protocol (ala clim's grafting/adopting protocol), which >> still requires some thought. > > I've been thinking about this too. Ideally, there would be a way to > allow an application to encode its backtracking slots into a URL like > "myapp.ucw/slot1val/slot2val" and so on. And then, only when the user > took an action which required some sort of continuations would the > session information be included (possibly in a cookie, leaving the URL > nice and pristine). So you can mix REST and continuation approaches > freely. Is something along these lines what you're thinking of? not directly, but you could do that with what i'm thinking of (tell me if this sounds too complex). i'm going to add two generic functions: parent (given a component return its parent component) and active-children (given a component returns the list of components which it will render on the next call to render-en). we will have a new method called compute-url which, given a component and an action-id, should return a uri object which will be used in forms and anchor tags (the uri class is also new). compute-url is implemented in terms of another generic function called update-url. update-url takes a component and a uri and does whatever it wants to the uri. update-url is called in parent first order so the "closest" component to the call to <ucw:a can override anything its parents have done. this means that you could, by definig the right entry-points and the "right" compute-url and update-url, methods create either wiki style links, REST style links, the with backtracking urls you mentioned above (excellent idea), or anything else you wanted. that's the idea at least, i'm working on this now and we'll see if in practice it turns out as nice as it sounds. > Chris Capel > -- > "What is it like to be a bat? What is it like to bat a bee? What is it > like to be a bee being batted? What is it like to be a batted bee?" > -- The Mind's I (Hofstadter, Dennet) this has been stuck in my head all f'cking day :) -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From pdf23ds at gmail.com Tue Dec 21 15:42:14 2004 From: pdf23ds at gmail.com (Chris Capel) Date: Tue, 21 Dec 2004 09:42:14 -0600 Subject: [Bese-devel] entry points other than index.ucw In-Reply-To: <m2hdmfc1rc.fsf@bese.it> References: <737b61f304121916032b301ea1@mail.gmail.com> <m2hdmfc1rc.fsf@bese.it> Message-ID: <737b61f30412210742588089f@mail.gmail.com> On Tue, 21 Dec 2004 12:46:31 +0100, Marco Baringer <mb at bese.it> wrote: > Chris Capel <pdf23ds at gmail.com> writes: > > > Hmm... > > > > I have an application with a entry point "diary.ucw". All actions lead > > the page to "index.ucw?blahblahblah". > > > > I think standard-action-url-generator should probably be taken out > > completely, as people wanting custom behavior can just define a method > > around generate-action-url. And then generate-action-url should > > probably extract the xxxx.ucw portion from the request URL. > > yeah, that's probably the best solution for now. what i'd like, > eventually, is to allow each component to chose what the links it (or > a nested component) generate. this will require a component > dependency protocol (ala clim's grafting/adopting protocol), which > still requires some thought. I've been thinking about this too. Ideally, there would be a way to allow an application to encode its backtracking slots into a URL like "myapp.ucw/slot1val/slot2val" and so on. And then, only when the user took an action which required some sort of continuations would the session information be included (possibly in a cookie, leaving the URL nice and pristine). So you can mix REST and continuation approaches freely. Is something along these lines what you're thinking of? Chris Capel -- "What is it like to be a bat? What is it like to bat a bee? What is it like to be a bee being batted? What is it like to be a batted bee?" -- The Mind's I (Hofstadter, Dennet) From mb at bese.it Wed Dec 22 12:07:55 2004 From: mb at bese.it (Marco Baringer) Date: Wed, 22 Dec 2004 13:07:55 +0100 Subject: [Bese-devel] entry points other than index.ucw In-Reply-To: <m2652vab4d.fsf@bese.it> (Marco Baringer's message of "Tue, 21 Dec 2004 17:07:14 +0100") References: <737b61f304121916032b301ea1@mail.gmail.com> <m2hdmfc1rc.fsf@bese.it> <737b61f30412210742588089f@mail.gmail.com> <m2652vab4d.fsf@bese.it> Message-ID: <m2y8fqr0x0.fsf@bese.it> "Marco Baringer" <mb at bese.it> writes: > this means that you could, by definig the right entry-points and the > "right" compute-url and update-url, methods create either wiki style > links, REST style links, the with backtracking urls you mentioned > above (excellent idea), or anything else you wanted. that's the idea > at least, i'm working on this now and we'll see if in practice it > turns out as nice as it sounds. i just commited it (turned out to be a pretty small change too). here's the code which will allow the example app's counter component's links to work across sessions: (defentry-point "counter.ucw" (:application example-app) ((value "0")) (let* ((example (make-instance 'example-app)) (body (example-app.body example)) (counter (ucw::find-component body 'counter))) (setf (container.current-component-name (example-app.body example)) 'counter (value counter) (or (parse-integer value :junk-allowed t) 0)) (call-component self example))) (defmethod update-url ((counter counter) url) (setf (ucw::uri.path url) "counter.ucw") (push (cons "value" (princ-to-string (value counter))) (ucw::uri.query url))) the counter.ucw entry-point is complicated only because it has to recreate the rest of the example app as well. i started implemnetating a generic "save all backtrack'd slots to url" function, but this would require marshalling/unmarshilling issues i don't want to get into right now. there is one issue though: in the counter app the urls are generated with the current (when the link is created) value of the counter. this means that: if you're looking at a counter page and the value on the screen is 2 and then you decrement you'll bee looking at 1. if you let the session expire and reload the page you'll be looking at 2 again, and not 1, since the value in the url of the page is 2 which was the value when the link generated. it may be neccessary to calculate urls _before_ the action is called, we'll see. (if nothing else it's a good start.) -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen From pdf23ds at gmail.com Tue Dec 28 09:29:06 2004 From: pdf23ds at gmail.com (Chris Capel) Date: Tue, 28 Dec 2004 03:29:06 -0600 Subject: [Bese-devel] Example patches, arch collaberation Message-ID: <737b61f304122801297d7f95ba@mail.gmail.com> I've made a couple changes to example.lisp that I think make it clearer. First, I renamed the example component to "example-component" instead of "example-app" so that it's clear in the method specializers that the source is referencing the component class and not the application. Second, I added a comment to the defapplication form to explain the use of the :server option. I think the example could use some more improvement. For one, I'm mystifyed by the tranasaction example. I played around with it for a while and couldn't figure out what a transaction *does*. You might add a comment, or make the messages during the transaction more verbose. I published these changes in a mirror of my archive, at http://pdf23ds.net/arch/ in the ucw--chris--0.3 branch. If I've configured it correctly you should be able to do a star-merge to commit it to the main archive (or you could use the set-tree-version trick, as I've merged with patch-181). Do you have a preferred method? I think this is the best arrangement unless I have write access to the archive. Chris Capel -- "What is it like to be a bat? What is it like to bat a bee? What is it like to be a bee being batted? What is it like to be a batted bee?" -- The Mind's I (Hofstadter, Dennet) From mb at bese.it Tue Dec 28 11:10:55 2004 From: mb at bese.it (Marco Baringer) Date: Tue, 28 Dec 2004 12:10:55 +0100 Subject: [Bese-devel] Example patches, arch collaberation In-Reply-To: <737b61f304122801297d7f95ba@mail.gmail.com> (Chris Capel's message of "Tue, 28 Dec 2004 03:29:06 -0600") References: <737b61f304122801297d7f95ba@mail.gmail.com> Message-ID: <m2brceekzk.fsf@bese.it> Chris Capel <pdf23ds at gmail.com> writes: > I've made a couple changes to example.lisp that I think make it > clearer. First, I renamed the example component to "example-component" > instead of "example-app" so that it's clear in the method specializers > that the source is referencing the component class and not the > application. > > Second, I added a comment to the defapplication form to explain the > use of the :server option. cool. [i had never dawned on me that you could use pass NIL to :server and use register-application later :)] > I think the example could use some more improvement. For one, I'm > mystifyed by the tranasaction example. I played around with it for a > while and couldn't figure out what a transaction *does*. You might add > a comment, or make the messages during the transaction more verbose. i'll do that. > I published these changes in a mirror of my archive, at > http://pdf23ds.net/arch/ in the ucw--chris--0.3 branch. If I've > configured it correctly you should be able to do a star-merge to > commit it to the main archive (or you could use the set-tree-version > trick, as I've merged with patch-181). Do you have a preferred method? > I think this is the best arrangement unless I have write access to the > archive. i think that's best for now, should the need arise (iow should i become a bottle neck) i'll give you write access to the main repo (or we'll mention your repo on the ucw pages). p.s. - i'm leaving for vacation tomorrow, don't take it personally if i ignore the list for the next two weeks. -- -Marco Ring the bells that still can ring. Forget your perfect offering. There is a crack in everything. That's how the light gets in. -Leonard Cohen