mb@mb
7 years ago
4 changed files with 258 additions and 0 deletions
@ -0,0 +1,56 @@ |
|||||
|
Summary |
||||
|
------- |
||||
|
|
||||
|
This plugin allows easy, variable length summaries directly embedded into the |
||||
|
body of your articles. It introduces two new settings: ``SUMMARY_BEGIN_MARKER`` |
||||
|
and ``SUMMARY_END_MARKER``: strings which can be placed directly into an article |
||||
|
to mark the beginning and end of a summary. When found, the standard |
||||
|
``SUMMARY_MAX_LENGTH`` setting will be ignored. The markers themselves will also |
||||
|
be removed from your articles before they are published. The default values |
||||
|
are ``<!-- PELICAN_BEGIN_SUMMARY -->`` and ``<!-- PELICAN_END_SUMMARY -->``. |
||||
|
For example:: |
||||
|
|
||||
|
Title: My super title |
||||
|
Date: 2010-12-03 10:20 |
||||
|
Tags: thats, awesome |
||||
|
Category: yeah |
||||
|
Slug: my-super-post |
||||
|
Author: Alexis Metaireau |
||||
|
|
||||
|
This is the content of my super blog post. |
||||
|
<!-- PELICAN_END_SUMMARY --> |
||||
|
and this content occurs after the summary. |
||||
|
|
||||
|
Here, the summary is taken to be the first line of the post. Because no |
||||
|
beginning marker was found, it starts at the top of the body. It is possible |
||||
|
to leave out the end marker instead, in which case the summary will start at the |
||||
|
beginning marker and continue to the end of the body. |
||||
|
|
||||
|
If no beginning or end marker is found, and if ``SUMMARY_USE_FIRST_PARAGRAPH`` |
||||
|
is enabled in the settings, the summary will be the first paragraph of the post. |
||||
|
|
||||
|
The plugin also sets a ``has_summary`` attribute on every article. It is True |
||||
|
for articles with an explicitly-defined summary, and False otherwise. (It is |
||||
|
also False for an article truncated by ``SUMMARY_MAX_LENGTH``.) Your templates |
||||
|
can use this e.g. to add a link to the full text at the end of the summary. |
||||
|
|
||||
|
reST example |
||||
|
~~~~~~~~~~~~ |
||||
|
|
||||
|
Inserting the markers into a reStructuredText document makes use of the |
||||
|
comment directive, because raw HTML is automatically escaped. The reST equivalent of the above Markdown example looks like this:: |
||||
|
|
||||
|
My super title |
||||
|
############## |
||||
|
|
||||
|
:date: 2010-12-03 10:20 |
||||
|
:tags: thats, awesome |
||||
|
:category: yeah |
||||
|
:slug: my-super-post |
||||
|
:author: Alexis Metaireau |
||||
|
|
||||
|
This is the content of my super blog post. |
||||
|
|
||||
|
.. PELICAN_END_SUMMARY |
||||
|
|
||||
|
and this content occurs after the summary. |
@ -0,0 +1 @@ |
|||||
|
from .summary import * |
@ -0,0 +1,105 @@ |
|||||
|
""" |
||||
|
Summary |
||||
|
------- |
||||
|
|
||||
|
This plugin allows easy, variable length summaries directly embedded into the |
||||
|
body of your articles. |
||||
|
""" |
||||
|
|
||||
|
from __future__ import unicode_literals |
||||
|
from pelican import signals |
||||
|
from pelican.generators import ArticlesGenerator, StaticGenerator, PagesGenerator |
||||
|
import re |
||||
|
|
||||
|
def initialized(pelican): |
||||
|
from pelican.settings import DEFAULT_CONFIG |
||||
|
DEFAULT_CONFIG.setdefault('SUMMARY_BEGIN_MARKER', |
||||
|
'<!-- PELICAN_BEGIN_SUMMARY -->') |
||||
|
DEFAULT_CONFIG.setdefault('SUMMARY_END_MARKER', |
||||
|
'<!-- PELICAN_END_SUMMARY -->') |
||||
|
DEFAULT_CONFIG.setdefault('SUMMARY_USE_FIRST_PARAGRAPH', False) |
||||
|
if pelican: |
||||
|
pelican.settings.setdefault('SUMMARY_BEGIN_MARKER', |
||||
|
'<!-- PELICAN_BEGIN_SUMMARY -->') |
||||
|
pelican.settings.setdefault('SUMMARY_END_MARKER', |
||||
|
'<!-- PELICAN_END_SUMMARY -->') |
||||
|
pelican.settings.setdefault('SUMMARY_USE_FIRST_PARAGRAPH', False) |
||||
|
|
||||
|
def extract_summary(instance): |
||||
|
# if summary is already specified, use it |
||||
|
# if there is no content, there's nothing to do |
||||
|
if hasattr(instance, '_summary'): |
||||
|
instance.has_summary = True |
||||
|
return |
||||
|
|
||||
|
if not instance._content: |
||||
|
instance.has_summary = False |
||||
|
return |
||||
|
|
||||
|
begin_marker = instance.settings['SUMMARY_BEGIN_MARKER'] |
||||
|
end_marker = instance.settings['SUMMARY_END_MARKER'] |
||||
|
use_first_paragraph = instance.settings['SUMMARY_USE_FIRST_PARAGRAPH'] |
||||
|
remove_markers = True |
||||
|
|
||||
|
content = instance._content |
||||
|
begin_summary = -1 |
||||
|
end_summary = -1 |
||||
|
if begin_marker: |
||||
|
begin_summary = content.find(begin_marker) |
||||
|
if end_marker: |
||||
|
end_summary = content.find(end_marker) |
||||
|
|
||||
|
if begin_summary == -1 and end_summary == -1 and use_first_paragraph: |
||||
|
begin_marker, end_marker = '<p>', '</p>' |
||||
|
remove_markers = False |
||||
|
begin_summary = content.find(begin_marker) |
||||
|
end_summary = content.find(end_marker) |
||||
|
|
||||
|
if begin_summary == -1 and end_summary == -1: |
||||
|
instance.has_summary = False |
||||
|
return |
||||
|
|
||||
|
# skip over the begin marker, if present |
||||
|
if begin_summary == -1: |
||||
|
begin_summary = 0 |
||||
|
else: |
||||
|
begin_summary = begin_summary + len(begin_marker) |
||||
|
|
||||
|
if end_summary == -1: |
||||
|
end_summary = None |
||||
|
|
||||
|
summary = content[begin_summary:end_summary] |
||||
|
|
||||
|
if remove_markers: |
||||
|
# remove the markers from the content |
||||
|
if begin_summary: |
||||
|
content = content.replace(begin_marker, '', 1) |
||||
|
if end_summary: |
||||
|
content = content.replace(end_marker, '', 1) |
||||
|
|
||||
|
summary = re.sub(r"<div.*>", "", summary) |
||||
|
summary = re.sub(r"</div>", "", summary) |
||||
|
|
||||
|
instance._content = content |
||||
|
instance._summary = summary |
||||
|
instance.has_summary = True |
||||
|
|
||||
|
|
||||
|
def run_plugin(generators): |
||||
|
for generator in generators: |
||||
|
if isinstance(generator, ArticlesGenerator): |
||||
|
for article in generator.articles: |
||||
|
extract_summary(article) |
||||
|
elif isinstance(generator, PagesGenerator): |
||||
|
for page in generator.pages: |
||||
|
extract_summary(page) |
||||
|
|
||||
|
|
||||
|
def register(): |
||||
|
signals.initialized.connect(initialized) |
||||
|
try: |
||||
|
signals.all_generators_finalized.connect(run_plugin) |
||||
|
except AttributeError: |
||||
|
# NOTE: This results in #314 so shouldn't really be relied on |
||||
|
# https://github.com/getpelican/pelican-plugins/issues/314 |
||||
|
signals.content_object_init.connect(extract_summary) |
@ -0,0 +1,96 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
import unittest |
||||
|
|
||||
|
from jinja2.utils import generate_lorem_ipsum |
||||
|
|
||||
|
# generate one paragraph, enclosed with <p> |
||||
|
TEST_CONTENT = str(generate_lorem_ipsum(n=1)) |
||||
|
TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) |
||||
|
|
||||
|
|
||||
|
from pelican.contents import Page |
||||
|
import pelican.settings |
||||
|
|
||||
|
import summary |
||||
|
|
||||
|
class TestSummary(unittest.TestCase): |
||||
|
def setUp(self): |
||||
|
super(TestSummary, self).setUp() |
||||
|
pelican.settings.DEFAULT_CONFIG['SUMMARY_MAX_LENGTH'] = None |
||||
|
pelican.settings.DEFAULT_CONFIG['SUMMARY_USE_FIRST_PARAGRAPH'] = False |
||||
|
|
||||
|
summary.register() |
||||
|
summary.initialized(None) |
||||
|
self.page_kwargs = { |
||||
|
'content': TEST_CONTENT, |
||||
|
'context': { |
||||
|
'localsiteurl': '', |
||||
|
}, |
||||
|
'metadata': { |
||||
|
'summary': TEST_SUMMARY, |
||||
|
'title': 'foo bar', |
||||
|
'author': 'Blogger', |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
def _copy_page_kwargs(self): |
||||
|
# make a deep copy of page_kwargs |
||||
|
page_kwargs = dict([(key, self.page_kwargs[key]) for key in |
||||
|
self.page_kwargs]) |
||||
|
for key in page_kwargs: |
||||
|
if not isinstance(page_kwargs[key], dict): |
||||
|
break |
||||
|
page_kwargs[key] = dict([(subkey, page_kwargs[key][subkey]) |
||||
|
for subkey in page_kwargs[key]]) |
||||
|
|
||||
|
return page_kwargs |
||||
|
|
||||
|
def test_end_summary(self): |
||||
|
page_kwargs = self._copy_page_kwargs() |
||||
|
del page_kwargs['metadata']['summary'] |
||||
|
page_kwargs['content'] = ( |
||||
|
TEST_SUMMARY + '<!-- PELICAN_END_SUMMARY -->' + TEST_CONTENT) |
||||
|
page = Page(**page_kwargs) |
||||
|
summary.extract_summary(page) |
||||
|
# test both the summary and the marker removal |
||||
|
self.assertEqual(page.summary, TEST_SUMMARY) |
||||
|
self.assertEqual(page.content, TEST_SUMMARY + TEST_CONTENT) |
||||
|
|
||||
|
def test_begin_summary(self): |
||||
|
page_kwargs = self._copy_page_kwargs() |
||||
|
del page_kwargs['metadata']['summary'] |
||||
|
page_kwargs['content'] = ( |
||||
|
'FOOBAR<!-- PELICAN_BEGIN_SUMMARY -->' + TEST_CONTENT) |
||||
|
page = Page(**page_kwargs) |
||||
|
summary.extract_summary(page) |
||||
|
# test both the summary and the marker removal |
||||
|
self.assertEqual(page.summary, TEST_CONTENT) |
||||
|
self.assertEqual(page.content, 'FOOBAR' + TEST_CONTENT) |
||||
|
|
||||
|
def test_begin_end_summary(self): |
||||
|
page_kwargs = self._copy_page_kwargs() |
||||
|
del page_kwargs['metadata']['summary'] |
||||
|
page_kwargs['content'] = ( |
||||
|
'FOOBAR<!-- PELICAN_BEGIN_SUMMARY -->' + TEST_SUMMARY + |
||||
|
'<!-- PELICAN_END_SUMMARY -->' + TEST_CONTENT) |
||||
|
page = Page(**page_kwargs) |
||||
|
summary.extract_summary(page) |
||||
|
# test both the summary and the marker removal |
||||
|
self.assertEqual(page.summary, TEST_SUMMARY) |
||||
|
self.assertEqual(page.content, 'FOOBAR' + TEST_SUMMARY + TEST_CONTENT) |
||||
|
|
||||
|
def test_use_first_paragraph(self): |
||||
|
page_kwargs = self._copy_page_kwargs() |
||||
|
del page_kwargs['metadata']['summary'] |
||||
|
pelican.settings.DEFAULT_CONFIG['SUMMARY_USE_FIRST_PARAGRAPH'] = True |
||||
|
page_kwargs['content'] = '<p>' + TEST_SUMMARY + '</p>' + TEST_CONTENT |
||||
|
page = Page(**page_kwargs) |
||||
|
summary.extract_summary(page) |
||||
|
# test both the summary and the marker removal |
||||
|
self.assertEqual(page.summary, TEST_SUMMARY) |
||||
|
self.assertEqual(page.content, '<p>' + TEST_SUMMARY + '</p>' + TEST_CONTENT) |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
unittest.main() |
Loading…
Reference in new issue