--- /home/tyc20/temp/getting-started.txt 2009-01-15 21:56:13.000000000 +1300 +++ /home/tyc20/temp/getting-started2.txt 2009-01-15 23:46:37.000000000 +1300 @@ -70,10 +70,10 @@ to explain UCW from the bottom up. Hopefully this will serve to demistify both the operation and the purpose of these features. -We'll start with an explaination of the "Standard" web application +We'll start with an explanation of the "Standard" web application features of UCW, such as session management and html generation, and -leads towards the advanced features, like the Component Oriented UI -and Linear Page Flow Logic using continuations. +lead towards the advanced features, like the Component Oriented UI and +Linear Page Flow Logic using continuations. Due to this bottom up approach, some of the early example code may seem long-winded and convoluted. Don't let that scare you off, it @@ -87,7 +87,7 @@ extensibility, UCW is suitable for all types of web applications. The more advanced features of UncommonWeb are especially suited for highly stateful applications with a complex control flow. The developer is -free to use an much or as little of the RERL as desired for any given +free to use as much or as little of the RERL as desired for any given request. One can freely intermix a REST-style with a heavily stateful CPS approach where appropriate. This manual will demonstrate both approaches, but will focus on the unique features of UCW and assume @@ -112,7 +112,7 @@ class. This backend will be included as part of a SERVER object. The BACKEND, for each request, is responsible for creating REQUEST and RESPONSE objects, and the three objects are passed to -HANDLE-REQUEST. This method sets up the UCW enviroment and passed +HANDLE-REQUEST. This method sets up the UCW enviroment and passes control to the SERVER object. The SERVER object is the logical 'server', through which all requests @@ -130,13 +130,12 @@ *** Applications and Dispatchers -An APPLICATION is just that, a cohesive collection of features. It's -main responsibilty in UCW is as a containter for DISPATCHERS and -ENTRY-POINTS, and as a place to store the SESSION objects. An -APPLICTION will attempt to match the REQUEST against its -DISPATCHERS. By default, there are two types of dispatchers that will -delegate their requests to the RERL, those created as ENTRY-POINTS and -ACTION dispatchers. +An APPLICATION is just that, a cohesive collection of features. Its +main responsibility in UCW is as a container for DISPATCHERS and +ENTRY-POINTS, and as a place to store SESSION objects. An APPLICATION +will attempt to match the REQUEST against its DISPATCHERS. By default, +there are two types of dispatchers that will delegate their requests +to the RERL, those created as ENTRY-POINTS and ACTION dispatchers. (defclass example-application (standard-application @@ -151,9 +150,9 @@ So, when a backend receives a request and passes it to ucw, the server object searches for a matching application (in our case matched via a -url-prefix). The application matches the request object against -against its dispatchers, and if a match is found that dispatcher calls -its handler function. +url-prefix). The application matches the request object against its +dispatchers, and if a match is found, that dispatcher calls its +handler function. ** The EVAL and RESPONSE stages. @@ -178,22 +177,21 @@ should be able to see a "Hello World" in your browser. The :WITH-CALL/CC option is set to NIL here. This is not strictly -neccesary, but were not using UCW's continuation based features yet, -so we can gain a minor performance increase by avoiding the overhead -of the CPS interpreter. +neccesary, but since we are not using UCW's continuation based +features yet, we can gain a minor performance increase by avoiding the +overhead of the CPS interpreter. Also, notice the *CONTEXT* special variable. Within the RERL, *CONTEXT* is always bound to the current REQUEST-CONTEXT. See protocol.lisp for an overview of what's available via *CONTEXT*. The HTML-STREAM of the RESPONSE object contains a stream that will write -to the users browser, and here we simply use FORMAT to write our -message. +to the user's browser. Here we simply use FORMAT to write our message. -*** Entry Points with Arguements (GET/POST parameters part 1) +*** Entry Points with Arguments (GET/POST parameters part 1) An entry point is very much like the concept of a 'page' or 'file' in other frameworks/languages... with all the issues that entails. While -a developer should avoid putting too much logic and presenation code +a developer should avoid putting too much logic and presentation code in an entry point, there are a number of cases where it is quite useful. @@ -209,7 +207,7 @@ "Hello ~A" message)) In this example, hitting "http://localhost:8000/example/hello2.ucw" -will producde our standard greeting. We can change the greeting like +will produce our standard greeting. We can change the greeting like "http://localhost:8000/example/hello2.ucw?message=Universe". This will display "Hello Universe" as expected. @@ -225,12 +223,12 @@ Internally, UCW uses the YACLML macro language to generate HTML, so that is the path of least resistance. For developers who prefer to -generate thier HTML from templates, UCW also includes support for TAL, +generate their HTML from templates, UCW also includes support for TAL, an xml template language. We'll only look at YACLML here, but it is trivial to add support for other methods. YACLML tag macros are defined on symbols in a package named "<". This -means that calls to the HTML macros look a little like HTML, an tags +means that calls to the HTML macros look a little like HTML, so tags are easily distinguised from lisp code. Attributes are supplied as keyword arguments, and must appear directly after the tag name. @@ -257,17 +255,20 @@ ((message nil)) (render-page-wrapper "UCW Example" (lambda () - (<:style ".message {font-size:2em;font-weight:bold") + (<:style ".message {font-size:2em;font-weight:bold}") (if message (render-message message) (render-message-form 'message))))) -This should serve to demonstrate yacml, and also show you a simple use of the FORM tag. Indeed, one could build an entire application this way, composing functions and entry points. However, we have only scratched the surface of what UCW can do for you. +This should serve to demonstrate yacml, and also show you a simple use +of the FORM tag. Indeed, one could build an entire application this +way, composing functions and entry points. However, we have only +scratched the surface of what UCW can do for you. *** UCW Components, a UI toolkit for the web. Up to this point we've been well within the realm of standard web -development. While building application in this style is possible, It +development. While building applications in this style is possible, it gets messy quickly. The control flow of our application is obscured by the manner in which we must keep state, by passing variables via get or post, and our display code, though nicely factored out into @@ -287,10 +288,10 @@ (:metaclass standard-component-class)) (defmethod render :before ((self example-message)) - (<:style ".message {font-size:2em;font-weight:bold")) + (<:style ".message {font-size:2em;font-weight:bold}")) (defmethod render ((self example-message)) - (render-message (message self))) + (render-message (message self))) (defclass example-form () () @@ -300,7 +301,7 @@ (render-message-form 'message)) We've created a couple of simple components here. In this very basic -example, using components over functions buys us very little.. it's +example, using components over functions buys us very little. It's more verbose and there's more overhead. However, components play an important role when using UCW's advanced control flow features, and it is useful to abstract the RENDERing to a single method. @@ -328,13 +329,13 @@ (defmethod render ((window example-window)) (render (window.body window))) -This should be pretty self-explanitory, but do take note of the body +This should be pretty self-explanatory, but do take note of the body slot with the :component initarg. This next utility function will help us clean up our entry point, and also serves to show how one might 'manually' render a component. In general, UCW calls the RENDER method as part of the RERL. However, in -this case we never pass control to a component (we havn't made it to +this case we never pass control to a component (we haven't made it to control flow yet), so something like this is neccessary. (defun render-example-window (body-component-name @@ -358,7 +359,7 @@ It must be said that components can do a lot more than encapsulate the display code. Components can call other components, which can answer -with real lisp values. Components are also conveinent places to store data +with real lisp values. Components are also convenient places to store data related to the application that one might traditionally keep in a 'session' variable. @@ -366,7 +367,7 @@ Up until this very point, we've basically been doing CGI in lisp. Form variables were used to keep state, in proper REST fashion, and as such -the actual control flow is hidden in an adhoc state machine. Wouldn't +the actual control flow is hidden in an ad hoc state machine. Wouldn't it be nice to simply be able to say something like: (unless message @@ -388,7 +389,7 @@ this reason), or you can append it to any URLs you render within that session. -If the session is not stored in a cookie, UCW expects to se it passed +If the session is not stored in a cookie, UCW expects to see it passed via GET or POST as a parameter named, oddly enough, +session-parameter-name+. This behavior can be changed at the dispatcher level. @@ -413,7 +414,7 @@ from the session. and display the reset link. We can reuse the same form as well. -(defclass example-session-message (example-message)() +(defclass example-session-message (example-message) () (:metaclass standard-component-class)) (defmethod message ((self example-session-message)) @@ -430,8 +431,8 @@ And again, an entry point to bring it all together. We still have way -too much logic in our entry points.. we're basically still making web -pages here. The next section is the beginning of the end of this, i +too much logic in our entry points... we're basically still making web +pages here. The next section is the beginning of the end of this, I promise. (defentry-point "hello-session.ucw" @@ -456,23 +457,23 @@ and a host of other things that web users do to innocent session-based applications. -UCW adds another object to the equation.. a FRAME. A frame represents -an indivual hit, a page rendered .. an interaction with the +UCW adds another object to the equation... a FRAME. A frame represents +an individual hit, a page rendered... an interaction with the application. When a session is created, an initial frame is created. Other hits to the same session might create other frames.. so a frame is like a point in time. Usually, frames are created as required to maintain state. FRAMES are used to store two important types of data, ACTIONS and -CALLBACKS. Actions are essentially functions.. they run to side-effect -the components that will be displayed. CALLBACKS, are setters. Usually +CALLBACKS. Actions are essentially functions... they run to side-effect +the components that will be displayed. CALLBACKS are setters. Usually called before an ACTION is run, callbacks take values from GET and POST variables and call a function on them. Most often this function uses the value to set a slot or a variable. A good example of an action is our reset functionality. Having to pass a variable to an entry point is not at the level of abstraction we'd -like to be working in.. i want a reset function to run when a user +like to be working in... I want a reset function to run when a user clicks a reset link, and damn the details. Since we are still not using UCW's control flow features, we have to do @@ -494,28 +495,27 @@ (setf (uri.path url) (entry-point component)) url)) -One might use this technique to create 'bookmarkable' or permenent +One might use this technique to create 'bookmarkable' or permanent URLs within an application that uses the control flow features. Also, a FRAME can contain a top level WINDOW-COMPONENT. If it exists, the RENDER method will be called on it. We can use this to create the -primitive control flow operator i mentioned earler. +primitive control flow operator mentioned earlier. (defun go-to (body-component-name - &rest initargs) + &rest initargs) (setf (frame.window-component (context.current-frame *context*)) (make-instance 'example-window :body (apply #'make-instance body-component-name - initargs)) -)) + initargs)))) **** Actions Next, we'll use the compute-url method, along with REGISTER-ACTION, to create a function that is attached to a URL. When that URL is -reqested, the function will be called, within the context of the +requested, the function will be called, within the context of the requests and components we've created. (defclass action-reset-link-mixin () ()) @@ -531,7 +531,7 @@ (<:a :href (print-uri-to-string url) "Reset Message"))) -In RENDER-RESET-LINK, we register an action ( a closure) in the +In RENDER-RESET-LINK, we register an action (a closure) in the current frame. That action is given a unique id that is used by COMPUTE-URL, and with the changes we made to it produces the correct magic url. Again note that we specify that no call/cc is needed here. @@ -566,7 +566,7 @@ We are still passing in MESSAGE via a GET parameter. CALLBACKS, like actions, allow you to specify a function that will be run when certain -parameters are passed via the url. unlike actions, callbacks accept a +parameters are passed via the url. Unlike actions, callbacks accept a value, and can be used as setters for input from forms or urls. (defclass example-callback-form (example-form) @@ -606,8 +606,7 @@ don't need to associate our compnents with an entry point anymore. (defclass example-callback-message (example-session-message - action-reset-link-mixin -) + action-reset-link-mixin) () (:metaclass standard-component-class)) @@ -616,9 +615,9 @@ (go-to 'example-callback-form)) -And breakin it back down, the entry point. Notice the lack of -arguments.. we are now storing all state on the server and handling -form/url arguments seamlessly.We could, of course, still use entry +Returning to the defentry-point declaration, notice the lack of +arguments... we are now storing all state on the server and handling +form/url arguments seamlessly. We could, of course, still use entry point arguments where it makes sense, but we no longer have to do so for most uses. @@ -634,7 +633,7 @@ Although i have to admit that our GO-TO version is a minor improvement over the ad hoc state machine, it's still GOTO, and we've come a long -way since Qbasic, havn't we. Besides, LAMBDA is the ultimate GOTO, and +way since Qbasic, haven't we. Besides, LAMBDA is the ultimate GOTO, and we're lispers. The problem with the above approach is that our message needs to know @@ -648,7 +647,7 @@ Two methods, CALL and ANSWER, are the high level control flow operators. CALL is like FUNCALL for components, and ANSWER like -return. Using these, we can make our message component into a generic +return. Using these, we can turn our message component into a generic input component with ease. (defclass example-control-flow-form (example-form) @@ -657,18 +656,21 @@ :initform "Enter a new message:")) (:metaclass standard-component-class)) -(defmethod render ((self example-callback-form)) (let ((input "")) - (