Browse Source

Splitting grouping and linking into their own plugins

main
Lakshmi Vyasarajan 14 years ago
parent
commit
0a9d66377c
7 changed files with 252 additions and 131 deletions
  1. +132
    -0
      hyde/ext/plugins/grouper.py
  2. +0
    -0
      hyde/ext/plugins/linker.py
  3. +3
    -62
      hyde/ext/plugins/sorter.py
  4. +10
    -4
      hyde/model.py
  5. +94
    -0
      hyde/tests/ext/test_grouper.py
  6. +1
    -65
      hyde/tests/ext/test_sorter.py
  7. +12
    -0
      hyde/util.py

+ 132
- 0
hyde/ext/plugins/grouper.py View File

@@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
"""
Contains classes and utilities related to grouping
resources and nodes in hyde.
"""
import re
from hyde.model import Expando
from hyde.plugin import Plugin
from hyde.site import Node, Resource
from hyde.util import add_method

from functools import partial
from itertools import ifilter, izip, tee, product
from operator import attrgetter


class Group(Expando):
"""
A wrapper class for groups. Adds methods for
grouping resources.
"""

def __init__(self, grouping):
super(Group, self).__init__(grouping)
name = 'group'

if hasattr(grouping, 'name'):
name = grouping.name

add_method(Node,
'walk_resources_grouped_by_%s' % name,
Group.walk_resources,
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) for group in value]
else:
return super(Group, self).set_expando(key, value)

@staticmethod
def walk_resources(node, group):
"""
The method that gets attached to the node
object.
"""
return group.list_resources(node)

def walk_groups(self):
"""
Walks the groups in the current group
"""
for group in self.groups:
yield group
group.walk_groups()


def list_resources(self, node):
"""
Lists the resources in the given node
sorted based on sorter configuration in this
group.
"""
walker = 'walk_resources'
if hasattr(self, 'sort_with'):
walker = 'walk_resources_sorted_by_' + self.sort_with
walker = getattr(node, walker, getattr(node, 'walk_resources'))

for resource in walker():
try:
group_value = getattr(resource.meta, self.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
sort_with: 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
self.site.grouper[name] = Group(grouping)

+ 0
- 0
hyde/ext/plugins/linker.py View File


+ 3
- 62
hyde/ext/plugins/sorter.py View File

@@ -1,12 +1,13 @@
# -*- coding: utf-8 -*-
"""
Contains classes and utilities related to sortin
Contains classes and utilities related to sorting
resources and nodes in hyde.
"""
import re
from hyde.model import Expando
from hyde.plugin import Plugin
from hyde.site import Node, Resource
from hyde.util import add_method

from functools import partial
from itertools import ifilter, izip, tee, product
@@ -58,39 +59,6 @@ def sort_method(node, settings=None):
key=attrgetter(*attr),
reverse=reverse)

def make_method(method_name, method_):
def method__(self):
return method_(self)
method__.__name__ = method_name
return method__

def add_method(obj, method_name, method_, settings):
m = make_method(method_name, partial(method_, settings=settings))
setattr(obj, method_name, m)


# class SortGroup(Expando):
# """
# A wrapper around sort groups. Understand hierarchical groups
# and group metadata.
# """
#
# def update(self, d):
# """
# Updates the Sortgroup with a new grouping
# """
#
# d = d or {}
# if isinstance(d, dict):
# for key, value in d.items():
# if key == "groups":
# for group in value:
#
# setattr(self, key, Expando.transform(value))
# elif isinstance(d, Expando):
# self.update(d.__dict__)



class SorterPlugin(Plugin):
"""
@@ -133,10 +101,9 @@ class SorterPlugin(Plugin):
return

for name, settings in config.sorter.__dict__.items():
self._add_groups(name, settings)
self.logger.info("Adding sort methods for [%s]" % name)
sort_method_name = 'walk_resources_sorted_by_%s' % name
add_method(Node, sort_method_name, sort_method, settings)
add_method(Node, sort_method_name, sort_method, settings=settings)
match_method_name = 'is_%s' % name
add_method(Resource, match_method_name, filter_method, settings)

@@ -153,29 +120,3 @@ class SorterPlugin(Plugin):
setattr(prev, next_att, next)
setattr(next, prev_att, prev)

def _add_groups(self, sorter_name, settings):
"""
Checks if the given `settings` contains a `groups` attribute.
If it does, it loads the specified groups into the `site` object.
"""
if not hasattr(settings, 'grouping') or \
not hasattr(settings.grouping, 'groups') or \
not hasattr(settings.grouping, 'name'):
return

grouping = Expando(settings.grouping)
setattr(self.site, sorter_name, grouping)

group_dict = dict([(g.name, g) for g in grouping.groups])
for resource in self.site.content.walk_resources():
try:
group_value = getattr(resource.meta, grouping.name)
except AttributeError:
continue
if group_value in group_dict:
group = group_dict[group_value]

if not hasattr(group, 'resources'):
group.resources = []
print "Adding resource[%s] to group[%s]" % (resource, group.name)
group.resources.append(resource)

+ 10
- 4
hyde/model.py View File

@@ -26,12 +26,18 @@ class Expando(object):
d = d or {}
if isinstance(d, dict):
for key, value in d.items():
setattr(self, key, Expando.transform(value))
self.set_expando(key, value)
elif isinstance(d, Expando):
self.update(d.__dict__)

@staticmethod
def transform(primitive):
def set_expando(self, key, value):
"""
Sets the expando attribute after
transforming the value.
"""
setattr(self, key, self.transform(value))

def transform(self, primitive):
"""
Creates an expando object, a sequence of expando objects or just
returns the primitive based on the primitive's type.
@@ -40,7 +46,7 @@ class Expando(object):
return Expando(primitive)
elif isinstance(primitive, (tuple, list, set, frozenset)):
seq = type(primitive)
return seq(Expando.transform(attr) for attr in primitive)
return seq(self.transform(attr) for attr in primitive)
else:
return primitive



