]> gitweb.factorcode.org Git - factor.git/commitdiff
Refactorings of the cont-responder and sqlite code. The browser
authorChris Double <chris.double@double.co.nz>
Sun, 13 Feb 2005 01:08:32 +0000 (01:08 +0000)
committerChris Double <chris.double@double.co.nz>
Sun, 13 Feb 2005 01:08:32 +0000 (01:08 +0000)
responder now accepts 'word' and 'vocab' as query parameters. The
cont-responder takes the continuation id as a query parameter instead of
part of the url.

contrib/cont-responder/browser.factor
contrib/cont-responder/cont-responder.factor
contrib/cont-responder/cont-testing.factor
contrib/cont-responder/live-updater.factor
contrib/cont-responder/todo-example.factor
contrib/cont-responder/tutorial.txt
contrib/sqlite/sqlite.factor
contrib/sqlite/test.factor

index db7c92df5dbafcc028921668ebebf58f9eb35992..3431dd0e4d19c865f9756e6522735d344f8dea1a 100644 (file)
@@ -45,6 +45,7 @@ USE: errors
 USE: unparser
 USE: logging
 USE: listener
+USE: url-encoding
 
 : <browser> ( allow-edit? vocab word -- )
   #! An object for storing the current browser
@@ -187,6 +188,15 @@ USE: listener
     ] when*
   ] catch ;
 
+: browser-url ( vocab word -- url )
+  #! Given a vocabulary and word as strings, return a browser
+  #! URL which, when requested, will display the source to that
+  #! word.
+  [ 
+    ".?word=" , url-encode ,
+    "&vocab=" , url-encode ,
+  ] make-string ;
+
 : browse ( <browser> -- )
   #! Display a Smalltalk like browser for exploring/modifying words.
   [
@@ -213,15 +223,22 @@ USE: listener
       ] extend
     ] bind [
       "allow-edit?" get
-      "vocabs" get
-      "words" get
+      "vocabs" get 
+      "words" get 
       "eval" get dup [ "vocabs" get swap eval-string ] [ drop ] ifte
+      [
+       "vocabs" get "words" get browser-url forward-to-url
+      ] show
     ] bind <browser>
   ] forever ;
 
 : browser-responder ( allow-edit? -- )
   #! Start the Smalltalk-like browser.
-  "browser" f <browser> browse ;
+  "query" get dup [
+    dup >r "vocab" swap assoc r> "word" swap assoc
+  ] [
+    drop "browser" f 
+  ] ifte <browser> browse ;
 
 "browser" [ f browser-responder ] install-cont-responder
-!"browser-edit" [ t browser-responder ] install-cont-responder
+! "browser-edit" [ t browser-responder ] install-cont-responder
index 410123a47dceb8d0a43bc50c4070b9294c32d8a9..a5995e72cc6575159380293594cb1b88d126dc00 100644 (file)
@@ -39,7 +39,7 @@ USE: logging
 USE: url-encoding
 USE: unparser
 USE: hashtables
-
+USE: parser
 USE: prettyprint
 USE: inspector
 
@@ -58,7 +58,7 @@ USE: inspector
 
 : get-random-id ( -- id ) 
   #! Generate a random id to use for continuation URL's
-  [ 16 [ random-digit unparse , ] times ] make-string ;
+  [ 32 [ random-digit unparse , ] times ] make-string str>number 36 >base ;
 
 : continuation-table ( -- <namespace> ) 
   #! Return the global table of continuations
@@ -127,6 +127,11 @@ USE: inspector
   #! Get the continuation item associated with the id.
   continuation-table [ get ] bind ;
 
+: id>url ( id -- string )
+  #! Convert the continuation id to an URL suitable for
+  #! embedding in an HREF or other HTML.
+  url-encode "?id=" swap cat2 ;
+
 DEFER: show 
 
 : expired-page-handler ( alist -- )
@@ -195,6 +200,15 @@ DEFER: show
   #! stream. Return the string on exit.
   1024 <string-output> dup >r swap with-stream r> stream>str ;
 
