Browse Source

added sorter plugin

main
Lakshmi Vyasarajan 14 years ago
parent
commit
27bb87d233
4 changed files with 222 additions and 67 deletions
  1. +106
    -0
      hyde/ext/plugins/sorter.py
  2. +0
    -29
      hyde/site.py
  3. +116
    -0
      hyde/tests/ext/test_sorter.py
  4. +0
    -38
      hyde/tests/test_site.py

+ 106
- 0
hyde/ext/plugins/sorter.py View File

@@ -0,0 +1,106 @@
"""
Contains classes and utilities related to sortin
resources and nodes in hyde.
"""
import re
from hyde.plugin import Plugin
from hyde.site import Node, Resource

from functools import partial
from itertools import ifilter
from operator import attrgetter

import logging
from logging import NullHandler
logger = logging.getLogger('hyde.engine')
logger.addHandler(NullHandler())


def filter_method(item, settings=None):
"""
Returns true if all the filters in the
given settings evaluate to True.
"""

all_match = True
if settings and hasattr(settings, 'filters'):
filters = settings.filters
for field, value in filters.__dict__.items():
try:
res = attrgetter(field)(item)
except:
res = None
if res != value:
all_match = False
break
return all_match

def sort_method(node, settings=None):
"""
Sorts the resources in the given node based on the
given settings.
"""
attr = 'name'
if settings and hasattr(settings, 'attr') and settings.attr:
attr = settings.attr
filter_ = partial(filter_method, settings=settings)
resources = ifilter(filter_, node.walk_resources())
return sorted(resources, key=attrgetter(attr))

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 SorterPlugin(Plugin):
"""
Sorter plugin for hyde. Adds the ability to do
sophisticated sorting by expanding the site objects
to support prebuilt sorting methods. These methods
can be used in the templates directly.

Configuration example
---------------------
#yaml

sorter:
kind:
# Sorts by this attribute name
# Uses `attrgetter` on the resource object
attr: source_file.kind

# The filters to be used before sorting
# This can be used to remove all the items
# that do not apply. For example,
# filtering non html content
filters:
source_file.kind: html
is_processable: True
meta.is_listable: True
"""

def __init__(self, site):
super(SorterPlugin, self).__init__(site)

def begin_site(self):
"""
Initialize plugin. Add a sort and match method
for every configuration mentioned in site settings
"""

config = self.site.config
if not hasattr(config, 'sorter'):
return

for name, settings in config.sorter.__dict__.items():
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)
match_method_name = 'is_%s' % name
add_method(Resource, match_method_name, filter_method, settings)

+ 0
- 29
hyde/site.py View File

@@ -169,35 +169,6 @@ class Node(Processable):
for resource in node.resources: for resource in node.resources:
yield resource yield resource


def walk_resources_sorted(self, attr='name', reverse=False, default=None):
"""
Walks the resources in this hierarchy sorted by
the given key.
"""
from operator import attrgetter

def safe_attrgetter(*items):
f = attrgetter(*items)

def wrapper(obj):
res = None
try:
res = f(obj)
except:
logger.error("Cannot get the requested items[%s]"
" from the object [%s]" %
(items, obj))
res = default
return res

return wrapper

sorted_resources = sorted(self.walk_resources(),
key=safe_attrgetter(attr),
reverse=reverse)
for resource in sorted_resources:
yield resource

@property @property
def relative_path(self): def relative_path(self):
""" """


+ 116
- 0
hyde/tests/ext/test_sorter.py View File

@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
"""
Use nose
`$ pip install nose`
`$ nosetests`
"""
from hyde.ext.plugins.sorter import SorterPlugin
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 TestMeta(object):

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

def tearDown(self):
TEST_SITE.delete()

def test_walk_resources_sorted(self):
s = Site(TEST_SITE)
s.load()
s.config.plugins = ['hyde.ext.sorter.SorterPlugin']
s.config.sorter = Expando(dict(kind=dict(attr='source_file.kind')))

SorterPlugin(s).begin_site()

assert hasattr(s.content, 'walk_resources_sorted_by_kind')
expected = ["404.html",
"about.html",
"apple-touch-icon.png",
"merry-christmas.html",
"crossdomain.xml",
"favicon.ico",
"robots.txt",
"site.css"
]

pages = [page.name for page in
s.content.walk_resources_sorted_by_kind()]


assert pages == sorted(expected, key=lambda f: File(f).kind)

def test_walk_resources_sorted_with_filters(self):
s = Site(TEST_SITE)
cfg = """
plugins:
- hyde.ext.sorter.SorterPlugin
sorter:
kind2:
filters:
source_file.kind: html
"""
s.config = Config(TEST_SITE, config_dict=yaml.load(cfg))
s.load()
SorterPlugin(s).begin_site()

assert hasattr(s.content, 'walk_resources_sorted_by_kind2')
expected = ["404.html",
"about.html",
"merry-christmas.html"
]

pages = [page.name for page in s.content.walk_resources_sorted_by_kind2()]

assert pages == sorted(expected)

def test_walk_resources_sorted_using_generator(self):
s = Site(TEST_SITE)
cfg = """
meta:
time: !!timestamp 2010-10-23
title: NahNahNah
plugins:
- hyde.ext.plugins.meta.MetaPlugin
- hyde.ext.plugins.sorter.SorterPlugin
sorter:
time:
attr: meta.time
filters:
source_file.kind: html
"""
s.config = Config(TEST_SITE, config_dict=yaml.load(cfg))
text = """
---
time: !!timestamp 2010-12-31
title: YayYayYay
---
{% extends "base.html" %}

{% block main %}
{% set latest = site.content.walk_resources_sorted_by_time()|reverse|first %}
<span class="latest">{{ latest.meta.title }}</span>
{% endblock %}
"""

about2 = File(TEST_SITE.child('content/about2.html'))
about2.write(text)
gen = Generator(s)
gen.generate_all()

from pyquery import PyQuery
target = File(Folder(s.config.deploy_root_path).child('about2.html'))
text = target.read_all()
q = PyQuery(text)

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


+ 0
- 38
hyde/tests/test_site.py View File

@@ -103,44 +103,6 @@ def test_walk_resources():
expected.sort() expected.sort()
assert pages == expected assert pages == expected


def test_walk_resources_sorted():
s = Site(TEST_SITE_ROOT)
s.load()
pages = [page.name for page in s.content.walk_resources_sorted(attr='name')]
expected = ["404.html",
"about.html",
"apple-touch-icon.png",
"merry-christmas.html",
"crossdomain.xml",
"favicon.ico",
"robots.txt",
"site.css"
]
assert pages == sorted(expected)
pages = [page.name for page in
s.content.walk_resources_sorted(attr='name', reverse=True)]
assert pages == sorted(expected, reverse=True)
pages = [page.name for page in
s.content.walk_resources_sorted(attr='source_file.kind')]
assert pages == sorted(expected, key=lambda f: File(f).kind)

from datetime import datetime, timedelta

d = {}
t = datetime.now()
for name in expected:
d[name] = t
t = t - timedelta(days=1)

for page in s.content.walk_resources():
page.meta = Expando(dict(time=d[page.name]))

pages = [page.name for page in
s.content.walk_resources_sorted(attr='meta.time', reverse=True)]
assert pages == expected



def test_contains_resource(): def test_contains_resource():
s = Site(TEST_SITE_ROOT) s = Site(TEST_SITE_ROOT)
s.load() s.load()


Loading…
Cancel
Save