From 0e807a41da79ddf1465f6908be0b977e8bb609d4 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 31 Mar 2012 21:15:24 -0400 Subject: [PATCH] Move paginator plugin into structure module. --- hyde/ext/plugins/structure.py | 146 +++++++++++++++++++++- hyde/tests/sites/test_paginator/site.yaml | 2 +- 2 files changed, 145 insertions(+), 3 deletions(-) diff --git a/hyde/ext/plugins/structure.py b/hyde/ext/plugins/structure.py index d35a67d..27e0768 100644 --- a/hyde/ext/plugins/structure.py +++ b/hyde/ext/plugins/structure.py @@ -1,12 +1,16 @@ # -*- coding: utf-8 -*- """ -Plugins related to folders and paths +Plugins related to structure """ from hyde.plugin import Plugin -from fswrap import Folder +from fswrap import File, Folder +from hyde.site import Resource +from hyde.util import pairwalk + +import os from fnmatch import fnmatch import operator @@ -171,3 +175,141 @@ class CombinePlugin(Plugin): else: return "".join([text] + [r.source.read_all() for r in resources]) + +class Page: + def __init__(self, posts, number): + self.posts = posts + self.number = number + +class Paginator: + """ + Iterates resources which have pages associated with them. + """ + + file_pattern = 'page$PAGE/$FILE$EXT' + + def __init__(self, settings): + self.sorter = getattr(settings, 'sorter', None) + self.size = getattr(settings, 'size', 10) + self.file_pattern = getattr(settings, 'file_pattern', self.file_pattern) + + def _relative_url(self, source_path, number, basename, ext): + """ + Create a new URL for a new page. The first page keeps the same name; + the subsequent pages are named according to file_pattern. + """ + path = File(source_path) + if number != 1: + filename = self.file_pattern.replace('$PAGE', str(number)) \ + .replace('$FILE', basename) \ + .replace('$EXT', ext) + path = path.parent.child(os.path.normpath(filename)) + return path + + def _new_resource(self, base_resource, node, page_number): + """ + Create a new resource as a copy of a base_resource, with a page of + resources associated with it. + """ + res = Resource(base_resource.source_file, node) + path = self._relative_url(base_resource.relative_path, + page_number, + base_resource.source_file.name_without_extension, + base_resource.source_file.extension) + res.set_relative_deploy_path(path) + return res + + @staticmethod + def _attach_page_to_resource(page, resource): + """ + Hook up a page and a resource. + """ + resource.page = page + page.resource = resource + + @staticmethod + def _add_dependencies_to_resource(dependencies, resource): + """ + Add a bunch of resources as dependencies to another resource. + """ + if not hasattr(resource, 'depends'): + resource.depends = [] + resource.depends.extend([dep.relative_path for dep in dependencies + if dep.relative_path not in resource.depends]) + + def _walk_pages_in_node(self, node): + """ + Segregate each resource into a page. + """ + walker = 'walk_resources' + if self.sorter: + walker = 'walk_resources_sorted_by_%s' % self.sorter + walker = getattr(node, walker, getattr(node, 'walk_resources')) + + posts = list(walker()) + number = 1 + while posts: + yield Page(posts[:self.size], number) + posts = posts[self.size:] + number += 1 + + def walk_paged_resources(self, node, resource): + """ + Group the resources and return the new page resources. + """ + added_resources = [] + pages = list(self._walk_pages_in_node(node)) + deps = reduce(list.__add__, [page.posts for page in pages], []) + + Paginator._attach_page_to_resource(pages[0], resource) + Paginator._add_dependencies_to_resource(deps, resource) + for page in pages[1:]: + # make new resource + new_resource = self._new_resource(resource, node, page.number) + Paginator._attach_page_to_resource(page, new_resource) + new_resource.depends = resource.depends + added_resources.append(new_resource) + + for prev, next in pairwalk(pages): + next.previous = prev + prev.next = next + + return added_resources + + +class PaginatorPlugin(Plugin): + """ + Paginator plugin. + + Configuration: in a resource's metadata: + + paginator: + sorter: time + size: 5 + file_pattern: page$PAGE/$FILE$EXT # optional + + then in the resource's content: + + {% for res in resource.page.posts %} + {% refer to res.url as post %} + {{ post }} + {% endfor %} + + {{ resource.page.previous }} + {{ resource.page.next }} + + """ + def __init__(self, site): + super(PaginatorPlugin, self).__init__(site) + + def begin_site(self): + for node in self.site.content.walk(): + added_resources = [] + paged_resources = (res for res in node.resources + if hasattr(res.meta, 'paginator')) + for resource in paged_resources: + paginator = Paginator(resource.meta.paginator) + added_resources += paginator.walk_paged_resources(node, resource) + + node.resources += added_resources + diff --git a/hyde/tests/sites/test_paginator/site.yaml b/hyde/tests/sites/test_paginator/site.yaml index 48a6c93..ac513fd 100644 --- a/hyde/tests/sites/test_paginator/site.yaml +++ b/hyde/tests/sites/test_paginator/site.yaml @@ -5,7 +5,7 @@ base_url: / # The base url for autogenerated links. plugins: - hyde.ext.plugins.meta.MetaPlugin - hyde.ext.plugins.sorter.SorterPlugin - - hyde.ext.plugins.paginator.PaginatorPlugin + - hyde.ext.plugins.structure.PaginatorPlugin meta: nodemeta: meta.yaml created: !!timestamp 2010-01-01 00:00:00