grimboite/articles/dev/jouons-un-peu-avec-jinja2-e...

4.3 KiB

Title Summary Tags
Jouons un peu avec Jinja2 et YAML Toi aussi, crée ton site statique en buvant un cocktail avec une main dans le dos et les pieds sur le bureau. yaml, jinja, ssg

Bon, et si je voulais développer mon propre générateur de sites statiques? Pas que ce soit nécessaire, car il y en a des dizaines de centaines de milliers (+une petite dizaine chaque jour), juste que j'en ai envie.

Les quelques idées sont les suivantes:

  • Utiliser markdown et ses extensions officielles pour la génération de code HTML.
  • Passer le tout dans Pygments pour la coloration de code
  • Ajouter une couche de Typogrify pour gérer quelques cas particuliers de mises en forme.
# coding: utf-8

from models import Site

from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
    loader=PackageLoader('grnx', 'templates'),
    autoescape=select_autoescape(['html'])
)

if __name__ == "__main__":
    root = Site('content')
    root.serialize()

    template = env.get_template('single.html')
    for article in root.articles:
        print(template.render(article.__dict__))

# coding: utf-8

import datetime
import json
import re
import os
import yaml


RE_HEADER = re.compile('---((.)?(\n)?)*---')

date_handler = lambda obj: (
    obj.isoformat()
    if isinstance(obj, datetime.datetime)
    or isinstance(obj, datetime.date)
    else None
)

def json_handler(obj):
    """Handles the JSON object serializer.

    Returns:
        The iso format if the object is a date.
        The __dict__ attribute for any other JSON serializable object.

    Excepts:
        TypeError when object is not JSON serialisable.
    """

    if hasattr(obj, 'isoformat'):
        return obj.isoformat()
    elif obj.__dict__:
        return obj.__dict__
    else:
        raise TypeError('Object of type %s with value of %s is not JSON serializable' % (type(obj), repr(obj)))


class Content(object):

    def __init__(self, filepath):

        with open(filepath, 'r') as f:
            try:
                file_content = f.read()
                print(file_content)
                regex_result = RE_HEADER.search(file_content)
                if regex_result:
                    header = file_content[regex_result.start():regex_result.end()-3]
                    self.properties = yaml.load(header)
                    headers = self.properties
                    print('headers: ' + str(headers))

                    self.published_date = headers.pop('Date', None)
                    self.last_modified_date = headers.pop('LastModified', self.published_date)
                    self.title = headers.pop('Title', None)
                    self.slug = headers.pop('Slug', None)
                    self.path = filepath
            except yaml.YAMLError as error:
                print(error)


class Site(object):
    """Represents a Site object.

    Args:
        articles: containt all articles.
        metadata: hum. I don't remember what I would store in this property.
        taxonomies: the taxonomies we find for this site. Tags, categories, ...

    """

    def __init__(self, current_path):
        self.articles = []
        self.metadata = {}
        self.taxonomies = {}

        for directory, dirnames, files in os.walk(current_path):
            for file in files:
                if file.endswith(".md"):
                    self.manage_article(directory, file)

    def manage_article(self, directory, file):
        article = Content(os.path.join(directory, file))
        self.articles.append(article)

        for taxonomy in article.properties:
            if taxonomy not in self.taxonomies:
                self.taxonomies[taxonomy] = []
            # TODO: we have to get the VALUE _and_ the article slug instead of just the slug.
            self.taxonomies[taxonomy].append(article.slug)

    def to_json(self):
        """Serialize the content of the current structure to JSON format."""

        return json.dumps(self, default=json_handler, sort_keys=True, indent=4)

    def serialize(self):
        """Serialize the current files structure to index.json"""

        with open('index.json', 'w') as json_serialized_file:
            json_serialized_file.write(self.to_json())