initial commit

This commit is contained in:
Joachim Neu 2014-08-29 17:13:46 +02:00
parent 6ac5f25c3b
commit 22712fc787
6 changed files with 262 additions and 0 deletions

View File

@ -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
md_yaml/__init__.py Normal file
View File

@ -0,0 +1 @@
from .md_yaml import *

63
md_yaml/md_yaml.py Normal file
View File

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

View File

@ -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.

View File

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

View File

@ -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