+ 94
- 0
hyde/tests/ext/test_grouper.py View File

@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
"""
Use nose
`$ pip install nose`
`$ nosetests`
"""
from hyde.ext.plugins.meta import MetaPlugin
from hyde.ext.plugins.sorter import SorterPlugin
from hyde.ext.plugins.grouper import GrouperPlugin
from hyde.fs import File, Folder
from hyde.generator import Generator
from hyde.site import Site
from hyde.model import Config, Expando
import yaml

TEST_SITE = File(__file__).parent.parent.child_folder('_test')


class TestGrouper(object):

def setUp(self):
TEST_SITE.make()
TEST_SITE.parent.child_folder(
'sites/test_grouper').copy_contents_to(TEST_SITE)

def tearDown(self):
TEST_SITE.delete()

def test_walk_resources_sorted_with_grouping_one_level(self):
s = Site(TEST_SITE)
cfg = """
plugins:
- hyde.ext.meta.MetaPlugin
- hyde.ext.sorter.SorterPlugin
- hyde.ext.grouper.GrouperPlugin
sorter:
kind:
attr:
- source_file.kind
grouper:
sections:
name: section
description: Sections in the site
sorter: kind
groups:
-
name: start
description: Getting Started
-
name: plugins
description: Plugins


"""
s.config = Config(TEST_SITE, config_dict=yaml.load(cfg))
s.load()
MetaPlugin(s).begin_site()
SorterPlugin(s).begin_site()
GrouperPlugin(s).begin_site()

groups = dict([(g.name, g) for g in s.grouper['sections'].groups])
assert 'start' in groups
assert 'plugins' in groups

assert hasattr(s.content, 'walk_resources_grouped_by_sections')


# assert hasattr(s, 'sectional')
# assert hasattr(s.sectional, 'groups')
# assert len(s.sectional.groups) == 2
#
# groups = dict([(g.name, g) for g in s.sectional.groups])
#
# assert 'start' in groups
# assert 'plugins' in groups
#
# start = groups['start']
# assert hasattr(start, 'resources')
# start_resources = [resource.name for resource in
# start.resources if resource.is_processable]
# assert len(start_resources) == 3
# assert 'installation.html' in start_resources
# assert 'overview.html' in start_resources
# assert 'templating.html' in start_resources
#
# plugin = groups['plugins']
# assert hasattr(plugin, 'resources')
# plugin_resources = [resource.name for resource in
# plugin.resources if resource.is_processable]
# assert len(plugin_resources) == 2
# assert 'plugins.html' in plugin_resources
# assert 'tags.html' in plugin_resources
#
#

+ 1
- 65
hyde/tests/ext/test_sorter.py View File

@@ -269,68 +269,4 @@ class TestSorter(object):
text = target.read_all()
q = PyQuery(text)

assert q('span.latest').text() == 'YayYayYay'

class TestGrouper(object):

def setUp(self):
TEST_SITE.make()
TEST_SITE.parent.child_folder(
'sites/test_grouper').copy_contents_to(TEST_SITE)

def tearDown(self):
TEST_SITE.delete()

def test_walk_resources_sorted_with_grouping_one_level(self):
s = Site(TEST_SITE)
cfg = """
plugins:
- hyde.ext.meta.MetaPlugin
- hyde.ext.sorter.SorterPlugin
sorter:
sectional:
grouping:
name: section
description: Sections in the site
groups:
-
name: start
description: Getting Started
-
name: plugins
description: Plugins
attr:
- source_file.kind
- node.name

"""
s.config = Config(TEST_SITE, config_dict=yaml.load(cfg))
s.load()
MetaPlugin(s).begin_site()
SorterPlugin(s).begin_site()

assert hasattr(s, 'sectional')
assert hasattr(s.sectional, 'groups')
assert len(s.sectional.groups) == 2

groups = dict([(g.name, g) for g in s.sectional.groups])

assert 'start' in groups
assert 'plugins' in groups

start = groups['start']
assert hasattr(start, 'resources')
start_resources = [resource.name for resource in
start.resources if resource.is_processable]
assert len(start_resources) == 3
assert 'installation.html' in start_resources
assert 'overview.html' in start_resources
assert 'templating.html' in start_resources

plugin = groups['plugins']
assert hasattr(plugin, 'resources')
plugin_resources = [resource.name for resource in
plugin.resources if resource.is_processable]
assert len(plugin_resources) == 2
assert 'plugins.html' in plugin_resources
assert 'tags.html' in plugin_resources
assert q('span.latest').text() == 'YayYayYay'

+ 12
- 0
hyde/util.py View File

@@ -83,3 +83,15 @@ class ColorFormatter(logging.Formatter):
return message + RESET_SEQ

logging.ColorFormatter = ColorFormatter


def make_method(method_name, method_):
def method__(self):
return method_(self)
method__.__name__ = method_name
return method__

def add_method(obj, method_name, method_, *args, **kwargs):
from functools import partial
m = make_method(method_name, partial(method_, *args, **kwargs))
setattr(obj, method_name, m)

Loading…
Cancel
Save