Started in August 2011, for my personal needs: website + blog.
Improved for my professional needs: OCaml course, software documentation and web sites.
Around 9500 lines of OCaml.
Development hosted on Github:
code: http://www.github.com/zoggy/stog
website+doc: http://zoggy.github.io/stog
Some sites generated with Stog:
Gallium's blog,
Introduction au langage OCaml,
a math article,
software websites (Chamo,
Genet,
Erssical).
a static site: easy to deploy, less security problems,
handling of blog posts, with dates, topics, keywords and associated RSS feeds,
dynamic comments for blog posts (⇒ using Disqus),
no new syntax,
using custom tags (e.g. section) to provide semantics in code,
avoid code duplication,
ability to use all HTML5 or any XML,
check internal references,
displaying evaluated OCaml code,
support for multiple languages (fr, en, ..),
ability to add specific features with plugins.
Three steps:
Read configuration file .stog/config and directory tree:
Handle "elements",
Copy other files, i.e. files not ignored and not elements.
Example: file doc.html from Stog's web site:
Example: file posts/release-0.7.0.html from Stog's web site:
Templates are regular XML documents, with some XML nodes which will be rewritten.
Templates are in the .stog/templates/ directory.
A template can be used in three ways:
according to an element type, this type being the root node tag of the element:
......page will result in using the .stog/template/page.tmpl file has template
for the element (and post.tmpl for post element).
referenced in the file attribute of a ]]> node,
used by other rewrite rules.
The template file .stog/templates/page.tmpl:
The template file .stog/templates/elt-in-list.tmpl:
An environment is a map associating tag names to rules. We note \Gamma(t) = f
to say that a function f is associated to the tag t in the environment \Gamma.
If no function is associated to t, then \Gamma(t) = \bot.
A rule is a function $f$ taking in parameters: an environment $\Gamma$, a list
of XML node attributes $l_a$, a list of XML (sub)nodes $l_{xml}$.
A rule, when applied, returns a list of XML nodes.
Let \mathcal{R}(\Gamma, n) be the function applying an environment \Gamma
to an XML node n = (t, l_a, l_{xml}). \mathcal{R}_l(\Gamma, l) applies \mathcal{R}(\Gamma, x)
on each element x of the list l.
The algorithm of \mathcal{R} is the following:
Apply \mathcal{R} on each attribute value, parsed as valid XML, to get a new list
of rewritten attributes l_a',
If \Gamma(t) = \bot, then return [(t, l_a', \mathcal{R}_l(\Gamma, l_{xml}))].
Else, with \Gamma(t) = f, return f(\Gamma, l_a', l_{xml}).
\mathcal{R} is called until a fixpoint is reached.
This rewrite engine is implemented in the Xtmpl library.
When we define an element, we're defining an environment \Gamma.
Example: consider the following element:
This is the body of my page
Here we defined an environment \Gamma with the following rules:
\Gamma("elt-title") = f_1 with f_1(\_,\_,\_) = [ "Example page" ]
\Gamma("author") = f_2 with f_2(\_,\_,\_) = [ "Maxence Guesdon" ]
\Gamma("elt-body") = f_3 with f_3(\_,\_,\_) = [ "This is the body of the page" ]
To compute the element's final XML, we apply this environment to the template
associated to the page type.
Remarks:
Of course, the initial environment is not empty. So defining an element adds rules to this initial
environment.
Predefined rules and user-defined rules can be more complex.
One of the element must be marked has "main", with a main="true" attribute.
This is usually the top index.html file but this is not mandatory.
The main element is the place to define rules for the initial environment. These rules are defined using
the stog: prefix (like an XML namespace). Defining stog:foo="bar" will
make this rule appear in the initial environment with the name "foo".
....
]]>
Having separate sessions is useful to prevent name pollution in your OCaml environment.
<archive-tree>,
<block>: to do the equivalent of LaTeX's \newenvironment,
<elements>: list elements according to type or other fields, associate RSS feed;
<graph>: include a graph of elements, linked by keywords,
<hcode> and <icode>: include syntax highlighted code (using Highlight),
<if>,
<inc>: include a node, to share code between elements,
<latex>: include latex rendered as SVG (using latex+dvisvgm),
<list>: add a separator between the sub nodes,
<prepare-toc> and <toc>: compute and insert table of contents,
<section>, <subsection>: default sectionning.
We must ensure some rules will be applied before or after others. For example:
computation of table of contents must occur before the <section>
nodes are rewritten, but after all <include> have been resolved,
most of rules must have been applied before resolving internal links.
Various levels of rewrite rules are defined, in a way mixing
Linux run levels and BASIC line numbering 😃
each level is numbered,
for each level, starting from level 0, the set of rewrite rules
is applied to each element content:
rules of level 0 are applied to all elements,
rules of next level are applied to all the resulting elements,
and so on until the last level.
predefined levels are numbered 0, 50, 100, 120, 150, 160; this lets
room for additional levels defined in plugins.
One can define "functions" with parameters, to factorize code:
Now the command function (rule) can be "called" with a specific value
for the prompt parameter:
This will produce the following code:
Developing plugins consists in writing some OCaml code:
More complex plugins can define new levels of rewrite rules.
By now, two plugins are already available:
Stog-writing: bibliography management, footnotes and automatic ids for paragraphs,
Stog-RDF: definition of an RDF graph associated to the generated site.
Some XML nodes are used to (easily) insert edges in the graph.
These two plugins aim at being able to write scientific artiles with semantic information
about elements of articles:
"this block is a proof of this proposition",
"this proof applies this theorem",
...
A module system will allow reusing functions and definitions. A simple system already exists:
]]>
The code above indicates to use definitions from .stog/modules/math.stm: