# Boop! – a simple "low-tech" static site generator, for fun. **Important note:** Boop! is under development, it is probably full of bugs. Also, it is a pet project and isn't communautary (for the moment at least). Use it at your own risks. ## Installation In this guide, we assume you are using Linux. First, you should clone the Boop! repository and install its dependencies. Boop! requires Python 3.6 to work (mainly because of our use of the `f-strings`). ```console $ git clone https://framagit.org/marien.fressinaud/boop.git $ cd boop $ pip3 install -r requirements.txt $ cd .. ``` Then, add the path to your `.bashrc`: ```console $ echo export PATH="$(pwd)/boop:\$PATH" >> ~/.bashrc ``` And source it so it considers the change: ```console $ source ~/.bashrc ``` ## Usage First, create a project and execute the Boop! command: ```console $ mkdir my-website && cd my-website $ echo '

Welcome!

' > index.html $ boop.py Boop! ``` Now, you should have your "production-ready" website under a `./site` folder that you can upload on your server. ```console $ tree . ├── site │   └── index.html └── index.html ``` Well OK, Boop! basically just copied the `index.html` file under the `site` directory. Let's write an article then. For that, you'll need a template file under a `./templates` folder: ```console $ mkdir templates $ echo '{{ ARTICLE_CONTENT }}' > templates/article.html ``` Then, you can create a Markdown file under a `./articles` folder: ```console $ mkdir articles $ echo '# My first article' > articles/my-article.md $ boop.py $ tree . ├── articles │   └── my-article.md ├── site │   ├── feeds │   │   └── all.atom.xml │   ├── index.html │   ├── my-article.html ├── templates │   └── article.html └── index.html $ echo site/my-article.html

My first article

``` Please note that `./articles` folder only accepts Markdown files (i.e. extension is `.md`). As you can see, it also generates automatically [an Atom feed](https://en.wikipedia.org/wiki/Atom_(Web_standard)) under `./site/feeds/all.atom.xml`. You can define meta variables in the Markdown file which will be accessible then in the template. Variables are uppercased and prepended by `ARTICLE_`. For example, for the following Markdown file: ```markdown --- title: An article author: Marien --- This is my article. ``` And the HTML template: ```html {{ ARTICLE_TITLE }}

{{ ARTICLE_TITLE }}

By {{ ARTICLE_AUTHOR }}

{{ ARTICLE_CONTENT }} ``` It will produce the following file: ```html An article

An article

By Marien

This is my article.

``` For now, you can use any valid Python expression between `{{ }}`, you have access to the variables defined in the meta header, the Python builtin functions and the `datetime` module. The following meta variables have specific significance, especially in the Atom feed: - `slug` (defines the final URL of the article) - `title` - `author` - `date` (the date of publication) - `update` (the date of the last update) It is highly recommended to always specify `title` and `date` (or default values will be generated). The default value of `slug` is the name of the file without its extension. A default value for `author` can be set in the `configuration.yml` file. `date` and `update` must follow this format: `YYYY-MM-DD HH:MM`. Then, you'll probably want to have a page listing all the articles of your blog. For that, you'll need to create a `templates/blog.html` file. This template has access to a `ARTICLES` variable: ```html Blog ``` This will generate a `site/blog.html` page. `Article` model has several public methods: - `slug()`: the name of the generated file, without its extension - `title()`: the title of the article - `author()`: the author of the article - `url()`: the full URL of the article - `uuid()`: a unique identifier, based on the URL - `content()`: the article's content in HTML - `date()`: the publication date - `update()`: the last update date The root folder can contain a `static` folder as well. Its content will be copied under the `./site` folder: ```console $ tree . ├── articles │   └── my-article.md ├── site │   ├── feeds │   │   └── all.atom.xml │   ├── blog.html │   ├── index.html │   ├── my-article.html │   └── style.css ├── static │   └── style.css ├── templates │   ├── article.html │   └── blog.html └── index.html ``` Finally, you might want to create a `./configuration.yml` file. Four information are used by the Atom feed, so you might want to declare them: ```yaml url: http://my-website.org/ title: My website author: Dale Cooper timezone: Europe/Paris ``` You can declare as many variables as you want, they all will be accessible in the article template, uppercased and prepended by `SITE_`. `url` can be set to `filesystem` for development (it will generate paths to the output directory). If you want to use a different configuration in development, you can specify different options under a `development` section: ```yaml url: http://my-website.org/ title: My website author: Dale Cooper timezone: Europe/Paris development: url: filesystem ``` By default, `boop.py` command generates the website with production configuration. To use the development one you should pass the `--development` argument: ```console $ boop.py --development ``` You might find yourself limited by the article-only system. If you want to create additional pages, just put HTML files under a `pages` folder. The directory structure will be preserved. ```console $ mkdir -p pages/foo $ echo 'My page' > pages/foo/index.html $ boop.py $ tree . ├── articles │   └── my-article.md ├── pages │   └── foo │   └── index.html ├── site │   ├── feeds │   │   └── all.atom.xml │   ├── foo │   │   └── index.html │   ├── blog.html │   ├── index.html │   ├── my-article.html │   └── style.css ├── static │   └── style.css ├── templates │   ├── article.html │   └── blog.html ├── configuration.yml └── index.html ``` You can also define a generic page template in the `templates/page.html` file. The file's content is accessible through the `PAGE_CONTENT` variable. ```console $ echo '{{ PAGE_CONTENT }}' > templates/page.html $ echo 'My page' > pages/foo/index.html $ boop.py $ cat site/foo/index.html My page ``` Please note since the index page is considered as a "normal" page, this template **also applies to the index page**. You can define Yaml variables in the pages that will be used in the template then. The variables are uppercased and prepended by `PAGE_`. For instance, in a `pages/my-page.html` file: ```html --- title: My page ---
This is the content of my page
``` And in the `templates/page.html` file: ```html {{ PAGE_TITLE }}

{{ PAGE_TITLE }}

{{ PAGE_CONTENT }} ``` This will generate the `site/my_page.html` file: ```html My page

My page

This is the content of my page
``` Please note if you make use of a variable in the template, it must be defined in all pages then (for example, we must add a `title` variable to all the pages we created until now). You can also override the default template by setting a `template` variable in the Yaml header of pages and articles. Last feature is the "serie" one. You might want to regroup several articles because they are related. First, create a new folder under `articles`: ```console $ mkdir articles/my-serie ``` Then, let's write two articles with the following format: ```markdown --- title: First article of the serie author: Enora date: 2019-02-24 17:00 --- This is my first article. ``` If you call Boop!, you'll notice nothing different than before. Just note for the moment that the articles are not generated under a `my-serie` folder. To transform this folder into a serie, you'll have to create a `serie.html` file. This is a normal page (so it is generated with the `page` template), except that it is located under the `articles/` folder. So, write a `articles/my-serie/serie.html`: ```html --- title: My serie ---
This is the main page of my serie!
``` Now, if you call the `boop.py` command, you'll notice two things: a new page `site/serie/my-serie.html` and a new feed `site/feeds/my-serie.atom.xml`. The feed obviously contains only the articles from the serie. You can also access the serie object from the article template with `ARTICLE_SERIE`. The two most interesting functions to use on this object are `title()` and `url()`. To finish, you can create a template specific to series. For that, you'll have to set a `template: serie` variable in your `serie.html` files. The series have access to two additional variables: `ARTICLES` (such in the `blog` template but they are sorted from the older to the newer) and `FEED` which represent the Atom feed associated to your serie. You can call `FEED.url()` to create a link to your feed. ## Template syntax As explained above, you can create templates under the `./templates` folder. These templates are basic HTML files, with a pinch of special syntax. To output the value of a variable, we already saw how to do: ```html

{{ ARTICLE_CONTENT }}

``` Any valid Python expression is accepted here. For instance, you might want to display the article publication date in a human format: ```html
{{ datetime.strptime(ARTICLE_DATE, "%Y-%m-%d %H:%M").strftime("%a %d %B %Y")
``` Yes, it's a bit complex for now. Hopefully, you will not have to call this very often. Improvement is planned. Then, you might want to display content conditionnaly with a `if` statement: ```html {% if PAGE_TITLE %} {{ PAGE_TITLE }} - {{ SITE_TITLE }} {% else %} {{ SITE_TITLE }} {% endif %} ``` `elif` statement is also supported the same way as `if`. Finally, the `for` statement gives you the possibility to generate lists: ```html ``` ## Tests There are some tests (i.e. doctests) that can be run to check that everything works smoothly. They can be executed with: ```console $ python3 -m doctest -vf */*.py ```