Check the functional-perl website for properly formatted versions of these documents.
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 FunctionalPerl::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: FunctionalPerl::Htmlgen::Toc is one of the classes that
follow the FunctionalPerl::Htmlgen::PXMLMapper api (for others see the sub-packages
in FunctionalPerl::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.
<with_toc>
Formatting
The *.md files support standard
Markdown format
(as implemented by Text::Markdown) plus the following additions:
-
files are expected to carry a header similar to
"Check the [Foo website](http://foo.org/) for properly formatted versions of these documents. --- "which is stripped from the file
-
local urls starting with // are resolved to the path where the file with the given filename resides. Example:
[a thing](//some_thing.md)is being resolved to something like
<a href="../bar/some_thing.xhtml">a thing</a> -
wiki style links like:
[[some_thing]]or
[[some_thing|a thing]]are supported, converting to
<a href="../bar/some_thing.xhtml">some thing</a>or
<a href="../bar/some_thing.xhtml">a thing</a>respectively.
Dependencies
Htmlgen needs Perl version >= 5.20.0, 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.
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/.
Hacking
-
to work interactively with the code, run
website/gen --repl -
it takes the path to a perl file that returns a hash with configuration as result of its initialization. This hash is kept in locked state in the
$configglobal variable. -
some general layout configuration can be found in
htmlgen.css; this could be supplemented with other files using PXML HTML code returned from the function at theheadconfig key (see example ingen-config.pl). -
the configuration for the functional-perl website chooses to put logo generation into its own file,
logo.pl, so that it can be reused by the mailing list archive generator. -
the word "path0" in identifier names refers to a relative path from the site root.
-
$filesinfo(passed around explicitely for no particular reason?), is aFunctionalPerl::Htmlgen::_::Filesinfoobject, mutated to add information (remember that I said it was not meant as a functional programming demo), maintains information about all the files that make up the website. Likewise,$genfilestateis aFunctionalPerl::Htmlgen::_::Genfilestateobject, which also contains the former. -
its TEST forms are run as part of the functional-perl test suite (if the necessary dependencies are available)
</with_toc>