Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimneu committed Aug 29, 2014
1 parent 6ac5f25 commit 22712fc
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 0 deletions.
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,62 @@
pelican-md-yaml
===============

This [Pelican](https://github.com/getpelican/pelican) plugin adds a reader for Markdown files with [YAML](https://en.wikipedia.org/wiki/YAML) metadata.
As the well-known static site generator [Jekyll](https://github.com/jekyll/jekyll) uses Markdown files with YAML metadata, this eases migration from Jekyll to Pelican.
Also, YAML metadata allows for easier specification of more complex metadata, such as nested lists or dictionaries.

Installation
------------

Copy the `md_yaml` directory to the `plugins` directory of your Pelican project (or whatever directory you specified for plugins in Pelican's `PLUGIN_PATHS` setting) and add
`'md_yaml'` to the list of plugins (Pelican setting `PLUGINS`) of your project.

Usage
-----

All your Markdown files (ending in `.md`, `.markdown`, `.mkd` and `.mdown`) will now be interpreted as using YAML for their metadata.
The following example shows a very simple article (only one line of text at the bottom) but with quite complex metadata (everything between the `---`):

```
---
template: article_recipe
title: Tiramisù
components:
- name: Tiramisù
for: 10
ingredients:
- - 4
- eggs
- - 150g
- sugar
- - 10 small cups
- espresso
- - 500g
- mascarpone
- - 1 package
- ladyfingers
steps:
- Cook the espresso, pour it into a soup plate.
- Separate the eggs very carefully.
- Add very little salt to the egg white.
- Blend egg yolk and sugar and mix it extensively for some minutes using a mixer, until you obtain a homogenous mass.
- Add mascarpone and mix again very extensively.
- Beat the egg white and fold it into the other mass.
- Construct the tiramisù: First a layer of cream, then a layer of ladyfingers dipped into espresso, cream, ladyfingers, ..., cream. Sprinkle with cacao.
- Put the tiramisù into the fridge for about a night, serve cold!
---
Thank you Silvia for the recipe!
```

Warranty
--------

No warranty whatsoever is provided for either the code or the recipe provided above! ;) Use only at your own risk!

References
----------

* This Pelican plugin uses the Markdown extension `mdx_meta_yaml` found here: <https://github.com/teoric/python-markdown-yaml-meta-data>
* The Pelican plugin `markdown-pullquote` was used as an example for a Pelican plugin providing a Markdown extension and can be found here: <https://github.com/arocks/markdown-pullquote>
* A similar approach to YAML metadata in Markdown files can be found here: <http://ianbarton.net/posts/2013/Apr/06/blogging-with-emacs-org-mode-and-pelican/>
1 change: 1 addition & 0 deletions md_yaml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .md_yaml import *
63 changes: 63 additions & 0 deletions md_yaml/md_yaml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import sys
import os

from pelican import signals
from pelican.readers import BaseReader
from pelican.utils import pelican_open

try:
from markdown import Markdown
except ImportError:
Markdown = False

class MarkdownYAMLReader(BaseReader):
"""Reader for Markdown files with YAML metadata"""

enabled = bool(Markdown)
file_extensions = ['md', 'markdown', 'mkd', 'mdown']

def __init__(self, *args, **kwargs):
super(MarkdownYAMLReader, self).__init__(*args, **kwargs)
self.settings = args[0]
self.extensions = list(self.settings['MD_EXTENSIONS'])
if 'meta_yaml' not in self.extensions:
self.extensions.append('meta_yaml')

def _parse_metadata(self, meta):
"""Return the dict containing document metadata"""

output = {}
for name, value in meta.items():
name = name.lower()
output[name] = value
return output

def read(self, source_path):
"""Parse content and metadata of Markdown files with YAML metadata"""

self.__set_plugin_path()

self._md = Markdown(extensions=self.extensions)
with pelican_open(source_path) as text:
content = self._md.convert(text)
metadata = self._parse_metadata(self._md.Meta)

self.__unset_plugin_path()

return content, metadata

def __set_plugin_path(self):
self.__sys_path_old = sys.path[:]
for pluginpath in self.settings['PLUGIN_PATHS']:
sys.path.insert(0, pluginpath)
sys.path.insert(0, os.path.join(pluginpath, 'md_yaml'))

def __unset_plugin_path(self):
sys.path = self.__sys_path_old

def add_reader(readers):
for k in MarkdownYAMLReader.file_extensions:
readers.reader_classes[k] = MarkdownYAMLReader

def register():
signals.readers_init.connect(add_reader)
30 changes: 30 additions & 0 deletions md_yaml/mdx_meta_yaml/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
Copyright 2004 Manfred Stienstra (the original version)

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

8 changes: 8 additions & 0 deletions md_yaml/mdx_meta_yaml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-

from mdx_meta_yaml.extension import MetaYamlExtension

def makeExtension(configs=None):
if isinstance(configs, list):
configs = dict(configs)
return MetaYamlExtension(configs=configs)
100 changes: 100 additions & 0 deletions md_yaml/mdx_meta_yaml/extension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""
# YAML Meta Data Extension for [Python-Markdown](https://github.com/waylan/Python-Markdown)
This extension adds YAML meta data handling to markdown.
As in the original, meta data is parsed but not used in processing.
(YAML meta data is used e.g. by [pandoc](http://johnmacfarlane.net/pandoc/))
Dependencies: [PyYAML](http://pyyaml.org/)
Basic Usage:
>>> import markdown
>>> text = '''---
... Title: Test Doc.
... Author: Waylan Limberg
... Blank_Data:
... ...
...
... The body. This is paragraph one.
... '''
>>> md = markdown.Markdown(['meta_yaml'])
>>> print(md.convert(text))
<p>The body. This is paragraph one.</p>
>>> print(md.Meta) # doctest: +SKIP
{'blank_data': [''], 'author': ['Waylan Limberg'], 'title': ['Test Doc.']}
Make sure text without Meta Data still works (markdown < 1.6b returns a <p>).
>>> text = ' Some Code - not extra lines of meta data.'
>>> md = markdown.Markdown(['meta_yaml'])
>>> print(md.convert(text))
<pre><code>Some Code - not extra lines of meta data.
</code></pre>
>>> md.Meta
{}
Copyright 2014 Bernhard Fisseni
Based on the meta data extension included with Python-Markdown,
Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
License: BSD (see LICENSE.md for details)
"""

from __future__ import absolute_import
from __future__ import unicode_literals
from markdown import Extension
from markdown.preprocessors import Preprocessor
import yaml
# from yaml.scanner import ScannerError


class MetaYamlExtension (Extension):
"""Extension for parsing YAML-Metadata with Python-Markdown."""

def extendMarkdown(self, md, md_globals):
"""Add MetaYamlPreprocessor to Markdown instance."""

md.preprocessors.add('meta_yaml', MetaYamlPreprocessor(md), "_begin")


class MetaYamlPreprocessor(Preprocessor):
"""
Get Meta-Data.
A YAML block is delimited by
- a line '---' at the start
- and a '...' or '---' line
at the end.
"""

def run(self, lines):
""" Parse Meta-Data and store in Markdown.Meta. """

in_yaml = False
yaml_block = []
line = lines.pop(0)

if line == '---':
in_yaml = True
else:
lines.insert(0, line)

while in_yaml and lines:
line = lines.pop(0)
if line == '---' or line == '...':
break
yaml_block.append(line)

if yaml_block:
yaml_block = "\n".join(yaml_block)
meta = yaml.load(yaml_block)
self.markdown.Meta = meta

return lines

0 comments on commit 22712fc

Please sign in to comment.