+: forward-to-url ( url -- )
+  #! When executed inside a 'show' call, this will force a
+  #! HTTP 302 to occur to instruct the browser to forward to
+  #! the request URL.
+  [ 
+    "HTTP/1.1 302 Document Moved\nLocation: " , ,
+    "\nContent-Length: 0\nContent-Type: text/plan\n\n" , 
+  ] make-string call-exit-continuation ;
+
 : redirect-to-here ( -- )
   #! Force a redirect to the client browser so that the browser
   #! goes to the current point in the code. This forces an URL
@@ -208,7 +222,7 @@ DEFER: show
   ] [
     [ 
       t swap register-continuation 
-      [ "HTTP/1.1 302 Document Moved\nLocation: " , , "\n" , 
+      [ "HTTP/1.1 302 Document Moved\nLocation: " , id>url , "\n" , 
         "Content-Length: 0\nContent-Type: text/plain\n\n" , ] make-string
       call-exit-continuation 
     ] callcc1 drop 
@@ -226,7 +240,7 @@ DEFER: show
   store-callback-cc
   redirect-enabled? [ redirect-to-here ] when
   [ 
-    t swap register-continuation swap 
+    t swap register-continuation id>url swap 
     [ serving-html ] car swons with-string-stream
     call-exit-continuation 
   ] callcc1 
@@ -235,6 +249,8 @@ DEFER: show
 
 : cont-get-responder ( id-or-f -- ) 
   #! httpd responder that retrieves a continuation and calls it.
+  drop
+  "id" "query" get assoc
   dup f-or-"" [
     #! No continuation id given
     drop "root-continuation" get dup [
@@ -255,7 +271,9 @@ DEFER: show
   #! id and calls it with the POST data as a hashtable on the top
   #! of the stack.
   [ 
-    "response" get alist>hash swap resume-continuation 
+    drop
+    "response" get alist>hash 
+    "id" "query" get assoc resume-continuation 
   ] with-exit-continuation
   print drop ;
 
@@ -271,7 +289,7 @@ DEFER: show
   #! back to the most recent 'show' call (via the callback-cc).
   #! The text of the link will be the 'text' argument on the 
   #! stack.
-  <a href= callback-quot t swap register-continuation a> write </a> ;
+  <a href= callback-quot t swap register-continuation id>url a> write </a> ;
 
 : with-new-session ( quot -- )
   #! Each cont-responder is bound inside their own
index 38030774c4d89b2bc8afaeaf904264219e3a0e17..899b8b37127412fd0c3cb910f9959a2c7c8ba247 100644 (file)
@@ -39,7 +39,7 @@
 ! eg.
 ! <cont-test-state> [ test-cont-responder ] test-cont-function
 !   => HTTP/1.1 302 Document Moved
-!      Location: 8506502852110820
+!      Location: ?id=8506502852110820
 !      Content-Length: 0
 !      Content-Type: text/plain
 !
 !      Content-Type: text/html
 !
 !      <html><head><title>Page one</title></head><body>
-!      <h1>Page one</h1><a href='5431597582800278'>Next</a>
+!      <h1>Page one</h1><a href='?id=5431597582800278'>Next</a>
 !      </body></html>
 !
 ! "5431597582800278" f test-cont-click
 !   => HTTP/1.1 302 Document Moved
-!      Location: 7944183606904129
+!      Location: ?id=7944183606904129
 !      Content-Length: 0
 !      Content-Type: text/plain
 !
 !
 !      <html><head><title>Enter your name</title></head>
 !      <body><h1>Enter your name</h1>
-!      <form method='post'action='8503790719833723'>
-!      Name: <input type='text'name='name'size='20'>
-!      <input type='submit'value='Ok'>
+!      <form method='post' action='?id=8503790719833723'>
+!      Name: <input type='text' name='name'size='20'>
+!      <input type='submit' value='Ok'>
 !      </form></body></html>
 !
-! "8503790719833723" [ [ "name" | "Chris" ] ] alist>hash test-cont-click
+! "8503790719833723" [ [[ "name" "Chris" ]] ] alist>hash test-cont-click
 !   => HTTP/1.1 302 Document Moved
-!      Location: 8879727708050260
+!      Location: ?id=8879727708050260
 !      Content-Length: 0
 !      Content-Type: text/plain
 !
@@ -80,7 +80,7 @@
 !
 !      <html><head><title>Hello Chris</title></head>
 !      <body><h1>Hello Chris</h1>
-!      <a href='0937854264503953'>Next</a>
+!      <a href='?id=0937854264503953'>Next</a>
 !      </body></html>
 ! 
 ! etc.
index 40a36c9bd6277b4a10e62feef6cb24ba1fd50ea6..d043398347ea357f454d875852a2f69eef9c13c1 100644 (file)
@@ -47,7 +47,7 @@ USE: lists
     [
       "js/liveUpdater.js" get-live-updater-js write
     ] show        
-  ] register-continuation ;
+  ] register-continuation id>url ;
 
 : include-live-updater-js ( -- )
   #! Write out the HTML script to include the live updater
@@ -96,7 +96,7 @@ USE: lists
     "document.getElementById('" write
     write
     "').onclick=liveUpdaterUri('" write
-    register-live-anchor-quot write
+    register-live-anchor-quot id>url write
     "');" write
   </script> ;
   
@@ -153,7 +153,7 @@ USE: lists
     "liveSearch('" write
     write
     "', '" write
-    register-live-search-quot write
+    register-live-search-quot id>url write
     "');" write
   </script> ;
 
index 1bdf64f44a699b2abc98503af8378fe402809662..591878f9f31384a206ba1d3dbc77a8d500dc7470 100644 (file)
@@ -107,7 +107,7 @@ USE: kernel
 
 : todo-stylesheet-url ( -- url )
   #! Generate an URL for the stylesheet.
-  t [ [ drop todo-stylesheet write ] show ] register-continuation ;
+  t [ [ drop todo-stylesheet write ] show ] register-continuation id>url ;
 
 : include-todo-stylesheet ( -- )  
   #! Generate HTML to include the todo stylesheet
index 7373c464b01296b114a0072f351c1f5a820c0f1d..fd1e9ef53dcf682199cdb9a88aac28edd264f1ba 100644 (file)
@@ -331,10 +331,10 @@ 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 a number at the end of
-them. 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.
+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
 ===================
@@ -603,7 +603,7 @@ calls the code we want to test and call the 'test-cont-function' word:
   <cont-test-state> [ subroutine-example1 ] test-cont-function
    => 
   HTTP/1.1 302 Document Moved
-  Location: 8209741119458310
+  Location: ?id=8209741119458310
   Content-Length: 0
   Content-Type: text/plain
 
@@ -628,9 +628,9 @@ state on the stack:
   Content-Type: text/html
   <html><head><title>Subroutine Example 1</title></head>
         <body><p>Please select:
-                 <ol><li><a href='7687398605200513'>Flow1</a></li>
-                     <li><a href='7856272029924613'>Flow2</a></li>
-                     <li><a href='4909116160485714'>Flow3</a></li>
+                 <ol><li><a href='?id=7687398605200513'>Flow1</a></li>
+                     <li><a href='?id=7856272029924613'>Flow2</a></li>
+                     <li><a href='?id=4909116160485714'>Flow3</a></li>
                  </ol>
               </p>
         </body>
@@ -645,7 +645,7 @@ written previously:
   <cont-test-state> [ post-example1 ] test-cont-function
     =>
   HTTP/1.1 302 Document Moved
-  Location: 5829759941409535
+  Location: ?id=5829759941409535
   Content-Length: 0
   Content-Type: text/plain
 
@@ -658,7 +658,7 @@ Again we skip past the forward:
 
   <html><head><title>Please enter your name</title></head>
         <body>
-          <form action='5456539333180428' method='post'>
+          <form action='?id=5456539333180428' method='post'>
             <p>Please enter your name:
                <input type='text'size='20'name='username'>
                <input type='submit'value='Ok'>
index 3dee2a375359de815d24f17da45f8bc6da466288..bde8be34e32d4e94ffec98361bef0a8232d7e4b0 100644 (file)
 ! Not all functions have been wrapped yet. Only those directly involving
 ! executing SQL calls and obtaining results.
 !
-! TODO: Do I have to free stuctures like <sqlite3> and <char*>, etc
-!       or do they get freed on garbage collection?
-!       How do I do pointers to pointers? Use the 'indirect' trick?
-!
 IN: sqlite
 USE: kernel
 USE: alien
@@ -98,77 +94,58 @@ END-STRUCT
 : SQLITE_TRANSIENT   -1 ;
 
 : sqlite3_open ( filename sqlite3-indirect -- result )
-  "int" "sqlite" "sqlite3_open" [ "char*" "sqlite3-indirect*" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_open" [ "char*" "sqlite3-indirect*" ] alien-invoke ; compiled
 
 : sqlite3_close ( db -- )
-  "int" "sqlite" "sqlite3_close" [ "sqlite3*" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_close" [ "sqlite3*" ] alien-invoke ; compiled
 
 : sqlite3_prepare ( db sql sql-len sqlite3-stmt-indirect tail -- result )
-  "int" "sqlite" "sqlite3_prepare" [ "sqlite3*" "char*" "int" "sqlite3-stmt-indirect*" "char*-indirect*" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_prepare" [ "sqlite3*" "char*" "int" "sqlite3-stmt-indirect*" "char*-indirect*" ] alien-invoke ; compiled
 
 : sqlite3_finalize ( stmt -- result ) 
-  "int" "sqlite" "sqlite3_finalize" [ "sqlite3-stmt*" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_finalize" [ "sqlite3-stmt*" ] alien-invoke ; compiled
 
 : sqlite3_reset ( stmt -- result )
-  "int" "sqlite" "sqlite3_reset" [ "sqlite3-stmt*" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_reset" [ "sqlite3-stmt*" ] alien-invoke ; compiled
 
 : sqlite3_step ( stmt -- result )
-  "int" "sqlite" "sqlite3_step" [ "sqlite3-stmt*" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_step" [ "sqlite3-stmt*" ] alien-invoke ; compiled
 
 : sqlite3_bind_blob ( stmt index pointer len destructor -- result )
-  "int" "sqlite" "sqlite3_bind_blob" [ "sqlite3-stmt*" "int" "void*" "int" "int" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_bind_blob" [ "sqlite3-stmt*" "int" "void*" "int" "int" ] alien-invoke ; compiled
 
 : sqlite3_bind_int ( stmt index int -- result )
-  "int" "sqlite" "sqlite3_bind_int" [ "sqlite3-stmt*" "int" "int" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_bind_int" [ "sqlite3-stmt*" "int" "int" ] alien-invoke ; compiled
 
 : sqlite3_bind_null ( stmt index  -- result )
-  "int" "sqlite" "sqlite3_bind_null" [ "sqlite3-stmt*" "int" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_bind_null" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 : sqlite3_bind_text ( stmt index text len destructor -- result )
-  "int" "sqlite" "sqlite3_bind_text" [ "sqlite3-stmt*" "int" "char*" "int" "int" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_bind_text" [ "sqlite3-stmt*" "int" "char*" "int" "int" ] alien-invoke ; compiled
 
 : sqlite3_column_count ( stmt -- count )
-  "int" "sqlite" "sqlite3_column_count" [ "sqlite3-stmt*" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_column_count" [ "sqlite3-stmt*" ] alien-invoke ; compiled
 
 : sqlite3_column_blob ( stmt col -- void* )
-  "void*" "sqlite" "sqlite3_column_blob" [ "sqlite3-stmt*" "int" ] alien-invoke ;
+  "void*" "sqlite" "sqlite3_column_blob" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 : sqlite3_column_bytes ( stmt col -- int )
-  "int" "sqlite" "sqlite3_column_bytes" [ "sqlite3-stmt*" "int" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_column_bytes" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 : sqlite3_column_decltype ( stmt col -- string )
-  "char*" "sqlite" "sqlite3_column_decltype" [ "sqlite3-stmt*" "int" ] alien-invoke ;
+  "char*" "sqlite" "sqlite3_column_decltype" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 : sqlite3_column_int ( stmt col -- int )
-  "int" "sqlite" "sqlite3_column_int" [ "sqlite3-stmt*" "int" ] alien-invoke ;
+  "int" "sqlite" "sqlite3_column_int" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 : sqlite3_column_name ( stmt col -- string )
-  "char*" "sqlite" "sqlite3_column_name" [ "sqlite3-stmt*" "int" ] alien-invoke ;
+  "char*" "sqlite" "sqlite3_column_name" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 : sqlite3_column_text ( stmt col -- string )
-  "char*" "sqlite" "sqlite3_column_text" [ "sqlite3-stmt*" "int" ] alien-invoke ;
+  "char*" "sqlite" "sqlite3_column_text" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 : sqlite3_column_type ( stmt col -- int )
-  "int" "sqlite" "sqlite3_column_type" [ "sqlite3-stmt*" "int" ] alien-invoke ;
-
-\ sqlite3_open compile
-\ sqlite3_close compile
-\ sqlite3_prepare compile
-\ sqlite3_finalize compile
-\ sqlite3_reset compile
-\ sqlite3_bind_blob compile
-\ sqlite3_bind_int compile
-\ sqlite3_bind_null compile
-\ sqlite3_bind_text compile
-\ sqlite3_step compile
-\ sqlite3_column_count compile
-\ sqlite3_column_blob compile
-\ sqlite3_column_bytes compile
-\ sqlite3_column_decltype compile
-\ sqlite3_column_int compile
-\ sqlite3_column_name compile
-\ sqlite3_column_text compile
-\ sqlite3_column_type compile
+  "int" "sqlite" "sqlite3_column_type" [ "sqlite3-stmt*" "int" ] alien-invoke ; compiled
 
 ! High level sqlite routines
 : sqlite-check-result ( result -- )
@@ -220,26 +197,32 @@ END-STRUCT
   #! from zero, as a string.
   sqlite3_column_text ;
 
-: (sqlite-each) 
-  "statement" get sqlite3_step dup SQLITE_ROW = [
-    drop
-    "statement" get "quot" get call (sqlite-each)
-  ] [ 
+: step-complete? ( step-result -- bool )
+  #! Return true if the result of a sqlite3_step is
+  #! such that the iteration has completed (ie. it is
+  #! SQLITE_DONE). Throw an error if an error occurs. 
+  dup SQLITE_ROW =  [
+    drop f
+  ] [
     dup SQLITE_DONE = [
-      drop
+      drop t 
     ] [
       sqlite-check-result
-    ] ifte 
+    ] ifte
   ] ifte ;
 
 : sqlite-each ( statement quot -- )    
-  #! Excecute the SQL statement, and call the quotation for
+  #! Execute the SQL statement, and call the quotation for
   #! each row returned from executing the statement with the
   #! statement on the top of the stack.
-  #! TODO: Implement without named parameters
-  <namespace> [
-    "quot" set
-    "statement" set
-    (sqlite-each)
-  ] bind ;
+  over sqlite3_step step-complete? [ 
+    2drop
+  ] [
+    2dup 2slip sqlite-each
+  ] ifte ;
 
+! For comparison, here is the linrec implementation of sqlite-each
+! [ drop sqlite3_step step-complete? ]
+! [ 2drop ]
+! [ 2dup 2slip ]
+! [ ] linrec ; 
\ No newline at end of file
index 8257c655b388c9d88e7a68362bfa30378c16cef2..59be1583cfebd0246225b66c69fcafd86a04c127 100644 (file)
@@ -47,4 +47,9 @@ USE: prettyprint
   sqlite-finalize
   sqlite-close ;
 
+: run-test2 ( -- )
+  "test.db" sqlite-open
+  dup "select * from test" sqlite-prepare
+  dup [ show-people ] ;
+
 run-test
\ No newline at end of file