1 Introduction

#About HH-Web#

HH-Web is the beginnings of a web application framework written in Lisp designed to streamline development of modern web applications.

See the LICENSE file for the license covering all code within the HH-Web directory and any subdirectories.
Basically, it's the MIT license, so you are free to do what you want, provided you reproduce the original copyright.

##Platforms##

The primary platform for HH-Web development is SBCL x64 on Mac OS X Lion (latest SBCL rev tested is 1.0.57); other Common Lisp implementations that appear to work correctly are CCL 1.8 x86, LispWorks 6.01, and ABCL 1.0.1. HH-Web has also been tested with SBCL 1.0.57 x64 on Ubuntu 11.04.

Platforms with known issues include CCL x64 (problem with threads) and CMUCL (which does not like named-readtables).

##Features##

In its present form (as of June 2012), there are 4 principal features in HH-Web:

Composable widgets: HH-Web let's the developer write a web page using conventional Lisp s-expression syntax, complete with properly generated CSS & Javascript. More importantly, commonly used fragments of HTML/CSS/Javascript can be bundled as a tag (just like HTML tags such as p, div, h1, etc.), and the corresponding HTML/CSS/Javascript for the expected fragment will be generated instead. Using custom tags means that most of the development of a new site involves identifying the common elements that make up the site's pages, creating custom tags (with parameters or "attributes", when necessary) as needed, and then authoring the pages as templates using both HTML tags and the site-specific custom tags.

Regex-based URL dispatching: Inspired by Django's (and Rails') use of regex dispatching, HH-Web implements a similar technique, but in Lisp. Most importantly, if the regex contains "variables" (e.g., named registers, in regex parlance), then symbols will be interned for those variables and exposed as parameters to the URL's handler. Thus, components of an URL's path will automatically be extracted and made available as arguments to the handling code.

Dynamic code reloading: HH-Web automatically monitors specific files for new URL dispatching rules, page template changes, and all taglibraries. Changes in the underlying code is by default automatically reflected the next time the page is refreshed in the browser. The intent is to provide the equivalent usability of other web authoring environments such as PHP or ASP: change the code for a page, and reflect that immediately in the browser.

Integrated caching: HH-Web's support for caching is evolving, but in its current form it permits marking caching guidelines for specific URLs. Specifically, caching causes HH-Web to preseve any generated content (from templates and tags, typically) in an in-memory cache for later use. If a request for a page in its map appear again, then HH-Web will serve the content from the cache, rather than invoking code to regenerate the content fresh.

##Getting Started##

As an aide to starting new projects that use HH-Web to structure web application development, you can load the HH-Web system into the REPL using Quicklisp (included as of 7/3/2012--thanks Zach!):

(ql:quickload :hh-web)

then execute the following expression:

