From baffbbbab971a0c7b6744a58b0289cddbf3a09b5 Mon Sep 17 00:00:00 2001 From: "mb@mb" Date: Wed, 16 May 2018 16:21:34 +0200 Subject: [PATCH] summary plugin added --- plugins/summary/Readme.rst | 56 +++++++++++++++++ plugins/summary/__init__.py | 1 + plugins/summary/summary.py | 105 ++++++++++++++++++++++++++++++++ plugins/summary/test_summary.py | 96 +++++++++++++++++++++++++++++ 4 files changed, 258 insertions(+) create mode 100644 plugins/summary/Readme.rst create mode 100644 plugins/summary/__init__.py create mode 100644 plugins/summary/summary.py create mode 100644 plugins/summary/test_summary.py diff --git a/plugins/summary/Readme.rst b/plugins/summary/Readme.rst new file mode 100644 index 0000000..29b3ed9 --- /dev/null +++ b/plugins/summary/Readme.rst @@ -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 ```` and ````. +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. + + 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. diff --git a/plugins/summary/__init__.py b/plugins/summary/__init__.py new file mode 100644 index 0000000..afe9311 --- /dev/null +++ b/plugins/summary/__init__.py @@ -0,0 +1 @@ +from .summary import * diff --git a/plugins/summary/summary.py b/plugins/summary/summary.py new file mode 100644 index 0000000..0fd89d1 --- /dev/null +++ b/plugins/summary/summary.py @@ -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', + '') + DEFAULT_CONFIG.setdefault('SUMMARY_END_MARKER', + '') + DEFAULT_CONFIG.setdefault('SUMMARY_USE_FIRST_PARAGRAPH', False) + if pelican: + pelican.settings.setdefault('SUMMARY_BEGIN_MARKER', + '') + pelican.settings.setdefault('SUMMARY_END_MARKER', + '') + 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 = '

', '

' + 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"", "", summary) + summary = re.sub(r"", "", 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) diff --git a/plugins/summary/test_summary.py b/plugins/summary/test_summary.py new file mode 100644 index 0000000..6dda508 --- /dev/null +++ b/plugins/summary/test_summary.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- + +import unittest + +from jinja2.utils import generate_lorem_ipsum + +# generate one paragraph, enclosed with

+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 + '' + 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' + 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' + TEST_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'] = '

' + TEST_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) + + +if __name__ == '__main__': + unittest.main()