Commits

Greg Slepak committed acdfd1f

API docs pretty much done

  • Participants
  • Parent commits d55f8fc

Comments (0)

Files changed (15)

example-site/dragonfly-framework/docs/dragonfly.lsp.html

 			link="#376590" vlink="#551A8B" alink="#ffAA28">
 <blockquote>
 <center><h1>dragonfly.lsp</h1></center>
-<p><a href="index.html">Module index</a></p><br/><br/><br/><h2>Module:&nbsp;dragonfly.lsp</h2><p>A newLISP web framework for rapid web development</p>
+<p><a href="index.html">Module index</a></p><br/><br/><br/><h2>Module:&nbsp;dragonfly.lsp</h2><p>The heart of Dragonfly - A newLISP web framework for rapid web development.</p>
 <b>Version: </b>0.50<br/>
 <b>Author: </b>Greg Slepak, Marc Hildmann (Team Dragonfly 2009)<br/>
 <b>Location: </b><a href="http://code.google.com/p/dragonfly-newlisp/">http://code.google.com/p/dragonfly-newlisp/</a><br/>
-<br/><br/>
- This file is the main entry-point of the Dragonfly framework and
+ <br>This file is the main entry-point of the Dragonfly framework and
  contains several important functions, as well as the default route
  definitions. The functions here are in the <tt>Dragonfly</tt> context (alias <tt>DF</tt>),
  which is the context your static files will be evaluated in by default.
  Therefore all of the functions here can be called in your templates without
  needing to be context-qualified.
-<br/><br/>
- Dragonfly's design is very simple, you can actually read through its
+ <br><br>Dragonfly's design is very simple, you can actually read through its
  source in very little time to get a great understanding of exactly how
  it works, and to get an idea of what sorts of tricks you can do to
  customize it to your liking (remember, newLISP is <em>extremely</em> dynamic!).
-<br/><br/>
  <h3>The <tt>listener</tt> function</h3>
  The <tt>listener</tt> function is called in <tt>index.cgi</tt>. It is the function that
  kicks everything off by looping through the available routes, finding a
  match, running it, sending the output to the browser, and then exiting.
-<br/><br/>
- However, before all of that, the very *first* thing it does is load the
+ <br><br>Before all of that, the very *first* thing it does is load the
  plugins in the <tt>dragonfly-framework/plugins-active</tt> folder, giving them
  an opportunity to do any special customization that they might require.
-<br/><br/>
- The <tt>listener</tt> function should not be modified at any point in any way.
-<br/><br/>
  <h3>Environment Variables</h3>
  At the very top of the <tt>config.lsp</tt> file there is the following line:
  <pre> (dolist (x (env)) (constant (global (sym (upper-case (first x)))) (last x)))</pre>
  global symbol out of it. This makes it extremely simple to access environment
  variables, simply type their name! If you prefer PHP-style, you can
  access them through the <tt>$SERVER</tt> function (simply a synonym for <tt>env</tt>).
-<br/><br/>
- To access any web parameters, files, and cookies use the functions <tt>$GET</tt>, <tt>$POST</tt>,
+ <br><br>To access any web parameters, files, and cookies use the functions <tt>$GET</tt>, <tt>$POST</tt>,
  <tt>$FILES</tt>, and <tt>$COOKIES</tt>, respectively. See <tt>Request.lsp</tt> for more information.
-<br/><br/>
  <h3>Routes</h3>
- Routes are simply FOOP contexts (with the <tt>Routes.</tt> prefix) that contain two
- functions: <tt>matches?</tt> and <tt>run</tt>.
-<br/><br/>
- The listener loops through the available routes and calls <tt>matches?</tt> on them
+ <p>Routes are FOOP objects inheriting from the Route class. They should have the <tt>Route.</tt> prefix.
+ Currently they only need to support two functions: <tt>matches?</tt> and <tt>run</tt>.</p>
+ <p>The listener loops through the available routes and calls <tt>matches?</tt> on them
  with no arguments. The route must decide, based on any data available to it,