(hh-web:make-skeleton :for :acme :in #p"~/lisp/")

Substitute your own project name for acme in the above expression. Note that the argument to the :for keyword must be a symbol or string, and the argument to the :in keyword must be a directory path (e.g., it must end in "/"), although that directory should not exist, make-skeleton will not overwrite any files or directories that already present--it will raise an error instead. In the above example, the package for your new application will appear as a subdirectory of the one you provided, thus it will appear in ~/lisp/acme/.

If you use Quicklisp and the "~/lisp/" directory is registered with ASDF as a source directory, then you can then run the following at your REPL to start your newly-created web application:

To develop your site, edit the following files as needed, and refresh your browser to see changes take effect immediately:

urls.lisp for your request dispatch rules

templates.lisp for the declaring what templates you wish to use

any file in the taglibraries folder for designing your tag or widget libraries

any file in the templates folder for creating your own page templates

The generated skeleton also demonstrates one mechanism for integrating Bootstrap
and jQuery into a site, so that the resources of both libraries are always available.
Note that the chosen method here may or may not be suitable for your scenario: the skeleton generates
links to CDNs that host these libraries to ease other web sites.

Learning More

For more information on how HH-Web works and how to make use of it for your application, see the documentation on the wiki.

The active tag in the scope of a tag method (e.g., while rendering); while rendering a custom tag,
*this-tag* will not change within the same method, but *current-tag* changes within the body of each
tag in the content

Create a ssl server, using the provided initialization arguments for constructing the acceptor.
The acceptor class used internally inherits from hunchentoot’s easy-ssl-acceptor, so initialization arguments
valid for that class are also valid here as well. The initialization arguments need to have the following keyword
arguments with pathnames for values:

* :ssl-certificate-file
* :ssl-privatekey-file

You can also pass the keyword argument with a pathname as a value

* ssl-privatekey-password

In addition to initialization arguments, the following keywords are understood:

* folders : a list of pairs URL -> path mappings, where each points to a filesystem folder for static files
* packages : a list of of pairs of URL -> package mappings, where packages should have a www/ subfolder containing static files
* dispatchers: list of additional hunchentoot dispatchers to use, if the server cannot otherwise find a handler for a request
after attempting to locate a handler based on provided URL routes

Create a web server, using the provided initialization arguments for constructing the acceptor.
The acceptor class used internally inherits from hunchentoot’s easy-acceptor, so initialization arguments
valid for that class are also valid here as well.

In addition to initialization arguments, the following keywords are understood:

* folders : a list of pairs URL -> path mappings, where each points to a filesystem folder for static files
* packages : a list of of pairs of URL -> package mappings, where packages should have a www/ subfolder containing static files
* dispatchers: list of additional hunchentoot dispatchers to use, if the server cannot otherwise find a handler for a request
after attempting to locate a handler based on provided URL routes

Defines a service with the specified name, optional documentation, optional args and keyword args
(typically extracted from the URL associated with the service), and a set of methods.

If present, args appear as the parameter lists of methods in client script
and are used to construct the path of the request. The intent is
to enable passing of args from the client through the URL
and also to have named registers from the pattern
registered for the service available as well

Interpret the body as html markup, return multiple values, the first of which is an HTML string. The full list of return values is:

$(ul
(li "The intended title of the page containing this HTML fragment")
(li "Link elements that should appear in the head of the page containing this fragment")
(li "Style sheets required by the HTML fragment")
(li "Script libraries required by the HTML fragment")
(li "Sections of Javascript code required by the HTML fragment")
(li "Sections of Javascript code to be run on page initialization that are required by the HTML fragment")
)

Any of these values may be null (including the fragment itself). Care should be taken when nesting calls to this macro, as inline
expansion of $$ characters will occur in each invocation of it, and unexpected results may occur.

Interpret the raw body as html markup, and return a complete HTML page. In combination with $(a {:href "_macro_html"} "html"), this macro weaves
the output of calls to $(em "html") into a complete page, with styles, scripts, references to script libraries, a page title, etc., all arranged
in the appropriate order.

Execute body with the values of provided parameters in indicated variables. The parameter-list
should be a list of variable/parameter combinations, where each combination in the list
is of the form (variable parameter). The parameter name should be a string, the variable
should be a symbol referenced in the body.

Special parameter used in POST requests to indicate the actual desired
method (should be either ’DELETE’ or ’PUT’). Used by some browser-side
code as a substitute for situations where the browser will not allow Javascript
to send a native DELETE or PUT request.

Handle the service meta request with the named service, using the
meta argument (if non-nil) or the +meta-service-request-parameter+ to determine what to do.
Common meta service requests include (but are not limited to) the following values of
+meta-service-request-parameter+:

client - returns sufficient Javascript for invoking the service as an ordinary
function form javascript
help - returns an HTML page with a documentation string for the service
documentation - same as help
doc - same as help
docs - same as help
form - returns an HTML page with both the documentation string for the
service, but also a form suitable for entering parameters and then
invoking the service, as well as displaying (and changing?) values
of involved cookies before and after the invocation.

Render just the content portion of the tag (no styles or scripts):
usually, the start tag, the rendered body, and the end tag. In tags
that have a custom html representation, this is usually the method overriden.

Return a string representing script to run when a page
first loads. During rendering, scripts are accumulated by visiting each tag
in the page (depth, then breadth), and adding each unique script
(based on string comparison) to the end of a list. Consequently,
outer tags have their ready script run before inner tags.

Return t (the default) if a tag expects to
have a tag body; nil otherwise. If no body, that implies
the tag treats the raw body as an initializer for the tag,
and that a custom html method will then use the tag’s
slots to render appropriate html.

Return t (the default) if a tag expects to
have an end tag rendered (e.g., </a>); nil otherwise. If nil,
then the tag’s rendering only includes the start tag and content
(if any). Examples of use is the <img> and <input> tags.

Return 2 values (nil if the value is not applicable):
the first is the tag initializer, the 2nd is the tag’s computed body.
Default behavior takes the first list starting ith +@ and uses the
cdr of that list as the arguments to a make-instance call for that
tag class. All other items in the list will be returned in the 2nd
value for the body of the tag