diff --git a/contrib/cont-responder/tutorial.txt b/contrib/cont-responder/tutorial.txt deleted file mode 100644 index fd1e9ef53d..0000000000 --- a/contrib/cont-responder/tutorial.txt +++ /dev/null @@ -1,684 +0,0 @@ -Overview -======== - -The 'cont-responder' library is a continuation based web server -for writing web applications in Factor. Each 'web application' is a -standard Factor httpd responder. - -This document outlines how to write simple web applications using -'cont-responder' by showing examples. It does not attempt to go into -the technical details of continuation based web applications or how it -is implemented in Factor. Instead it uses a series of examples that -can be immediately tried at the Factor prompt to get a feel for how -things work. - -Getting Started -=============== -To get started you will first need to load the 'cont-responder' -code. You will need the following as a minimum: - - "cont-responder.factor" run-file - "cont-utils.factor" run-file - USE: cont-responder - USE: cont-utils - -The responders that you will be writing will require an instance of -the httpd server to be running. It will be run in a background thread -to enable the interactive development of the applications. The -following is a simple function to start the server on port 8888 and -restart it if an error occurs: - - USE: httpd - USE: threads - : start-httpd [ 8888 httpd ] [ dup . flush [ start-httpd ] when* ] catch ; - [ start-httpd ] in-thread - -Responders -========== -A 'responder' is a word that is registered with the httpd server that -gets run when the client accesses a particular URL. When run that word -has 'standard output' bound in such a way that all output goes to the -clients web browser. - -In the 'cont-responder' system the word used to set output to go to the web -browser and display a page is 'show'. Think of it as 'show a page to -the client'. 'show' takes a single item on the stack and that is a -'page generation' quotation. - -A 'page generation' quotation is a quotation with stack effect -( string -- ). For now we'll ignore the string it receives on the -stack. Its purpose will be explained later. - -Hello World 1 -============= -A simple 'hello world' responder would be: - - : hello-world1 ( -- ) - [ - drop - "
"This is a paragraph" write
- =>This is a paragraph
- -You can write open and close tags like orginary HTML and anything sent -to standard output in between the tags will be enclosed in the -specified tags. Attributes can also be used: - -"More text" write
- =>More text
- -The attribute must be seperated from the value of that attribute via -whitespace. If you are using attributes the tag must be closed with a -'[tagname]>' where the [tagname] is the name of the tag used. See the -'' example above. - -You can use any factor code at any point: - - "text-align: " "red" -
- "Using style " write swap write write -
- =>Using style text-align: red
- -Tags that are not normally closed are written using XML style closed -tag (ie. with a trailing slash): - - "One" writetag so it is -formatted correctly. - - : memory-stats1 ( -- ) - [ - drop - -"Memory Statistics" write - -
"Total Data Memory" write | -room unparse write | -
"Free Data Memory" write | -unparse write | -
"Total Code Memory" write | -unparse write | -
"Free Code Memory" write | -unparse write | -
room.- - ] show drop ; - - "memorystats1" [ memory-stats1 ] install-cont-responder - -Accessing this page will show a table with the current memory -statistics. Hitting refresh will update the page with the latest -information. - -The HTML output can be refactored into different words. For example: - - : memory-stats-table ( free total -- ) - #! Output a table containing the given statistics. -
"Total Data Memory" write | -unparse write | -
"Free Data Memory" write | -unparse write | -
"Page 1" write
- - - - ] show drop - [ - -"Page 2" write
- - - - ] show drop - [ - drop - -"Page 3" write
- - - ] show drop ; - - "flowexample1" [ flow-example1 ] install-cont-responder - -The 'flow-example1' word contains three 'show' calls in a row. The -first two display simple pages with an anchor link to the URL received -on the stack. This URL when accessed resumes the computation. The -final page just drops the URL. - -When you display this example in the browser you'll be able to click -the URL to navigate. You can use the back button to retry the URL's, -you can clone the browser window and navigate them independantly, etc. - -The similarity of the functions above shows that some refactoring -would be useful. The pages are almost exactly the same so we seperate -this into a seperate word: - - : show-flow-page ( n bool -- ) - #! Show a page in the flow, using 'n' as the page number - #! to display. If 'bool' is true display a link to the - #! next page. - [ ( n bool url -- ) - -"Page " write rot unparse write
- swap [ - - ] [ - drop - ] ifte - - - ] show 3drop ; - - : flow-example2 ( n -- ) - #! Display the given number of pages in a row. - dup pred [ succ t show-flow-page ] times* - f show-flow-page ; - - "flowexample2" [ 5 flow-example2 ] install-cont-responder - -In this example the 'show-flow-age' pulls the page number off the -stack. It also gets whether or not to display the link to the next -page. - -Notice that after the show that a '3drop' is done whereas -previously we've only done a single 'drop'. This is due to a side -effect of 'show' using continuations. - -After the 'show' call returns there will be one item on the stack -(which we've been dropping and will explain later what it is). The -stack will also be set as it was before the show call. So in this case -the 'n' and 'bool' remain on the stack even though they were removed -during the page generation quotation. This is because we resumed the -continuation which, when captured, had those items on the stack. The -general rule of thumb is you will need to account for items on the -stack before the show call. - -This example also demonstrates using the 'times*' combinator to -sequence the page shows. Any Factor code can be called and the -continuation based system will sequentially display each page. The -back button, browser window cloning, etc will all continue to work. - -You'll notice the URL's in the browser have an 'id' query parameter with -a number as its value. This is the 'continuation identifier' which is -like a session id except that it identifies not just the data you have -stored but your location within the responder as well. - -Forms and POST data -=================== -The web pages we've generated so far don't accept input from the -user. I've mentioned previously that 'show' returns a value on the -stack and we've been dropping it in our examples. - -The value returned is a namespace containing the field names and -values of any POST data in the request. If no POST data exists then it -is the boolean value 'f'. - -To process input from the user just put a form in the HTML with a -method of 'POST' and an action set to the URL passed in to the page -generation quotation. The show call will then return a namespace -containing this data. Here is a simple example: - - : accept-users-name ( -- name ) - #! Display an HTML requesting the users name. Push - #! the name the user input on the stack.. - [ - -accept-users-name write ", Good to see you!" write
- - - ] show drop ; - - "post-example1" [ post-example1 ] install-cont-responder - -The 'accept-users-name' word displays an HTML form allowing input of -the name. When that form is submitted the namespace containing the -data is returned by 'show'. We bind to it and retrieve the 'username' -field. The name used here should be the same name used when creating -the field in the HTML. - -'post-example1' then does something a bit tricky. Instead of first -calling 'accept-users-name' to push the name on the stack and then -displaying the resulting page we call 'accept-users-name' from within -the page itself when we actually need it. The magic of the -continuation system causes the 'accept-users-name' to be called when -needed displaying that page first. It is certainly possible to do it -the other way though: - - : post-example2 ( -- ) - accept-users-name - [ ( name url -- ) - drop - -write ", Good to see you!" write
- - - ] show 2drop ; - - "post-example2" [ post-example2 ] install-cont-responder - -Either way works. Notice that in the 'post-example2' we had to do a -'2drop' instead of a 'drop' at the end of the show to remove the -additional 'name' that is on the stack. This wasn't needed in -'post-example1' because the 'name' was not on the stack at the time of -the 'show' call. - -Associating URL's with words -============================ -A web page can contain URL's that when clicked perform some -action. This may be to display other pages, or to affect some server -state. - -The 'cont-responder' system enables an URL to be associated with any -Factor quotation. This quotation will be run when the URL is -clicked. When that quotation exits control is returned to the page -that contained the call. - -The word that enables this is 'quot-href'. It takes two items on the -stack. One is the text to display for the link. The other is the -quotation to run when the link is clicked. This quotation should have -stack effect ( -- ). - -This example displays a number which can be incremented or -decremented. - -0 "counter" set - -: counter-example1 ( - ) - #! Display a global counter which can be incremented or decremented - #! using anchors. - #! - #! We don't need the 'url' argument - [ - drop - - -"++" [ "counter" get succ "counter" set ] quot-href - "--" [ "counter" get pred "counter" set ] quot-href -
- - - ] show - drop ; - - "counter-example1" [ counter-example1 ] install-cont-responder - -Accessing this example from the web browser will display a count of -zero. Clicking '++' or '--' will increment or decrement the count -respectively. This is done by calling a quotation that either -increments or decrements the count when the URL's are clicked. - -Because the count is 'global' in this example, if you clone the -browser window with the count set to a specific value and increment -it, and then refresh the original browser window you will see the most -recent incremented state. This gives you 'shopping cart' like state -whereby using the back button or cloning windows shows a view of a -single global value that can be modified by all browser -instances. ie. The state is not backtracked when the back button is -used. - -You'll notice that when you visit the root URL for the responder that -the count is reset back to zero. This is because when the responder -was installed the value of zero was in the namespace stack. This stack -is copied when the responder is installed resulting in initial -accesses to the URL having the starting value. This gives you 'server -side session data' for free. - -Local State -=========== -You can also have a counter value with 'local' state. That is, cloning -the browser window will give you a new independant state value that -can be incremented. Going to the original browser window and -refreshing will show the original value which can be incremented or -decremented seperately from that value in the cloned window. With this -type of state, using the back button results in 'backtracking' the -state value. - -A way to get 'local' state is to store values on the stack itself -rather than a namespace: - -: counter-example2 ( count - ) - [ ( count URL -- ) - drop - - -"++" over [ succ counter-example2 ] cons quot-href - "--" swap [ pred counter-example2 ] cons quot-href -
- - - ] show - drop ; - - "counter-example2" [ 0 counter-example2 ] install-cont-responder - -This example works by taking the value of the counter and consing it -to a code quotation that will increment or decrement it then call the -responder again. So if the counter value is '5' the two 'quot-href' -calls become the equivalent of: - - "++" [ 5 succ counter-example2 ] cons quot-href - "--" [ 5 pred counter-example2 ] cons quot-href - -Because it calls itself with the new count value the state is -remembered for that page only. This means that each page has an -independant count value. You can clone or use the back button and all -browser windows have an independant value. - -Calling 'Subroutines' -===================== -Being able to call other page display functions from 'quot-href' gives -you subroutine like functionality in your web pages. A simple menu -that displays a sequence of pages and returns back to the main page is -very easy: - - : show-page ( n -- ) - #! Show a page in the flow, using 'n' as the page number - #! to display. - [ ( n url -- ) - -"Page " write swap unparse write
- - - - ] show 2drop ; - - : show-some-pages ( n -- ) - #! Display the given number of pages in a row. - [ succ show-page ] times* ; - - : subroutine-example1 ( -- ) - [ - -"Please select:" write -
Please select: -
- - - - -We can continue to drill down using 'test-cont-click' using the URL's -above to see the HTML for each 'click'. - -Here's an example using post data. We'll test the 'post-example1' word -written previously: - -Chris, Good to see you!
- - - -As you can see the post data was sent correctly. \ No newline at end of file