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

4.2 KiB

Jouons un peu avec Jinja2 et YAML

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())