Functional Logo Perl                  
history | edit

A website generator from markdown files

This is the Perl program that generates most of the functional-perl.org website. It makes quite heavy use of functional-perl, and may serve as a demo, although it was originally written just for practical purposes, and doesn't really employ exemplary separation between pure and non-pure parts. (Todo: improve that aspect?)

The code that builds the table of content, process__with_toc__body in Htmlgen::Toc, is purely functional and may serve as an example of relatively involved functional code. It uses a variant of fold_right that also explicitely passes state while recursing down the input lists (the HTML (which is parsed to PXML) element bodies), which allows to collect the subsection headers (which don't need to reside within in the same HTML element) and get the numbering while mapping the HTML document to add the numbering at the same time. This code may look a bit involved, and could perhaps be abstracted into some PXML library functions (how would XSLT look to do the same?). It could be rewritten using normal fold_right or map (todo: try?) when ditching the purity aim and using side-effects to pass the state. (To be fair, Haskell programmers would probably do the same (todo: ask/try?), but at least the side-effects would be channeled to some extent?)

While we're explaining code: Htmlgen::Toc is one of the classes that follow the Htmlgen::PXMLMapper api (for others see the sub-packages in Htmlgen::Linking), which take a few configuration values (in a way similar to how currying might be used in functional languages that don't support OO) and are then used to build a hash table (by pxml_name_to_mapper in the gen script) which is passed to pxml_map_elements_exhaustively from PXML::Util. The mapper functions in the hash table receive the element and an "uplist", which is a linked list with the parents (with the direct one being the first). Note that purely functional data structures can't store links to parents in their elements (unless when cheating by way of recreating the parents on the fly or referring to them lazily); thus the mappers wouldn't know the context. But we can instead pass the context when those functions are actually called (which in typical functional manner is better since the same subtree can now be part of various different parents at the same time).

The htmlgen/ directory contains the universally usable program, whereas the website/ directory contains the configuration to build the functional-perl website.

Note that the first time you run it, it will test everything that is quoted and looks like a namespace on metacpan.org to see whether it's a module, which takes time and can fail with network or server errors; the results are cached, thus subsequent runs will be fast.

Contents

  • 1. Formatting
  • 2. Dependencies
  • 3. Run
  • 4. Hacking
  • 1. Formatting

    The *.md files support standard Markdown format (as implemented by Text::Markdown) plus the following additions:

    2. Dependencies

    Htmlgen needs Function::Parameters, Sub::Call::Tail, LWP::UserAgent, LWP::Protocol::https, and Text::Markdown (and URI which is probably depended on by LWP anyway.)

    If you don't want to (or can't) install Sub::Call::Tail, you can instead rely on the bundled tail expansion hack by running the second variant shown in the next section.

    3. Run

    website/gen
    

    or if you don't have Sub::Call::Tail installed:

    meta/tail-expand && HTMLGEN_=1 website/gen
    

    The output is written to website/www/.

    4. Hacking