- whether or not it to return a non-nil value from <tt>matches?</tt>.
-<br/><br/>
+ whether or not it to return a non-nil value from <tt>matches?</tt>.</p>
  Here, for example, is the <tt>matches?</tt> function for <tt>Route.Resource</tt>:
  <pre> (define (matches?)
      (when (regex {^([a-z]\w+)(/([a-z]\w+))?(/(\d+))?(\.([a-z]+))?} QUERY_STRING 1)
  There are two default routes: <tt>Route.Static</tt> and <tt>Route.Resource</tt>. See the
  documentation on the example-site and in <tt>config.lsp</tt> for more information on
  what they do.
-<br/><br/>
+ <h3>Resources</h3>
+ <tt>Route.Resource</tt> handles URLs that refer to RESTful resources, represented as FOOP objects
+ deriving from the <tt>Resource</tt> class. The resources reside in the <tt>RESOURCES_PATH</tt> as .lsp files.
+ The URL scheme works in a similar manner to twitter's RESTful API:
+ <pre>http://mysite.com/<em>resource</em>[/<em>action</em>][/<em>id</em>][.<em>response_format</em>][?get paramters...]</pre>
+ <tt>resource</tt> maps to a context name in a special way. First <tt>Resource.</tt> is prepended
+ to the name, then the underscores are removed and the name is written in title case.
+ The <tt>resource</tt> may only have the letters A-Z (lowercase or uppercase), 0-9, the underscore,
+ and it must begin with a letter.
+ <br/><pre> my_resource => Resource.MyResource</pre>
+ The name also maps to a real file located in <tt>RESOURCES_PATH</tt> by appending ".lsp" to the name:
+ <br/><pre> my_resource => load file: RESOURCES_PATH/my_resource.lsp</pre>
+ If <tt>resource</tt> implements <tt>action</tt>, then that function is called.
+ Like <tt>resource</tt>, <tt>action</tt> may only contain letters, numbers, and the underscore.
+ If no <tt>action</tt> is specified, then the resource's default function is called instead.
+ <p>The optional paramters <tt>id</tt> and <tt>response_format</tt> are passed in to the function
+ as parameters (in that order).</p>
+ <p><tt>id</tt> may only contain numbers, and <tt>response_format</tt> may only contain letters.</p>
  <h3>Plugins</h3>
  There are two types of plugins, those in the <tt>plugins-active</tt> folder, and those
  in the <tt>plugins-inactive</tt> folder. The ones in the former are loaded when <tt>listener</tt>
  is called, prior to running the routes. Every .lsp file in the <tt>plugins-active</tt> folder
  is loaded at that point, so you'll only want your most frequently used files in there.
-<br/><br/>
- A good example of an active plugin is a custom route. Defining a custom route consists
- of two basic steps: creating your route "FOOP class", and adding an instance of
+ <p>A good example of an active plugin is a custom route. Defining a custom route consists
+ of two basic steps: creating your <tt>Route</tt> "subclass", and adding an instance of
  it to <tt>Dragonfly:dragonfly-routes</tt>. Take a look at how it's done in the source of
- <tt>dragonfly.lsp</tt> for more info.
-<br/><br/>
- Inactive plugins are simply those that should be loaded on a "need to use" basis.
+ <tt>dragonfly.lsp</tt> for more info.</p>
+ <p>Inactive plugins are simply those that should be loaded on a "need to use" basis.
  Most plugins will probably fall into this category. Use <tt>Dragonfly:activate-plugin</tt>
  to load them. All plugins are loaded exactly once, no matter how many times
- <tt>activate-plugin</tt> is called on them.
+ <tt>activate-plugin</tt> is called on them.</p>
 
 
 

example-site/dragonfly-framework/docs/index.html

 <blockquote>
 <center><h1>Index</h1></center>
 <a href="dragonfly.lsp.html"><br/><br/><h2>Module:&nbsp;dragonfly.lsp</h2></a>
-<p>A newLISP web framework for rapid web development</p>
-<a href="dragonfly.lsp.html#_STDOUT">STDOUT</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_activate-plugin">activate-plugin</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_web-root">web-root</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_view-path">view-path</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_partial-path">partial-path</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_resource-path">resource-path</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_include">include</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-file">display-file</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-partial">display-partial</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-view">display-view</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-error">display-error</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_eval-template">eval-template</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_die">die</a>&nbsp; &nbsp; <a href="request.lsp.html"><br/><br/><h2>Module:&nbsp;request.lsp</h2></a>
+<p>The heart of Dragonfly - A newLISP web framework for rapid web development.</p>
+<a href="dragonfly.lsp.html#_STDOUT">STDOUT</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_activate-plugin">activate-plugin</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_web-root">web-root</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_view-path">view-path</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_partial-path">partial-path</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_resource-path">resource-path</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_include">include</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-file">display-file</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-partial">display-partial</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-view">display-view</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_display-error">display-error</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_eval-template">eval-template</a>&nbsp; &nbsp; <a href="dragonfly.lsp.html#Dragonfly_die">die</a>&nbsp; &nbsp; <a href="log.lsp.html"><br/><br/><h2>Module:&nbsp;log.lsp</h2></a>
+<p>Provides convenient logging facility for all of Dragonfly.</p>
+<a href="log.lsp.html#Dragonfly_log-func">log-func</a>&nbsp; &nbsp; <a href="log.lsp.html#Dragonfly_log-debug">log-debug</a>&nbsp; &nbsp; <a href="log.lsp.html#Dragonfly_log-info">log-info</a>&nbsp; &nbsp; <a href="log.lsp.html#Dragonfly_log-warn">log-warn</a>&nbsp; &nbsp; <a href="log.lsp.html#Dragonfly_log-err">log-err</a>&nbsp; &nbsp; <a href="request.lsp.html"><br/><br/><h2>Module:&nbsp;request.lsp</h2></a>
 <p></p>
 <a href="request.lsp.html#_$GET">$GET</a>&nbsp; &nbsp; <a href="request.lsp.html#_$POST">$POST</a>&nbsp; &nbsp; <a href="request.lsp.html#_$FILES">$FILES</a>&nbsp; &nbsp; <a href="request.lsp.html#_$COOKIES">$COOKIES</a>&nbsp; &nbsp; <a href="request.lsp.html#_$BINARY">$BINARY</a>&nbsp; &nbsp; <a href="response.lsp.html"><br/><br/><h2>Module:&nbsp;response.lsp</h2></a>
 <p></p>
-<a href="response.lsp.html#Response_status">status</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_header">header</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_cookie">cookie</a>&nbsp; &nbsp; <a href="response.lsp.html#Respons_send-headers">send-headers</a>&nbsp; &nbsp; <a href="utils.lsp.html"><br/><br/><h2>Module:&nbsp;utils.lsp</h2></a>
+<a href="response.lsp.html#Response_status">status</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_header">header</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_cookie">cookie</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_send-headers">send-headers</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_redirect">redirect</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_send-headers-with-status">send-headers-with-status</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_content-type">content-type</a>&nbsp; &nbsp; <a href="response.lsp.html#Response_extension->type">extension->type</a>&nbsp; &nbsp; <a href="utils.lsp.html"><br/><br/><h2>Module:&nbsp;utils.lsp</h2></a>
 <p></p>
-<a href="utils.lsp.html#_regex-captcha">regex-captcha</a>&nbsp; &nbsp; <a href="utils.lsp.html#_load-files-in-dir">load-files-in-dir</a>&nbsp; &nbsp; 
+<a href="utils.lsp.html#_regex-captcha">regex-captcha</a>&nbsp; &nbsp; <a href="utils.lsp.html#_load-files-in-dir">load-files-in-dir</a>&nbsp; &nbsp; <a href="utils.lsp.html#_into-ctx-assoc">into-ctx-assoc</a>&nbsp; &nbsp; 
 <br/><br/><center>- &part; -</center><br/>
 <center><font face='Arial' size='-2' color='#444444'>
 generated with <a href="http://newlisp.org">newLISP</a>&nbsp;

example-site/dragonfly-framework/docs/log.lsp.html

+<!DOCTYPE HTML PUBLIC "HTML 4.01 Transitional">
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>log.lsp</title>
+
+<link rel="stylesheet" type="text/css" href="newlispdoc.css" />
+</head>
+
+<body style="margin: 20px;" text="#111111" bgcolor="#FFFFFF" 
+			link="#376590" vlink="#551A8B" alink="#ffAA28">
+<blockquote>
+<center><h1>log.lsp</h1></center>
+<p><a href="index.html">Module index</a></p><br/><br/><br/><h2>Module:&nbsp;log.lsp</h2><p>Provides convenient logging facility for all of Dragonfly.</p>
+<b>Author: </b>Greg Slepak<br/>
+ <p>To avoid checking the value of <tt>Dragonfly:LOG_LEVEL</tt> each time something is logged
+ the logging functions that correspond to a lower logging level are disabled
+ when this file is loaded.</p>
+ <p>It is possible to change the <tt>LOG_LEVEL</tt> at runtime, but the way it is done
+ is slightly tricky because <tt>MAIN:load</tt> is overwritten by Dragonfly
+ to provide once-only loading. If you want to dynamically change the
+ log-level (say in a plugin), then you will need to use the remapped <tt>sys-load</tt>
+ function to force a reload of this file:</p>
+ <pre> (context 'DF)
+ (constant 'LOG_LEVEL 'LOG_DEBUG) ; enable debug logging at runtime
+ (sys-load (string DRAGONFLY_ROOT "/lib/log.lsp"))
+ (context MAIN)</pre>
+ There are four log levels defined:
+ <pre> (map set '(LOG_DEBUG LOG_INFO LOG_WARN LOG_ERROR)
+          '(        0        1        2         3))</pre>
+
+
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Dragonfly_log-func"></a><h3><font color=#CC0000>Dragonfly:log-func</font></h3>
+<b>syntax: (<font color=#CC0000>Dragonfly:log-func</font> <em>str-level</em> <em>str-msg</em>)</b><br/>
+<b>parameter: </b><em>str-level</em> - a string representing the log level (ex: "[DEBUG]: ")<br/>
+<b>parameter: </b><em>str-msg</em> - a string containing the message<br/>
+ <br/>This function appends to the file specified by <tt>Dragonfly:LOG_FILE_PATH</tt>
+ and prepends date information to the log.
+ <pre> (log-func "[CRAZY!]: " (string user " just did something crazy!"))
+ => Oct 26 01:44:24 [CRAZY!]: johnny-b just did something crazy!</pre>
+ All other log functions call this one. You can override this function
+ at runtime to provide your own logging behavior.
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Dragonfly_log-debug"></a><h3><font color=#CC0000>Dragonfly:log-debug</font></h3>
+<b>syntax: (<font color=#CC0000>Dragonfly:log-debug</font>)</b><br/>
+ <br>String-concats its arguments and calls <tt>log-func</tt> with <em>level</em> set to "[DEBUG]: "
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Dragonfly_log-info"></a><h3><font color=#CC0000>Dragonfly:log-info</font></h3>
+<b>syntax: (<font color=#CC0000>Dragonfly:log-info</font>)</b><br/>
+ <br>String-concats its arguments and calls <tt>log-func</tt> with <em>level</em> set to "[INFO]: "
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Dragonfly_log-warn"></a><h3><font color=#CC0000>Dragonfly:log-warn</font></h3>
+<b>syntax: (<font color=#CC0000>Dragonfly:log-warn</font>)</b><br/>
+ <br>String-concats its arguments and calls <tt>log-func</tt> with <em>level</em> set to "[WARNING]: "
+
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Dragonfly_log-err"></a><h3><font color=#CC0000>Dragonfly:log-err</font></h3>
+<b>syntax: (<font color=#CC0000>Dragonfly:log-err</font>)</b><br/>
+ <br>String-concats its arguments and calls <tt>log-func</tt> with <em>level</em> set to "[ERROR]: "
+
+
+
+<br/><br/><center>- &part; -</center><br/>
+<center><font face='Arial' size='-2' color='#444444'>
+generated with <a href="http://newlisp.org">newLISP</a>&nbsp;
+and <a href="http://newlisp.org/newLISPdoc.html">newLISPdoc</a>
+</font></center>
+</blockquote>
+</body>
+</html>

example-site/dragonfly-framework/docs/request.lsp.html

  If a variable was specified, but no value assigned (i.e. <tt>/?foo</tt>), then
  the value will be an empty string (you can use <tt>empty?</tt> to check for this).
  If the variable does not exist, <tt>nil</tt> will be returned.
-<br/><br/>
- The values are url decoded:
+ <br><br>The values are url decoded:
  <pre> "What+time+is+it%3f"  => "What time is it?"</pre>
  <h3>$FILES</h3>
  If a <tt>multipart/form-data</tt> content type was submitted, then
  STDIN is read for the values. Any files are placed in <tt>$FILES</tt>, while
  other key/value pairs are placed in <tt>$POST</tt>.
-<br/><br/>
- The values in <tt>$FILES</tt> contain an associative array with more information
+ <br><br>The values in <tt>$FILES</tt> contain an associative array with more information
  about the files.
  <h3>$BINARY</h3>
  If the environment variable <tt>HTTP_CONTENT_TRANSFER_ENCODING</tt> is set to
  stored in <tt>$BINARY</tt>. Note that unlike the other symbols in this file,
  <tt>$BINARY</tt> is a string, not a function.
  <h3>$COOKIES</h3>
- The environment variable <tt>HTTP_COOKIE</tt> is parsed and the cookies are
+ The environment variable <tt>HTTP_COOKIE</tt> is parsed and the cookies are placed in
  in <tt>$COOKIES</tt> as key/value pairs just like <tt>$GET</tt> and <tt>$POST</tt>.
-
 <br/><br/><center>- &sect; -</center><br/>
 <a name="_$GET"></a><h3><font color=#CC0000>$GET</font></h3>
 <b>syntax: (<font color=#CC0000>$GET</font> <em>str-key</em>)</b><br/>
 <br/><br/><center>- &sect; -</center><br/>
 <a name="_$FILES"></a><h3><font color=#CC0000>$FILES</font></h3>
 <b>syntax: (<font color=#CC0000>$FILES</font> <em>str-key</em>)</b><br/>
+ <p>Returns an association list with keys <tt>'name</tt>, <tt>'data</tt>, and <tt>'length</tt> for the result
+ of a <tt>multipart/form-data</tt> posted form.</p>
 <br/><br/><center>- &sect; -</center><br/>
 <a name="_$COOKIES"></a><h3><font color=#CC0000>$COOKIES</font></h3>
 <b>syntax: (<font color=#CC0000>$COOKIES</font> <em>str-key</em>)</b><br/>
+<p><b>return: </b>the value of the cookie with the key <em>str-key</em>, or nil if no such cookie exists.</p>
 <br/><br/><center>- &sect; -</center><br/>
 <a name="_$BINARY"></a><h3><font color=#CC0000>$BINARY</font></h3>
 <b>syntax: $BINARY</b><br/>
+ <p>This is a global buffer that contains what was sent to STDIN (up to <tt>MAX_POST_LENGTH</tt>)
+ when the value of environment variable <tt>HTTP_CONTENT_TRANSFER_ENCODING</tt> is set to "binary".</p>
 
 
 

example-site/dragonfly-framework/docs/response.lsp.html

 <a name="Response_status"></a><h3><font color=#CC0000>Response:status</font></h3>
 <b>syntax: (<font color=#CC0000>Response:status</font>)</b><br/>
 <b>syntax: (<font color=#CC0000>Response:status</font> <em>int-code</em> [<em>str-description</em>])</b><br/>
- <br>In the first syntax...
+ <p>In the first syntax, returns a list containing the current status code and corresponding description.</p>
+ <p>In the second syntax, sets the response status to <em>int-code</em>, using the description from
+ a built-in list. If the description for <em>int-code</em> is not found in the built-in
+ list then an error will be thrown if <em>str-description</em> is not provided.</p>
 
 <br/><br/><center>- &sect; -</center><br/>
 <a name="Response_header"></a><h3><font color=#CC0000>Response:header</font></h3>
 <b>syntax: (<font color=#CC0000>Response:header</font> <em>str-key</em>)</b><br/>
-<b>parameter: </b><em>str-key</em> - the header's name<br/>
+<b>parameter: </b><em>str-key</em> - the header's name<br><br/>
 <b>syntax: (<font color=#CC0000>Response:header</font> <em>str-key</em> <em>str-value</em>)</b><br/>
 <b>parameter: </b><em>str-key</em> - the header's name<br/>
 <b>parameter: </b><em>str-value</em> - the header's value<br/>
  <br>In the first syntax, returns the header matching <em>str-key</em> or,
- if <em>str-key</em> is nil, all of the headers in a list.
+ if <em>str-key</em> is nil, all of the headers in an association list.
  <br>In the second syntax, sets or updates the header matching <em>str-key</em> or,
  if <em>str-value</em> is nil, deletes the header for <em>str-key</em>.
 
 <br/><br/><center>- &sect; -</center><br/>
 <a name="Response_cookie"></a><h3><font color=#CC0000>Response:cookie</font></h3>
 <b>syntax: (<font color=#CC0000>Response:cookie</font> <em>str-key</em>)</b><br/>
-<b>parameter: </b><em>str-key</em> - the cookie's name<br/>
+<b>parameter: </b><em>str-key</em> - the cookie's name<br><br/>
 <b>syntax: (<font color=#CC0000>Response:cookie</font> <em>str-key</em> <em>str-value</em> [<em>int-expires</em> [<em>str-path</em> [<em>str-domain</em> [<em>bool-http-only</em>]]]])</b><br/>
 <b>parameter: </b><em>str-key</em> - the cookie's name<br/>
 <b>parameter: </b><em>str-value</em> - the cookie's value<br/>
 <br/><br/><center>- &sect; -</center><br/>
 <a name="Response_send-headers"></a><h3><font color=#CC0000>Response:send-headers</font></h3>
 <b>syntax: (<font color=#CC0000>Response:send-headers</font>)</b><br/>
- <br>Actually sends the headers (without buffering them to <tt>Dragonfly:STDOUT</tt>).
- Normally you should never call this yourself!
+ <p>Actually sends the headers (without buffering them to <tt>Dragonfly:STDOUT</tt>).
+ Normally you should never call this yourself!</p>
 
 
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Response_redirect"></a><h3><font color=#CC0000>Response:redirect</font></h3>
+<b>syntax: (<font color=#CC0000>Response:redirect</font> <em>str-url</em>)</b><br/>
+<b>parameter: </b><em>str-url</em> - The URL you'd like to send them to<br/>
+ <p>Does an immediate 302 Found redirect and calls <tt>exit</tt>.</p>
 
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Response_send-headers-with-status"></a><h3><font color=#CC0000>Response:send-headers-with-status</font></h3>
+<b>syntax: (<font color=#CC0000>Response:send-headers-with-status</font> <em>int-code</em> <em>str-description</em>)</b><br/>
+ <p>Convenience. Combines a call to <tt>Response:status</tt> and <tt>Response:send-headers</tt>.
+ As this calls <tt>send-headers</tt>, you typically do not want to call this yourself!</p>
 
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Response_content-type"></a><h3><font color=#CC0000>Response:content-type</font></h3>
+<b>syntax: (<font color=#CC0000>Response:content-type</font> <em>str-value</em>)</b><br/>
+ <p>Convenience for calling <tt>(Response:header "Content-Type" str-value)</tt>.</p>
+ <p>If <em>str-value</em> is nil, returns the current content-type value</p>
 
+<br/><br/><center>- &sect; -</center><br/>
+<a name="Response_extension->type"></a><h3><font color=#CC0000>Response:extension->type</font></h3>
+<b>syntax: (<font color=#CC0000>Response:extension->type</font> <em>str-file-extension</em>)</b><br/>
+ <p>Given a file extension (with or without a preceding dot), returns the
+ MIME-type for that extension. Currently only a small number of file extensions
+ are supported by default, see the source in lib/response.lsp for a complete list.</p>
 
 
 

example-site/dragonfly-framework/docs/utils.lsp.html

 <blockquote>
 <center><h1>utils.lsp</h1></center>
 <p><a href="index.html">Module index</a></p><br/><br/><br/><h2>Module:&nbsp;utils.lsp</h2><b>Author: </b>Greg Slepak <greg at taoeffect.com><br/>
+ <p>This file not only provides the functions documented below, but
+ it also plays a role in globally overriding certain functions in the MAIN context.</p>
+ <p>The overridden functions include: <tt>load</tt>, <tt>print</tt>, and <tt>println</tt>.</p>
+ <p><tt>load</tt> is overwritten to load a file only once, while <tt>print</tt> and <tt>println</tt>
+ are overwritten to send their output the the <tt>Dragonfly:STDOUT</tt> buffer, allowing
+ Dragonfly to ensure pages are displayed properly.</p>
 
 <br/><br/><center>- &sect; -</center><br/>
 <a name="_regex-captcha"></a><h3><font color=#CC0000>regex-captcha</font></h3>
 <b>syntax: (<font color=#CC0000>regex-captcha</font> <em>str-regex</em> <em>str</em> [<em>int-options</em>] [<em>int-captcha</em>])</b><br/>
+<b>parameter: </b><em>int-options</em> - options to regex, defaults to 0.<br/>
+<b>parameter: </b><em>int-captch</em> - which of the regex group captures to return, defaults to 1.<br/>
+ <p>Returns the captured text, or nil if it couldn't be captured.<br/>This is a global function.</p>
+ <b>example:</b>
+ <pre> (regex-captcha {^(foo|bar).*} "foobaz") => "foo"
+ (regex-captcha {^(foo|bar).*} "bazfoo") => nil</pre>
 <br/><br/>
 <br/><br/><center>- &sect; -</center><br/>
 <a name="_load-files-in-dir"></a><h3><font color=#CC0000>load-files-in-dir</font></h3>
 <b>syntax: (<font color=#CC0000>load-files-in-dir</font> <em>str-dir</em> <em>regex-match</em>)</b><br/>
+ <p>Loads all the files in <em>str-dir</em> matching <em>regex-match</em>. Does not
+ traverse subdirectories.<br/>This is a global function.</p>
+<br/><br/>
+<br/><br/><center>- &sect; -</center><br/>
+<a name="_into-ctx-assoc"></a><h3><font color=#CC0000>into-ctx-assoc</font></h3>
+<b>syntax: (<font color=#CC0000>into-ctx-assoc</font> <em>ctx</em> <em>list-assoc</em>)</b><br/>
+ <p>Places the key/value pairs in <em>list-assoc</em> into the context <em>ctx</em>
+ to be used as a lookup table.<br/>This is a global function.</p>
+ <b>example:</b>
+ <pre> (new Tree 'MyCtx)
+ (into-ctx-assoc MyCtx '(
+     ("key" "value")
+     ("apple" "mmmm... good")
+     ("organic?" true)
+ ))</pre>
 <br/><br/>
 
 <br/><br/><center>- &part; -</center><br/>

example-site/dragonfly-framework/dragonfly.lsp

 ;; @module dragonfly.lsp
-;; @description A newLISP web framework for rapid web development
+;; @description The heart of Dragonfly - A newLISP web framework for rapid web development.
 ;; @version 0.50
 ;; @author Greg Slepak, Marc Hildmann (Team Dragonfly 2009)
 ;; @location http://code.google.com/p/dragonfly-newlisp/
-;; 
-;; This file is the main entry-point of the Dragonfly framework and
+;; <br>This file is the main entry-point of the Dragonfly framework and
 ;; contains several important functions, as well as the default route
 ;; definitions. The functions here are in the 'Dragonfly' context (alias 'DF'),
 ;; which is the context your static files will be evaluated in by default.
 ;; Therefore all of the functions here can be called in your templates without
 ;; needing to be context-qualified.
-;; 
-;; Dragonfly's design is very simple, you can actually read through its
+;; <br><br>Dragonfly's design is very simple, you can actually read through its
 ;; source in very little time to get a great understanding of exactly how
 ;; it works, and to get an idea of what sorts of tricks you can do to
 ;; customize it to your liking (remember, newLISP is <extremely> dynamic!).
-;; 
 ;; <h3>The 'listener' function</h3>
 ;; The 'listener' function is called in 'index.cgi'. It is the function that
 ;; kicks everything off by looping through the available routes, finding a
 ;; match, running it, sending the output to the browser, and then exiting.
-;; 
-;; However, before all of that, the very *first* thing it does is load the
+;; <br><br>Before all of that, the very *first* thing it does is load the
 ;; plugins in the 'dragonfly-framework/plugins-active' folder, giving them
 ;; an opportunity to do any special customization that they might require.
-;; 
-;; The 'listener' function should not be modified at any point in any way.
-;; 
 ;; <h3>Environment Variables</h3>
 ;; At the very top of the 'config.lsp' file there is the following line:
 ;; <pre> (dolist (x (env)) (constant (global (sym (upper-case (first x)))) (last x)))</pre>
 ;; global symbol out of it. This makes it extremely simple to access environment
 ;; variables, simply type their name! If you prefer PHP-style, you can
 ;; access them through the '$SERVER' function (simply a synonym for 'env').
-;; 
-;; To access any web parameters, files, and cookies use the functions '$GET', '$POST',
+;; <br><br>To access any web parameters, files, and cookies use the functions '$GET', '$POST',
 ;; '$FILES', and '$COOKIES', respectively. See 'Request.lsp' for more information.
-;; 
 ;; <h3>Routes</h3>
-;; Routes are simply FOOP contexts (with the 'Routes.' prefix) that contain two
-;; functions: 'matches?' and 'run'.
-;; 
-;; The listener loops through the available routes and calls 'matches?' on them
+;; <p>Routes are FOOP objects inheriting from the Route class. They should have the 'Route.' prefix.
+;; Currently they only need to support two functions: 'matches?' and 'run'.</p>
+;; <p>The listener loops through the available routes and calls 'matches?' on them
 ;; with no arguments. The route must decide, based on any data available to it,
-;; whether or not it to return a non-nil value from 'matches?'.
-;; 
+;; whether or not it to return a non-nil value from 'matches?'.</p>
 ;; Here, for example, is the 'matches?' function for 'Route.Resource':
 ;; <pre> (define (matches?)
 ;;     (when (regex {^([a-z]\w+)(/([a-z]\w+))?(/(\d+))?(\.([a-z]+))?} QUERY_STRING 1)
 ;; There are two default routes: 'Route.Static' and 'Route.Resource'. See the
 ;; documentation on the example-site and in 'config.lsp' for more information on
 ;; what they do.
-;; 
+;; <h3>Resources</h3>
+;; 'Route.Resource' handles URLs that refer to RESTful resources, represented as FOOP objects
+;; deriving from the 'Resource' class. The resources reside in the 'RESOURCES_PATH' as .lsp files.
+;; The URL scheme works in a similar manner to twitter's RESTful API:
+;; <pre>http://mysite.com/<resource>[/<action>][/<id>][.<response_format>][?get paramters...]</pre>
+;; 'resource' maps to a context name in a special way. First 'Resource.' is prepended
+;; to the name, then the underscores are removed and the name is written in title case.
+;; The 'resource' may only have the letters A-Z (lowercase or uppercase), 0-9, the underscore,
+;; and it must begin with a letter.
+;; <br/><pre> my_resource => Resource.MyResource</pre>
+;; The name also maps to a real file located in 'RESOURCES_PATH' by appending ".lsp" to the name:
+;; <br/><pre> my_resource => load file: RESOURCES_PATH/my_resource.lsp</pre>
+;; If 'resource' implements 'action', then that function is called.
+;; Like 'resource', 'action' may only contain letters, numbers, and the underscore.
+;; If no 'action' is specified, then the resource's default function is called instead.
+;; <p>The optional paramters 'id' and 'response_format' are passed in to the function
+;; as parameters (in that order).</p>
+;; <p>'id' may only contain numbers, and 'response_format' may only contain letters.</p>
 ;; <h3>Plugins</h3>
 ;; There are two types of plugins, those in the 'plugins-active' folder, and those
 ;; in the 'plugins-inactive' folder. The ones in the former are loaded when 'listener'
 ;; is called, prior to running the routes. Every .lsp file in the 'plugins-active' folder
 ;; is loaded at that point, so you'll only want your most frequently used files in there.
-;; 
-;; A good example of an active plugin is a custom route. Defining a custom route consists
-;; of two basic steps: creating your route "FOOP class", and adding an instance of
+;; <p>A good example of an active plugin is a custom route. Defining a custom route consists
+;; of two basic steps: creating your 'Route' "subclass", and adding an instance of
 ;; it to 'Dragonfly:dragonfly-routes'. Take a look at how it's done in the source of
-;; 'dragonfly.lsp' for more info.
-;; 
-;; Inactive plugins are simply those that should be loaded on a "need to use" basis.
+;; 'dragonfly.lsp' for more info.</p>
+;; <p>Inactive plugins are simply those that should be loaded on a "need to use" basis.
 ;; Most plugins will probably fall into this category. Use 'Dragonfly:activate-plugin'
 ;; to load them. All plugins are loaded exactly once, no matter how many times
-;; 'activate-plugin' is called on them.
+;; 'activate-plugin' is called on them.</p>
 
 
 ;===============================================================================
 ; !Setup Default Routes
 ;===============================================================================
 
-; newLISP can't handle calling 'new' outside of MAIN context...
-(context MAIN) (new Class 'Route.Static) (context Route.Static)
+; newLISP can't handle calling 'new' outside of MAIN context, nor does it currently
+; allow switching contexts in a function call. If it does one day, route defintions
+; will be specified through a 'define-route' macro.
+(context MAIN)
+(new Route 'Route.Static) (context Route.Static)
 
 (define (matches?)
 	(set 'chunks (parse QUERY_STRING "?"))
 	)
 )
 
-; Route.Resource handles URLs that refer to RESTful resources, represented
-; as newLISP contexts. These resources reside in the RESOURCES_PATH as .lsp files.
-; The URL works in a similar manner to twitter's RESTful API:
-; http://mysite.com/<resource_name>[/resource_action][/resource_id][.restponse_format][?get_paramters]
-; <resource_name> maps to a context name in a special way: first "Resource." is prepended
-; to the name, then the underscores are removed and the name is mapped to title case.
-; <resource_name> may only have the letters A-Z (lowercase or uppercase), 0-9, the underscore, and
-; must start with a letter.
-; ex: resource_name => Resource.ResourceName
-; The name also maps to a real file located in RESOURCES_PATH by appending ".lsp" to the name:
-; ex: resource_name => load file: RESOURCES_PATH/resource_name.lsp
-; If <resource_name> implements <resource_action>, then that function is called.
-; <resource_action> follows the same naming rules as <resource_name>.
-; When <resource_action> is called, the optional paramters <resource_id> and <response_format>
-; are passed in.
-; <resource_id> may only contain numbers, and <response_format> may only contain letters.
-; If no <resource_action> is specified, then the resource's default function is called instead.
-(context MAIN) (new Class 'Route.Resource) (context Route.Resource)
+(context MAIN)
+(new Route 'Route.Resource) (context Route.Resource)
 
 (define (matches?)
 	(when (regex {^([a-z]\w+)(/([a-z]\w+))?(/(\d+))?(\.([a-z]+))?} QUERY_STRING 1)

example-site/dragonfly-framework/lib/classes.lsp

+;  Copyright (C) <2009> <Marc Hildmann, Greg Slepak>
+;
+;  This program is free software: you can redistribute it and/or modify
+;  it under the terms of the GNU General Public License as published by
+;  the Free Software Foundation, either version 3 of the License, or
+;  (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;  You should have received a copy of the GNU General Public License
+;  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;
+
+(new Class 'Route)
+(context 'Route)
+(define (matches?) nil)
+(define (run) nil)
+(context 'MAIN)
+
+(new Class 'Resource)
+
+; nothing so far.. but it's recommend to "inherit" from it anyway
+; for future possibilities...

example-site/dragonfly-framework/lib/log.lsp

-;;  Copyright (C) <2009> <Marc Hildmann, Greg Slepak>
-;;
-;;  This program is free software: you can redistribute it and/or modify
-;;  it under the terms of the GNU General Public License as published by
-;;  the Free Software Foundation, either version 3 of the License, or
-;;  (at your option) any later version.
-;;
-;;  This program is distributed in the hope that it will be useful,
-;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;;  GNU General Public License for more details.
-;;  You should have received a copy of the GNU General Public License
-;;  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-;;
+;  Copyright (C) <2009> <Marc Hildmann, Greg Slepak>
+;
+;  This program is free software: you can redistribute it and/or modify
+;  it under the terms of the GNU General Public License as published by
+;  the Free Software Foundation, either version 3 of the License, or
+;  (at your option) any later version.
+;
+;  This program is distributed in the hope that it will be useful,
+;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;  GNU General Public License for more details.
+;  You should have received a copy of the GNU General Public License
+;  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+;
+;; @module log.lsp
+;; @description Provides convenient logging facility for all of Dragonfly.
 ;; @author Greg Slepak
+;; <p>To avoid checking the value of 'Dragonfly:LOG_LEVEL' each time something is logged
+;; the logging functions that correspond to a lower logging level are disabled
+;; when this file is loaded.</p>
+;; <p>It is possible to change the 'LOG_LEVEL' at runtime, but the way it is done
+;; is slightly tricky because 'MAIN:load' is overwritten by Dragonfly
+;; to provide once-only loading. If you want to dynamically change the
+;; log-level (say in a plugin), then you will need to use the remapped 'sys-load'
+;; function to force a reload of this file:</p>
+;; <pre> (context 'DF)
+;; (constant 'LOG_LEVEL 'LOG_DEBUG) ; enable debug logging at runtime
+;; (sys-load (string DRAGONFLY_ROOT "/lib/log.lsp"))
+;; (context MAIN)</pre>
+;; There are four log levels defined:
+;; <pre> (map set '(LOG_DEBUG LOG_INFO LOG_WARN LOG_ERROR)
+;;          '(        0        1        2         3))</pre>
 
 (context 'Dragonfly)
 
 (map set '(LOG_DEBUG LOG_INFO LOG_WARN LOG_ERROR)
          '(        0        1        2         3))
 
-
+;; @syntax (Dragonfly:log-func <str-level> <str-msg>)
+;; @param <str-level> a string representing the log level (ex: "[DEBUG]: ")
+;; @param <str-msg> a string containing the message
+;; <br/>This function appends to the file specified by 'Dragonfly:LOG_FILE_PATH'
+;; and prepends date information to the log.
+;; <pre> (log-func "[CRAZY!]: " (string user " just did something crazy!"))
+;; => Oct 26 01:44:24 [CRAZY!]: johnny-b just did something crazy!</pre>
+;; All other log functions call this one. You can override this function
+;; at runtime to provide your own logging behavior.
 (define (log-func level msg)
 	(append-file LOG_FILE_PATH (string (date (date-value) 0 "%b %d %H:%M:%S ") level msg "\n"))
 )
 
+;; @syntax (Dragonfly:log-debug)
+;; <br>String-concats its arguments and calls 'log-func' with <level> set to "[DEBUG]: "
 (define (log-debug)
 	(log-func "[DEBUG]: " (apply string $args))
 )
 
+;; @syntax (Dragonfly:log-info)
+;; <br>String-concats its arguments and calls 'log-func' with <level> set to "[INFO]: "
 (define (log-info)
 	(log-func "[INFO]: " (apply string $args))
 )
 
+;; @syntax (Dragonfly:log-warn)
+;; <br>String-concats its arguments and calls 'log-func' with <level> set to "[WARNING]: "
 (define (log-warn)
 	(log-func "[WARNING]: " (apply string $args))
 )
 
+;; @syntax (Dragonfly:log-err)
+;; <br>String-concats its arguments and calls 'log-func' with <level> set to "[ERROR]: "
 (define (log-err)
 	(log-func "[ERROR]: " (apply string $args))
 )

example-site/dragonfly-framework/lib/request.lsp

 ;; If a variable was specified, but no value assigned (i.e. '/?foo'), then
 ;; the value will be an empty string (you can use 'empty?' to check for this).
 ;; If the variable does not exist, 'nil' will be returned.
-;; 
-;; The values are url decoded:
+;; <br><br>The values are url decoded:
 ;; <pre> "What+time+is+it%3f"  => "What time is it?"</pre>
 ;; <h3>$FILES</h3>
 ;; If a 'multipart/form-data' content type was submitted, then
 ;; STDIN is read for the values. Any files are placed in '$FILES', while
 ;; other key/value pairs are placed in '$POST'.
-;; 
-;; The values in '$FILES' contain an associative array with more information
+;; <br><br>The values in '$FILES' contain an associative array with more information
 ;; about the files.
 ;; <h3>$BINARY</h3>
 ;; If the environment variable 'HTTP_CONTENT_TRANSFER_ENCODING' is set to
 ;; stored in '$BINARY'. Note that unlike the other symbols in this file,
 ;; '$BINARY' is a string, not a function.
 ;; <h3>$COOKIES</h3>
-;; The environment variable 'HTTP_COOKIE' is parsed and the cookies are
+;; The environment variable 'HTTP_COOKIE' is parsed and the cookies are placed in
 ;; in '$COOKIES' as key/value pairs just like '$GET' and '$POST'.
-
 ;; @syntax ($GET <str-key>)
 ;; @return the value of the GET parameter for <str-key>, nil if no such GET variable was passed in.
 ;; @syntax ($POST <str-key>)
 ;; @return the value of the POST parameter for <str-key>, nil if no such POST variable was passed in.
 ;; @syntax ($FILES <str-key>)
+;; <p>Returns an association list with keys ''name', ''data', and ''length' for the result
+;; of a 'multipart/form-data' posted form.</p>
 ;; @syntax ($COOKIES <str-key>)
+;; @return the value of the cookie with the key <str-key>, or nil if no such cookie exists.
 ;; @syntax $BINARY
+;; <p>This is a global buffer that contains what was sent to STDIN (up to 'MAX_POST_LENGTH')
+;; when the value of environment variable 'HTTP_CONTENT_TRANSFER_ENCODING' is set to "binary".</p>
 
 ;===============================================================================
 ; !Global Variables

example-site/dragonfly-framework/lib/response.lsp

 
 ;; @syntax (Response:status)
 ;; @syntax (Response:status <int-code> [<str-description>])
-;; <br>In the first syntax...
+;; <p>In the first syntax, returns a list containing the current status code and corresponding description.</p>
+;; <p>In the second syntax, sets the response status to <int-code>, using the description from
+;; a built-in list. If the description for <int-code> is not found in the built-in
+;; list then an error will be thrown if <str-description> is not provided.</p>
 (define (status code description)
 	(if code
 		(begin
 			(unless (assoc code status-codes)
+				(if-not description
+					(throw-error (string "Unknown status code " code ". Please provide a description.")))
 				(push (list code description) status-codes))
 			(setf status-code code)
 		)
 )
 
 ;; @syntax (Response:header <str-key>)
-;; @param <str-key> the header's name
+;; @param <str-key> the header's name<br>
 ;; @syntax (Response:header <str-key> <str-value>)
 ;; @param <str-key> the header's name
 ;; @param <str-value> the header's value
 ;; <br>In the first syntax, returns the header matching <str-key> or,
-;; if <str-key> is nil, all of the headers in a list.
+;; if <str-key> is nil, all of the headers in an association list.
 ;; <br>In the second syntax, sets or updates the header matching <str-key> or,
 ;; if <str-value> is nil, deletes the header for <str-key>.
 (define (header key)
 )
 
 ;; @syntax (Response:cookie <str-key>)
-;; @param <str-key> the cookie's name
+;; @param <str-key> the cookie's name<br>
 ;; @syntax (Response:cookie <str-key> <str-value> [<int-expires> [<str-path> [<str-domain> [<bool-http-only>]]]])
 ;; @param <str-key> the cookie's name
 ;; @param <str-value> the cookie's value
 )
 
 ;; @syntax (Response:send-headers)
-;; <br>Actually sends the headers (without buffering them to 'Dragonfly:STDOUT').
-;; Normally you should never call this yourself!
+;; <p>Actually sends the headers (without buffering them to 'Dragonfly:STDOUT').
+;; Normally you should never call this yourself!</p>
 (define (send-headers)
 	(sys-print "Status: " status-code " " (lookup status-code status-codes) "\r\n")
 	(dolist (header headers) (sys-print (first header) ": " (last header) "\r\n"))
 ; !Public Convenience Functions and Variables
 ;===============================================================================
 
-(define (redirect path)
-	(header "Location" path)
+;; @syntax (Response:redirect <str-url>)
+;; @param <str-url> The URL you'd like to send them to
+;; <p>Does an immediate 302 Found redirect and calls 'exit'.</p>
+(define (redirect url)
+	(header "Location" url)
 	(status 302)
 	(send-headers)
 	(exit)
 )
 
+;; @syntax (Response:send-headers-with-status <int-code> <str-description>)
+;; <p>Convenience. Combines a call to 'Response:status' and 'Response:send-headers'.
+;; As this calls 'send-headers', you typically do not want to call this yourself!</p>
 (define (send-headers-with-status code description)
 	(status code description)
 	(send-headers)
 )
 
+;; @syntax (Response:content-type <str-value>)
+;; <p>Convenience for calling '(Response:header "Content-Type" str-value)'.</p>
+;; <p>If <str-value> is nil, returns the current content-type value</p>
 (define (content-type value)
 	(if value
 		(header "Content-Type" value)
 	)
 )
 
+;; @syntax (Response:extension->type <str-file-extension>)
+;; <p>Given a file extension (with or without a preceding dot), returns the
+;; MIME-type for that extension. Currently only a small number of file extensions
+;; are supported by default, see the source in lib/response.lsp for a complete list.</p>
 (define (extension->type file-extension)
 	(if-not (starts-with file-extension ".") (push "." file-extension))
 	(eval (lookup file-extension extension-to-type-map))

example-site/dragonfly-framework/lib/utils.lsp

 ; NOTE: it's OK to load this file multiple times
 ;; @module utils.lsp
 ;; @author Greg Slepak <greg at taoeffect.com>
+;; <p>This file not only provides the functions documented below, but
+;; it also plays a role in globally overriding certain functions in the MAIN context.</p>
+;; <p>The overridden functions include: 'load', 'print', and 'println'.</p>
+;; <p>'load' is overwritten to load a file only once, while 'print' and 'println'
+;; are overwritten to send their output the the 'Dragonfly:STDOUT' buffer, allowing
+;; Dragonfly to ensure pages are displayed properly.</p>
 
 ; protect against situation where one of the load functions is used to
 ; load this file, thereby redefining the function itself while it's running
 	; If someday newLISP supports switching contexts like this we'll use it
 	(define-macro (define-subclass)
 		(new (args 0 1) (args 0 0))
-		(context (args 0 0))
+		;(context (args 0 0))
 		(dolist (method (rest $args))
 			(setf (method 0 0) (sym $it (args 0 0)))
 			(eval (push 'define method))
 		)
-		(context MAIN)
+		;(context MAIN)
 	)
 	
 ;; @syntax (regex-captcha <str-regex> <str> [<int-options>] [<int-captcha>])
+;; @param <int-options> options to regex, defaults to 0.
+;; @param <int-captch> which of the regex group captures to return, defaults to 1.
+;; <p>Returns the captured text, or nil if it couldn't be captured.<br/>This is a global function.</p>
+;; <b>example:</b>
+;; <pre> (regex-captcha {^(foo|bar).*} "foobaz") => "foo"
+;; (regex-captcha {^(foo|bar).*} "bazfoo") => nil</pre>
 ;; 
 	(define (regex-captcha regex-str str (options 0) (captcha 1))
 		(if (regex regex-str str options)
 	)
 	
 ;; @syntax (load-files-in-dir <str-dir> <regex-match>)
+;; <p>Loads all the files in <str-dir> matching <regex-match>. Does not
+;; traverse subdirectories.<br/>This is a global function.</p>
 ;;
 	(define (load-files-in-dir dir regex-match)
 		(dolist (x (directory dir regex-match))
 			(load-once (string dir "/" x))
 		)
 	)
+
+;; @syntax (into-ctx-assoc <ctx> <list-assoc>)
+;; <p>Places the key/value pairs in <list-assoc> into the context <ctx>
+;; to be used as a lookup table.<br/>This is a global function.</p>
+;; <b>example:</b>
+;; <pre> (new Tree 'MyCtx)
+;; (into-ctx-assoc MyCtx '(
+;;     ("key" "value")
+;;     ("apple" "mmmm... good")
+;;     ("organic?" true)
+;; ))</pre>
+;; 
+	(define (into-ctx-assoc ctx assoc-list)
+		(dolist (x assoc-list) (ctx (x 0) (x 1))) ; here dolist is slightly faster than map
+	)
 	
-	; these two functions should be global (define-subclass should not)
-	(global 'load-files-in-dir 'regex-captcha 'load-once)
+	
+	; these functions should be global (define-subclass should not)
+	(global 'load-files-in-dir 'regex-captcha 'load-once 'into-ctx-assoc)
 	
 	; swap these functions for ours and save the originals
 	(constant (global 'sys-load) load)

example-site/dragonfly-framework/plugins-inactive/artfulcode/http.lsp

+;; @module Http
+;; @author Jeff Ober <jeffober@gmail.com>
+;; @version 1.1
+;; @location http://static.artfulcode.net/newlisp/http.lsp
+;; @package http://static.artfulcode.net/newlisp/http.qwerty
+;; @description A bare-bones HTTP 1.0 library (updated for newlisp 10).
+;; Http is an extremely bare-bones HTTP 1.0 library. Not all functionality
+;; is implemented. In particular, the ability to parse an HTTP response is not
+;; yet finished, but the ability to parse requests and send both requests and
+;; responses is finished.
+;; This module has not been rigorously tested. Your mileage may vary. Requires
+;; newlisp 10.
+;; <h4>Version history</h4>
+;; <b>1.1</b>
+;; &bull; updated for newlisp 10
+;; &bull; code clean-up
+;; 
+;; <b>1.0</b>
+;; &bull; initial release
+
+(context 'Http)
+
+(constant 'request-init-re (regex-comp {^(GET|POST|HEAD|PUT) (.+?) HTTP/(1.\d)$}))
+(constant 'request-header-re (regex-comp {^(.+?):\s+(.+?)$}))
+(constant 'line-ending-re (regex-comp [text][\r\n]{2,4}[/text]))
+(constant 'response-template "HTTP/1.0 %d OK\r\nConnection: close\r\nContent-Type: %s\r\nDate: %s\r\nContent-Length: %d%s\r\n\r\n%s")
+
+(define (format-header pair)
+  (format "%s: %s" (title-case (string (pair 0))) (string (pair 1))))
+
+;; @syntax (Http:parse-request <str-request>)
+;; @param <str-request> an HTTP request received
+;; <p>Parses an HTTP request and returns an association list.</p>
+;; @example
+;; (parse-request
+;;   (format-request "POST"
+;;                   "/cgi-bin/post_comment.cgi"
+;;                   '(("Host" "www.somesite.com"))
+;;                   "name=Some+Person&comment=Hello+world!"))
+;;
+;; => (("method" "POST")
+;;     ("path" "/cgi-bin/post_comment.cgi")
+;;     ("http-version" "1.0")
+;;     ("headers" (("host" "www.somesite.com")
+;;                 ("content-length" "37") nil)) 
+;;     ("content" ""))
+(define (parse-request req , lines request headers)
+  (when (and (string? req) (not (empty? req)))
+    (setf lines (map trim (parse req line-ending-re 0x10000)))
+    (setf headers '())
+    (setf request
+      (first (find-all request-init-re (first lines)
+               (list (list "method" $1) (list "path" $2) (list "http-version" $3))
+               0x10000)))
+    (when request
+      (dolist (line (slice lines 1 -1))
+        (push (first (find-all request-header-re line (list (lower-case $1) $2) 0x10000))
+          headers -1))
+      (push (list "headers" headers) request -1)
+      (push (list "content" (slice (last lines) 0)) request -1)
+      request)))
+
+;; @syntax (Http:format-response <str-response> [<int-code> [<str-content-type> [<assoc-headers>]]])
+;; @param <str-response> the text of the HTTP response
+;; @param <int-code> the HTTP response code; default is 200 (success)
+;; @param <str-content-type> MIME type of response; default is "text/html"
+;; @param <assoc-headers> association list of headers to add to response
+;; <p>Formats an HTTP/1.0 response.</p>
+;; @example
+;; (format-response binary-file-content 200 "audio/mp3")
+;; => "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: audio/mp3\r\nDate: Tue, 08 Jul 2008 10:30:09 EDT\r\nContent-Length: 17\r\n\r\n11000101010101..."
+(define (format-response response (code 200) (content-type "text/html") (extra-headers '()))
+  (format response-template
+          code
+          content-type
+		      (date (date-value) 0 "%a, %d %b %Y %H:%M:%S %Z")
+		      (length response)
+		      (if-not (empty? extra-headers)
+				    (string "\r\n" (join (map format-header extra-headers) "\r\n"))
+				    "")
+		      response))
+
+;; @syntax (Http:format-request <str-method> [<str-path> [<assoc-headers> [<str-content>]]])
+;; @param <str-method> request method (GET, POST, HEAD, or PUT)
+;; @param <str-path> request path; default is "/"
+;; @param <assoc-headers> association list of headers to add to request
+;; @param <str-content> for POST and PUT methods, string containing request content
+;; <p>Formats an appropriate HTTP/1.0 request. Note that the "Host" header must be added explicitly if required.</p>
+;; @example
+;; (format-request "POST"
+;;                 "/cgi-bin/post_comment.cgi"
+;;                 '(("Host" "www.somesite.com"))
+;;                 "name=Some+Person&comment=Hello+world!"))
+;; => "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\nDate: Tue, 08 Jul 2008 10:28:03 EDT\r\nContent-Length: 46\r\n\r\n<html><body><h1>Hello world</h2></body></html>"
+(define (format-request method (path "/") (headers '()) content, (buf ""))
+  (if-not (and (string? method) (find (upper-case method) '("GET" "POST" "HEAD" "PUT")))
+	  (throw-error "Invalid or unimplemented HTTP method"))
+  (setf method (upper-case method))
+  (write-buffer buf (format "%s %s HTTP/1.0\r\n" method (string path)))
+  (dolist (header headers)
+    (write-buffer buf (format "%s\r\n" (format-header header))))
+  (when content
+		(write-buffer buf (format "Content-Length: %d\r\n\r\n" (length content)))
+		(write-buffer buf content))
+  (write-buffer buf "\r\n\r\n")
+  buf)
+
+(context MAIN)

example-site/dragonfly-framework/plugins-inactive/http.lsp

-;; @module Http
-;; @author Jeff Ober <jeffober@gmail.com>
-;; @version 1.1
-;; @location http://static.artfulcode.net/newlisp/http.lsp
-;; @package http://static.artfulcode.net/newlisp/http.qwerty
-;; @description A bare-bones HTTP 1.0 library (updated for newlisp 10).
-;; Http is an extremely bare-bones HTTP 1.0 library. Not all functionality
-;; is implemented. In particular, the ability to parse an HTTP response is not
-;; yet finished, but the ability to parse requests and send both requests and
-;; responses is finished.
-;; This module has not been rigorously tested. Your mileage may vary. Requires
-;; newlisp 10.
-;; <h4>Version history</h4>
-;; <b>1.1</b>
-;; &bull; updated for newlisp 10
-;; &bull; code clean-up
-;; 
-;; <b>1.0</b>
-;; &bull; initial release
-
-(context 'Http)
-
-(constant 'request-init-re (regex-comp {^(GET|POST|HEAD|PUT) (.+?) HTTP/(1.\d)$}))
-(constant 'request-header-re (regex-comp {^(.+?):\s+(.+?)$}))
-(constant 'line-ending-re (regex-comp [text][\r\n]{2,4}[/text]))
-(constant 'response-template "HTTP/1.0 %d OK\r\nConnection: close\r\nContent-Type: %s\r\nDate: %s\r\nContent-Length: %d%s\r\n\r\n%s")
-
-(define (format-header pair)
-  (format "%s: %s" (title-case (string (pair 0))) (string (pair 1))))
-
-;; @syntax (Http:parse-request <str-request>)
-;; @param <str-request> an HTTP request received
-;; <p>Parses an HTTP request and returns an association list.</p>
-;; @example
-;; (parse-request
-;;   (format-request "POST"
-;;                   "/cgi-bin/post_comment.cgi"
-;;                   '(("Host" "www.somesite.com"))
-;;                   "name=Some+Person&comment=Hello+world!"))
-;;
-;; => (("method" "POST")
-;;     ("path" "/cgi-bin/post_comment.cgi")
-;;     ("http-version" "1.0")
-;;     ("headers" (("host" "www.somesite.com")
-;;                 ("content-length" "37") nil)) 
-;;     ("content" ""))
-(define (parse-request req , lines request headers)
-  (when (and (string? req) (not (empty? req)))
-    (setf lines (map trim (parse req line-ending-re 0x10000)))
-    (setf headers '())
-    (setf request
-      (first (find-all request-init-re (first lines)
-               (list (list "method" $1) (list "path" $2) (list "http-version" $3))
-               0x10000)))
-    (when request
-      (dolist (line (slice lines 1 -1))
-        (push (first (find-all request-header-re line (list (lower-case $1) $2) 0x10000))
-          headers -1))
-      (push (list "headers" headers) request -1)
-      (push (list "content" (slice (last lines) 0)) request -1)
-      request)))
-
-;; @syntax (Http:format-response <str-response> [<int-code> [<str-content-type> [<assoc-headers>]]])
-;; @param <str-response> the text of the HTTP response
-;; @param <int-code> the HTTP response code; default is 200 (success)
-;; @param <str-content-type> MIME type of response; default is "text/html"
-;; @param <assoc-headers> association list of headers to add to response
-;; <p>Formats an HTTP/1.0 response.</p>
-;; @example
-;; (format-response binary-file-content 200 "audio/mp3")
-;; => "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: audio/mp3\r\nDate: Tue, 08 Jul 2008 10:30:09 EDT\r\nContent-Length: 17\r\n\r\n11000101010101..."
-(define (format-response response (code 200) (content-type "text/html") (extra-headers '()))
-  (format response-template
-          code
-          content-type
-		      (date (date-value) 0 "%a, %d %b %Y %H:%M:%S %Z")
-		      (length response)
-		      (if-not (empty? extra-headers)
-				    (string "\r\n" (join (map format-header extra-headers) "\r\n"))
-				    "")
-		      response))
-
-;; @syntax (Http:format-request <str-method> [<str-path> [<assoc-headers> [<str-content>]]])
-;; @param <str-method> request method (GET, POST, HEAD, or PUT)
-;; @param <str-path> request path; default is "/"
-;; @param <assoc-headers> association list of headers to add to request
-;; @param <str-content> for POST and PUT methods, string containing request content
-;; <p>Formats an appropriate HTTP/1.0 request. Note that the "Host" header must be added explicitly if required.</p>
-;; @example
-;; (format-request "POST"
-;;                 "/cgi-bin/post_comment.cgi"
-;;                 '(("Host" "www.somesite.com"))
-;;                 "name=Some+Person&comment=Hello+world!"))
-;; => "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\nDate: Tue, 08 Jul 2008 10:28:03 EDT\r\nContent-Length: 46\r\n\r\n<html><body><h1>Hello world</h2></body></html>"
-(define (format-request method (path "/") (headers '()) content, (buf ""))
-  (if-not (and (string? method) (find (upper-case method) '("GET" "POST" "HEAD" "PUT")))
-	  (throw-error "Invalid or unimplemented HTTP method"))
-  (setf method (upper-case method))
-  (write-buffer buf (format "%s %s HTTP/1.0\r\n" method (string path)))
-  (dolist (header headers)
-    (write-buffer buf (format "%s\r\n" (format-header header))))
-  (when content
-		(write-buffer buf (format "Content-Length: %d\r\n\r\n" (length content)))
-		(write-buffer buf content))
-  (write-buffer buf "\r\n\r\n")
-  buf)
-
-(context MAIN)

example-site/resources/wings.lsp

 
 (DF:activate-plugin "artfulcode/json")
 
+(new Resource 'Resource.Wings)
 (context 'Resource.Wings)
 
 (set 'my-data