Clone me from GitHub!
Grimoire is a minuscule static site generator written in Python. It focuses on generating content from simple data to be integrated in layouts. The root directory of a site should contain a site.json
descriptor file and a layouts/
directory containing all of the layouts to be used. Layouts can be any type of text files, including but not limited to HTML, CSS or SVG. The site descriptor file gives global variable and site categories to be loaded. It ressemble the following example :
{
"site": "My Blog",
"rootDirectory": "blog/",
"categories":[
{
"category": "Posts",
"reader": "postReader",
"files": "true",
"directories": "false"
},
{
"category": "Gallery",
"reader": "imageReader",
"files": "true",
"directories": "true"
}],
"description": "My Blog, built by Grimoire",
"title": "My Blog",
"githubUsername": "myUsername",
"someOtherVariable": "someValue"
}
site
: Code name of the site.rootDirectory
: Root directory of the site.description
: Description of the site.title
: Title of the site.categories
: List of the categories in the site (an array).category
: Category name and directory name from which the resource will be loaded.reader
: Name of the function to be used to read each resource file. Directories will not be read.files
: List the files in the category (true or false). The listing is recursive.directories
: List the directories in the category (true or false). The listing is recursive.Grimoire will start by listing all the files in layouts/
and then, all the files and directories (if enabled) in the categories (here Posts/
and Gallery/
). For each file found it will attempt to read it with the specified eader functions. Readers are located in the Modules/
directory. Each contains a python function def apply(filename):
which returns a tupple made of two elements, the first is a dictionnary of the data (key and value pairs) the other is the content of the resource. Both can be left empty if needed.
Each layout file can either be a raw text file or a text file with JSON header to declare variables separated from the text by a delimitation : -----
. To generate HTML pages the header must contain one of the two following variable : "generate" : "path/filename.html"
or "foreach" : "var in site.variableList"
. The first will generate a single page and the second will generate one page per resource, each page will be saved to the same path as the resource with a standard HTML extension.
{
"generate": "index.html",
"someVariable": "someValue"
}
-----
<!-- Some header -->
This is the index page.
<!-- Some footer -->
And for each of the posts :
{
"foreach": "post in site.categories.Posts.data",
"someVariable": "someValue"
}
-----
<!-- Some header -->
<h1>{{post.title}}</h1>
{{post.content}}
<!-- Some footer -->
Variables are surrounded by {{
and }}
. They are given as a standard object to member notation, with dots as separator : {{ rootObject.obj1.obj2.value }}
and can support spaces with double quotes : {{ rootObject."another object".value }}
. The following variables are set by default :
Variable | Description |
---|---|
site | Main site variable. |
site.site | Name of the site. |
site.rootDirectory | Root directory of the site on the server. |
site.dirname | Local root directory. |
side.outputDirname | Local output directory name. |
site.someVariable | Any variable someVariable defined in site.json . |
site.layouts | All the listed layouts, by name. |
site.layouts.myLayout | Layout variable corresponding to the file layouts/myLayout.ext (all the files there must have a different name). |
site.layouts.myLayout.content | Content of the previous file. |
site.layouts.myLayout.someVariable | Any variable someVariable defined in the header of the previous file. |
site.categories | Contains all the categories listed in alphabetical order. |
site.categories.myCategory | Object containing the category myCategory. |
site.categories.myCategories.someVariable | Any variable someVariable defined in the category descriptor in site.json . |
site.categories.myCategories.data | List of the resource loaded for this category (to be iterated), in alphabetical order. |
site.categories.myCategories.data."CategoryName/filename.ext" | Particular resource file content. |
site.categories.myCategories.data."CategoryName/filename.ext".content | Content of a particular resource. |
site.categories.myCategories.data."CategoryName/filename.ext".someVariable | Any variable someVariable defined in the header of the resource. |
For each resource we also have the following additional variables (resource
is an arbitrary name here) :
Variable | Description |
---|---|
resource.name | Name of the resource (filename without path nor extension). |
resource.isFile | Defined if this is a file. |
resource.filename | Filename of the resource. |
resource.basename | Basename of the resource. |
resource.dirname | Directory name of the resource |
resource.localFilename | Filename from the site root. |
resource.localDirname | Dirname from the site root. |
resource.directoryName | Name of the containing directory (without path). |
resource.parentDirname | Directory name of the parent (or None if it does not exist). |
resource.localParentDirname | Parent directory name from the site root. |
resource.outputDirname | Directory name for the output file. |
resource.urlDirname | Directory url for the output file. |
resource.outputFilename | Output filename. |
resource.url | Url of the page associated with resource. |
resource.urlRaw | Url of the resource. |
resource.firstFilename | Filename of the first file in the current directory. |
resource.firstFile | First file in the current directory. |
resource.firstDirname | Directory name of the first directory in the current directory. |
resource.firstDirectory | First directory in the current directory |
resource.previousFilename | Filename of the previous file in the current directory. |
resource.previousFile | Previous file in the current directory. |
resource.previousDirname | Previous directory name in the current directory. |
resource.previousDirectory | Previous directory in the current directory. |
resource.previousName | Name of the previous item in the current directory. |
resource.previous | Previous item in the current directory. |
resource.nextFilename | Filename of the next file in the current directory. |
resource.nextFile | Next file in the current directory. |
resource.nextDirname | Next directory name in the current directory. |
resource.nextDirectory | Next directory in the cyrrent directory. |
resource.nextName | Next item name in the current directory. |
resource.next | Next item in the current directory. |
resource.lastFilename | Filename of the last file in the current directory. |
resource.lastFile | Last file in the current directory. |
resource.lastDirname | Directory name of the last directory in the current directory. |
resource.lastDirectory | Last directory in the current directory. |
resource.lastName | Name of the last item in the current directory. |
resource.last | Last item in the current directory. |
resource.parentDirname | Directory name of the parent directory. |
resource.parent | Parent directory. |
resource.subFilenames | Filenames of the children files. |
resource.subFiles | Children files. |
resource.subDirnames | Directory names of the children directories. |
resource.subDirectories | Children directories. |
resource.subNames | Names of the children items. |
resource.sub | Children items. |
It is also possible to process information from the layouts with three constructs :
{% if object.variable %%
This text will be present in the final page if object.variable exists.
%}
{% ifnot object.variable %%
This text will be present in the final page if object.variable does not exist.
%}
Elements list :
{% foreach element in object.list %%
Here is another value : {{element.someValue}}
%}
Calling a function from the Modules/ folder :
{% call myFunction arg1 arg2 %%
Some relevant body.
%}
Finally, we can generate the site from the resources with the command : python /path/to/grimoire.py
from within the site directory. You can also start a local server with : python /path/to/grimoire.py --serve --port 8000