News

[17/Sep/2009:19:20] Release 0.5 includes Open Flash Chart support.

[01/Jul/2009:10:50] Repoze.who authentication tutorial added

[22/Jun/2009:11:36] AJAX calculator tutorial added.

[01/May/2009:14:15] MVC/SQL based wiki tutorial added.



Contact Email:



view source
W1500.
whyIsWhiffCool.
whiff



Download instructions
at whiff.sourceforge.net
project page
.
WHIFF DOCUMENTION

Whiff is cool because...

This self-referential WHIFF document uses itself to describe why WHIFF is cool and why you can't write pages like this one as easily using any other method (as far as I know).

Please notice the headings listed below and click the footnote.  
×
This list of cross linked headings was generated automatically by a page fragment middleware named "headings" which worked in collaboration with the "heading" middleware to collect all the headings and automatically build page cross references. The present page did nothing except use these middlewares to build the headings.

Contents:

Look Mom, no database
Nothing up my sleeves...
The automatic navigation decorations
The comments area at the bottom
The index of contents
Syntax highlighted code displays
Dynamic examples
Pop-up footnotes
Wasn't that easy?
Audience
This page is addressed to developers with experience using other methods or frameworks for developing web applications.
You can't do this without WHIFF! ;c)
The page demonstrates some WHIFF features that are not easily emulated using other approaches, as far as I know.  
×
I could be wrong, please correct me by posting a response below.
The page also tries to explain the features demonstrated.
...That's why WHIFF is weird
Along the way we conversationally touch on some of the design motivations and rationales for the WHIFF architecture.
Your mission, should you choose to accept it

Please look at the browser formatted page, noting the features (and trying them where they require interaction), then look at the configuration source listing for the page colorize?page=W1500.whyIsWhiffCool to see how incredibly easy it was to do all this cool stuff!  

×
If you feel masochistic you could also use the browser "view source" feature to see the fully expanded HTML/javascript generated from the configuration template.
Complaints? Corrections? Rants?
If you disagree with my comments, please let me know publicly or privately -- I'm hoping to learn something from the replies. It would be especially great if you could point me to pages that show how to do things similar to the techniques illustrated below using other methods. Thanks in advance!

Look Mom, no database

This page uses no real database.  
×
In production deployment the documentation components use files in directories to record CAPTCHA data and page comments.
Many web development methods presuppose an SQL database backend. WHIFF does not. You can do a lot of neat stuff (like this page) using WHIFF with no database. You can use databases or other storage methods with WHIFF but WHIFF does not limit your options in any way.  
×
Furthermore, since WHIFF has no built in concept of a back end database, you can use any number of databases, or even a dynamic number of databases, without one of the databases being special.
I would like to rant about how it's a bad idea to automate database design, but I'll control myself.  
×
Or at least I'll restrict the rant to a footnote.

The basic problem with having database design automated is that you always need to change the design later -- and if your db-design automater says that they make changing the design easy, don't believe them. Usually when you need to change the design you have already populated the database with important information which has to be retrofitted back into the new database design, and in order to do this you have to understand everything about how the db-automator works, including such things as name mangling. It's not pretty.

Fixing the database later works much better when you put the database together carefully by hand in the first place and documented the database design in the process.

Nothing up my sleeves...

The WHIFF design attempts to follow the Python design maxim explicit is better than implicit. For this reason WHIFF is designed to avoid performing magic automatically.  
×
If you want WHIFF to serve a directory, you have to mark the directory; if you want WHIFF to serve static data from that directory, you have to indicate that; if you want a Python module to have a middleware or application interpretation, you must identify the interpretation function.
Furthermore WHIFF attempts to make the mapping between every bit of functionality and the implementation of that functionality easy to understand.

In spite of this rather pedantic attitude, it is easy to build complex, interactive web pages using WHIFF. Lets explore some of the features demonstrated on this page.

The automatic navigation decorations

None of the features used on this page are defined on this page -- they are all "imported" using other middleware scaffolds and fragments. In particular the entire page is processed by a middleware called comments which does a number of things.  
×
One feature of comments is turned off in the "production" deploy. When I run the script in development mode I see a form that allows me to add new subsections to the documentation hierarchy, which automatically fills in the standard document page components. In the production deploy this feature is not enabled. You can run the documentation in development mode too using INSTALL/doc/servedocs.py, and if you come up with a good subsection that you think I should add let me know.

One of the services provided by the comments middleware generates page navigation decorations for moving to other documentation pages. The implementation of the navigation decorations examines the files in the documentation directory, identifies the ancestors, children, and siblings of this page, and formats the titles and summaries of the related pages in two places -- there is a navigation pane showing the titles of related page on the upper left, and towards the bottom there is a summaries areas showing titles related pages with summaries of subsections.  

×
In this case there are no child subsections for this page.

The configuration for this page explicitly imported this functionality by putting the entire text of the page inside a include invoking the comments middleware.

{{include "comments"}}
   {{using title}} Whiff is cool because... {{/using}}
   {{using summary}} This self-referential... {{/using}}
   {{using body}} Please notice the... {{/using}}
{{/include}}
The comments middleware did the rest.

The comments area at the bottom

... But there's more! The comments middleware also automatically included an input form for the reader (you) to comment on the page. at the very bottom of the page.  
×
In order to make sure the commenter is a person and not an evil computer program, the form requires the commenter to translate a PNG image into a number correctly before the comment will be accepted.

The configuration for this page automatically got the comment recording service when it used the comments middleware. The storage mechanism for the comment text is configured externally as a resource by the WHIFF root module configuration.  

×
The root module is configured to store the comments in files in a directory. A one line change to the root module configuration could configure the comments to be stored in an SQL database instead of files without effecting the implementation of the comments middleware or any of the documentation pages.

The index of contents

At the top of the page is a table of contents linked to headers in the middle of the page. The configuration for this page uses two related middlewares to get the table of contents: heading and headings. The headings middleware wraps the main content of the page like this:
{{include "whiff_middleware/headings"}}
	{{using headingsFormat}}
       		{{include "headers"/}}
	{{/using}}
	{{using text}}
		This page is addressed to...

		 {{include "whiff_middleware/heading"}}
			 Look Mom, no database
		 {{/include}}

		This page uses no...

		 {{include "whiff_middleware/heading"}}
		 	Nothing up my sleeves
		 {{/include}}

		The WHIFF design ...
	{{/using}}
{{/include}}
The headings middleware establishes an environment data structure for collecting headings to construct a table of contents. The heading fragments both format the headings as HTML and record the heading text in the table of contents data structure. The headers application fragment formats the table of contents data structure into a sequence of internal HTML links from the top of the page to the relevant page header.  
×
The headings middleware implementation had to be just a bit clever to get this to work. Obviously, the heading middlewares must execute before the headers application -- so the headings middleware evaluates its text argument first and its headersFormat argument later so that the headersFormat argument can use the complete table of contents data structure. When headings delivers its HTML stream response it delivers the formatted headers first followed by the text.

To get the table of contents functionality this page included the relevant middlewares in appropriate positions -- no other explicit bookkeeping was needed.

Syntax highlighted code displays

This page also included syntax-highlighted code fragments created by the Pygments syntax highlighter. In the browser the fragment looks something like this
"hello world python script"

def hello():
    print "hello world"

if __name__=="__main__":
    hello()
In the source of the page configuration template the fragment looks similar, but less colorful
{{include "python"}}
"hello world python script"

def hello():
    print "hello world"

if __name__=="__main__":
    hello()
{{/include}}
Here we used the middleware python.whiff to colorize the python code.  
×
The implementation of python.whiff just passes the text to the pygments middleware after configuring the pygments middleware for Python code. Here is the configuration template source:
{{env whiff.content_type: "text/html"/}}
{{require page/}}
{{include "whiff_middleware/pygmentsColorize" 
           pygmentsCss.lexer: "python"}}
    {{use page/}}
{{/include}}
There are similar middlewares bash and whiffhtml which make colorizing other code examples just as easy.

Dynamic examples

In some cases it is nice to show what a WHIFF configuration looks like and what it does all at once. The "example" middleware allows the view to switch between viewing the configuration template, the colorized generated HTML, and the formatted HTML for a given example, for example like this:
whiff source generated page formatted output
temp content
The "use" of the example middleware is quite simple
{{include "example"}}
{{using targetName}}debugdump{{/using}}
{{using page}}
<h2>Environment entries:</h2>
<pre>
{{include "whiff_middleware/debugDump"/}}
</pre>
{{/using}}
{{/include}}
The implementation of the middleware generates quite a bit of javascript and cross references between the bits of javascript. It's a good thing the source for this page doesn't have to concern itself with any of that complexity!  
×
Someday I will make it simpler too -- the targetName is used by the javascript generator and could be eliminated. It is there for historical reasons at the moment.

Pop-up footnotes

Of course you have already seen the pop up footnotes.  
×
Like this one.
The footnotes are implemented by the footnote middleware
{{include "footnote"}}
Like this one.
{{/include}}
The footnote middleware is surprisingly complex because it wires together two HTML document object elements with two event handlers. But this page need not concern itself with any of that complexity. It just uses the middleware and the footnote appears.

Wasn't that easy?

Wasn't it easy to implement this page using WHIFF? Wouldn't it be much harder using other techniques? (Or not?)

Now that you have read the formatted HTML version of the page look at the configuration source listing for the page colorize?page=W1500.whyIsWhiffCool to see how incredibly easy it was to do all this cool stuff!

0 comments.
Care to comment?
name: (required)
- email (not published):
comment: (required)

<< security number? >>