From b7ce44f305459234c7fe2c1f90dc9e980e49ae36 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade <quantum.analyst@gmail.com> Date: Sat, 31 Mar 2012 21:19:04 -0400 Subject: [PATCH] Move the grouper plugin into meta module. --- hyde/ext/plugins/meta.py | 207 ++++++++++++++++++++++++++++++++- hyde/layouts/starter/site.yaml | 2 +- hyde/tests/ext/test_grouper.py | 9 +- 3 files changed, 213 insertions(+), 5 deletions(-) diff --git a/hyde/ext/plugins/meta.py b/hyde/ext/plugins/meta.py index 7b1defe..c6635d6 100644 --- a/hyde/ext/plugins/meta.py +++ b/hyde/ext/plugins/meta.py @@ -4,14 +4,15 @@ Contains classes and utilities related to meta data in hyde. """ import re +from collections import namedtuple from operator import attrgetter from itertools import ifilter from functools import partial from hyde.model import Expando from hyde.plugin import Plugin from hyde.fs import File, Folder -from hyde.site import Node -from hyde.util import add_method +from hyde.site import Node, Resource +from hyde.util import add_method, add_property, pairwalk import yaml @@ -513,3 +514,205 @@ class SorterPlugin(Plugin): setattr(prev, next_att, next) setattr(next, prev_att, prev) + +Grouper = namedtuple('Grouper', 'group resources') + +class Group(Expando): + """ + A wrapper class for groups. Adds methods for + grouping resources. + """ + + def __init__(self, grouping, parent=None): + self.name = 'groups' + self.parent = parent + self.root = self + self.root = parent.root if parent else self + self.groups = [] + self.sorter = getattr(grouping, 'sorter', None) + if hasattr(parent, 'sorter'): + self.sorter = parent.sorter + super(Group, self).__init__(grouping) + + add_method(Node, + 'walk_%s_groups' % self.name, + Group.walk_groups_in_node, + group=self) + add_method(Node, + 'walk_resources_grouped_by_%s' % self.name, + Group.walk_resources, + group=self) + add_property(Resource, + '%s_group' % self.name, + Group.get_resource_group, + group=self) + add_method(Resource, + 'walk_%s_groups' % self.name, + Group.walk_resource_groups, + group=self) + + def set_expando(self, key, value): + """ + If the key is groups, creates group objects instead of + regular expando objects. + """ + if key == "groups": + self.groups = [Group(group, parent=self) for group in value] + else: + return super(Group, self).set_expando(key, value) + + @staticmethod + def get_resource_group(resource, group): + """ + This method gets attached to the resource object. + Returns group and its ancestors that the resource + belongs to, in that order. + """ + try: + group_name = getattr(resource.meta, group.root.name) + except AttributeError: + group_name = None + + return next((g for g in group.walk_groups() + if g.name == group_name), None) \ + if group_name \ + else None + + @staticmethod + def walk_resource_groups(resource, group): + """ + This method gets attached to the resource object. + Returns group and its ancestors that the resource + belongs to, in that order. + """ + try: + group_name = getattr(resource.meta, group.root.name) + except AttributeError: + group_name = None + if group_name: + for g in group.walk_groups(): + if g.name == group_name: + return reversed(list(g.walk_hierarchy())) + return [] + + @staticmethod + def walk_resources(node, group): + """ + The method that gets attached to the node + object for walking the resources in the node + that belong to this group. + """ + for group in group.walk_groups(): + for resource in group.walk_resources_in_node(node): + yield resource + + @staticmethod + def walk_groups_in_node(node, group): + """ + The method that gets attached to the node + object for walking the groups in the node. + """ + walker = group.walk_groups() + for g in walker: + lister = g.walk_resources_in_node(node) + yield Grouper(group=g, resources=lister) + + def walk_hierarchy(self): + """ + Walks the group hierarchy starting from + this group. + """ + g = self + yield g + while g.parent: + yield g.parent + g = g.parent + + def walk_groups(self): + """ + Walks the groups in the current group + """ + yield self + for group in self.groups: + for child in group.walk_groups(): + yield child + + def walk_resources_in_node(self, node): + """ + Walks the resources in the given node + sorted based on sorter configuration in this + group. + """ + walker = 'walk_resources' + if hasattr(self, 'sorter') and self.sorter: + walker = 'walk_resources_sorted_by_' + self.sorter + walker = getattr(node, walker, getattr(node, 'walk_resources')) + for resource in walker(): + try: + group_value = getattr(resource.meta, self.root.name) + except AttributeError: + continue + if group_value == self.name: + yield resource + +class GrouperPlugin(Plugin): + """ + Grouper plugin for hyde. Adds the ability to do + group resources and nodes in an arbitrary + hierarchy. + + Configuration example + --------------------- + #yaml + sorter: + kind: + atts: source.kind + grouper: + hyde: + # Categorizes the nodes and resources + # based on the groups specified here. + # The node and resource should be tagged + # with the categories in their metadata + sorter: kind # A reference to the sorter + description: Articles about hyde + groups: + - + name: announcements + description: Hyde release announcements + - + name: making of + description: Articles about hyde design decisions + - + name: tips and tricks + description: > + Helpful snippets and tweaks to + make hyde more awesome. + """ + def __init__(self, site): + super(GrouperPlugin, self).__init__(site) + + def begin_site(self): + """ + Initialize plugin. Add the specified groups to the + site context variable. + """ + config = self.site.config + if not hasattr(config, 'grouper'): + return + if not hasattr(self.site, 'grouper'): + self.site.grouper = {} + + for name, grouping in self.site.config.grouper.__dict__.items(): + grouping.name = name + prev_att = 'prev_in_%s' % name + next_att = 'next_in_%s' % name + setattr(Resource, prev_att, None) + setattr(Resource, next_att, None) + self.site.grouper[name] = Group(grouping) + walker = Group.walk_resources( + self.site.content, self.site.grouper[name]) + + for prev, next in pairwalk(walker): + setattr(next, prev_att, prev) + setattr(prev, next_att, next) + diff --git a/hyde/layouts/starter/site.yaml b/hyde/layouts/starter/site.yaml index 901719d..6ec17d8 100644 --- a/hyde/layouts/starter/site.yaml +++ b/hyde/layouts/starter/site.yaml @@ -13,7 +13,7 @@ plugins: - hyde.ext.plugins.meta.AutoExtendPlugin # Plugins needed for the advances section. - hyde.ext.plugins.meta.SorterPlugin - - hyde.ext.plugins.grouper.GrouperPlugin + - hyde.ext.plugins.meta.GrouperPlugin - hyde.ext.plugins.meta.TaggerPlugin context: data: diff --git a/hyde/tests/ext/test_grouper.py b/hyde/tests/ext/test_grouper.py index 0a17e47..80d3735 100644 --- a/hyde/tests/ext/test_grouper.py +++ b/hyde/tests/ext/test_grouper.py @@ -6,7 +6,12 @@ Use nose """ from hyde.ext.plugins.meta import MetaPlugin from hyde.ext.plugins.meta import SorterPlugin +<<<<<<< HEAD from hyde.ext.plugins.grouper import GrouperPlugin +======= +from hyde.ext.plugins.meta import GrouperPlugin +from hyde.fs import File, Folder +>>>>>>> Move the grouper plugin into meta module. from hyde.generator import Generator from hyde.site import Site from hyde.model import Config, Expando @@ -31,7 +36,7 @@ class TestGrouperSingleLevel(object): plugins: - hyde.ext.plugins.meta.MetaPlugin - hyde.ext.plugins.meta.SorterPlugin - - hyde.ext.plugins.grouper.GrouperPlugin + - hyde.ext.plugins.meta.GrouperPlugin sorter: kind: attr: @@ -237,7 +242,7 @@ class TestGrouperSingleLevel(object): plugins: - hyde.ext.plugins.meta.MetaPlugin - hyde.ext.plugins.meta.SorterPlugin - - hyde.ext.plugins.grouper.GrouperPlugin + - hyde.ext.plugins.meta.GrouperPlugin sorter: kind: attr: