@@ -5,6 +5,8 @@ Contains classes and utilities related to meta data in hyde. | |||||
import re | import re | ||||
from operator import attrgetter | from operator import attrgetter | ||||
from itertools import ifilter | |||||
from functools import partial | |||||
from hyde.model import Expando | from hyde.model import Expando | ||||
from hyde.plugin import Plugin | from hyde.plugin import Plugin | ||||
from hyde.fs import File, Folder | from hyde.fs import File, Folder | ||||
@@ -394,3 +396,120 @@ extends: false | |||||
archive_file.write(text.strip()) | archive_file.write(text.strip()) | ||||
self.site.content.add_resource(archive_file) | self.site.content.add_resource(archive_file) | ||||
def filter_method(item, settings=None): | |||||
""" | |||||
Returns true if all the filters in the | |||||
given settings evaluate to True. | |||||
""" | |||||
all_match = True | |||||
default_filters = {} | |||||
filters = {} | |||||
if hasattr(settings, 'filters'): | |||||
filters.update(default_filters) | |||||
filters.update(settings.filters.__dict__) | |||||
for field, value in filters.items(): | |||||
try: | |||||
res = attrgetter(field)(item) | |||||
except: | |||||
res = None | |||||
if res != value: | |||||
all_match = False | |||||
break | |||||
return all_match | |||||
def attributes_checker(item, attributes=None): | |||||
""" | |||||
Checks if the given list of attributes exist. | |||||
""" | |||||
try: | |||||
x = attrgetter(*attributes)(item) | |||||
return True | |||||
except AttributeError: | |||||
return False | |||||
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 | |||||
reverse = False | |||||
if settings and hasattr(settings, 'reverse'): | |||||
reverse = settings.reverse | |||||
if not isinstance(attr, list): | |||||
attr = [attr] | |||||
filter_ = partial(filter_method, settings=settings) | |||||
excluder_ = partial(attributes_checker, attributes=attr) | |||||
resources = ifilter(lambda x: excluder_(x) and filter_(x), | |||||
node.walk_resources()) | |||||
return sorted(resources, | |||||
key=attrgetter(*attr), | |||||
reverse=reverse) | |||||
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(): | |||||
sort_method_name = 'walk_resources_sorted_by_%s' % name | |||||
self.logger.debug("Adding sort methods for [%s]" % name) | |||||
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) | |||||
prev_att = 'prev_by_%s' % name | |||||
next_att = 'next_by_%s' % name | |||||
setattr(Resource, prev_att, None) | |||||
setattr(Resource, next_att, None) | |||||
walker = getattr(self.site.content, | |||||
sort_method_name, | |||||
self.site.content.walk_resources) | |||||
for prev, next in pairwalk(walker()): | |||||
setattr(prev, next_att, next) | |||||
setattr(next, prev_att, prev) | |||||
@@ -5,7 +5,7 @@ base_url: / # The base url for autogenerated links. | |||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.meta.AutoExtendPlugin | - hyde.ext.plugins.meta.AutoExtendPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.meta.TaggerPlugin | - hyde.ext.plugins.meta.TaggerPlugin | ||||
- hyde.ext.plugins.text.SyntextPlugin | - hyde.ext.plugins.text.SyntextPlugin | ||||
- hyde.ext.plugins.text.TextlinksPlugin | - hyde.ext.plugins.text.TextlinksPlugin | ||||
@@ -12,7 +12,7 @@ plugins: | |||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.meta.AutoExtendPlugin | - hyde.ext.plugins.meta.AutoExtendPlugin | ||||
# Plugins needed for the advances section. | # Plugins needed for the advances section. | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.grouper.GrouperPlugin | - hyde.ext.plugins.grouper.GrouperPlugin | ||||
- hyde.ext.plugins.meta.TaggerPlugin | - hyde.ext.plugins.meta.TaggerPlugin | ||||
context: | context: | ||||
@@ -5,7 +5,7 @@ Use nose | |||||
`$ nosetests` | `$ nosetests` | ||||
""" | """ | ||||
from hyde.ext.plugins.meta import MetaPlugin | from hyde.ext.plugins.meta import MetaPlugin | ||||
from hyde.ext.plugins.sorter import SorterPlugin | |||||
from hyde.ext.plugins.meta import SorterPlugin | |||||
from hyde.ext.plugins.grouper import GrouperPlugin | from hyde.ext.plugins.grouper import GrouperPlugin | ||||
from hyde.generator import Generator | from hyde.generator import Generator | ||||
from hyde.site import Site | from hyde.site import Site | ||||
@@ -30,7 +30,7 @@ class TestGrouperSingleLevel(object): | |||||
nodemeta: meta.yaml | nodemeta: meta.yaml | ||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.grouper.GrouperPlugin | - hyde.ext.plugins.grouper.GrouperPlugin | ||||
sorter: | sorter: | ||||
kind: | kind: | ||||
@@ -236,7 +236,7 @@ class TestGrouperSingleLevel(object): | |||||
nodemeta: meta.yaml | nodemeta: meta.yaml | ||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.grouper.GrouperPlugin | - hyde.ext.plugins.grouper.GrouperPlugin | ||||
sorter: | sorter: | ||||
kind: | kind: | ||||
@@ -321,4 +321,4 @@ class TestGrouperSingleLevel(object): | |||||
gen.load_site_if_needed() | gen.load_site_if_needed() | ||||
gen.load_template_if_needed() | gen.load_template_if_needed() | ||||
out = gen.template.render(text, {'site':self.s}) | out = gen.template.render(text, {'site':self.s}) | ||||
assert_html_equals(out, expected) | |||||
assert_html_equals(out, expected) |
@@ -5,7 +5,12 @@ Use nose | |||||
`$ nosetests` | `$ nosetests` | ||||
""" | """ | ||||
from hyde.ext.plugins.meta import MetaPlugin | from hyde.ext.plugins.meta import MetaPlugin | ||||
<<<<<<< HEAD | |||||
from hyde.ext.plugins.sorter import SorterPlugin | from hyde.ext.plugins.sorter import SorterPlugin | ||||
======= | |||||
from hyde.ext.plugins.meta import SorterPlugin | |||||
from hyde.fs import File, Folder | |||||
>>>>>>> Move the sorter plugin into the meta module. | |||||
from hyde.generator import Generator | from hyde.generator import Generator | ||||
from hyde.site import Site | from hyde.site import Site | ||||
from hyde.model import Config, Expando | from hyde.model import Config, Expando | ||||
@@ -30,7 +35,7 @@ class TestSorter(object): | |||||
def test_walk_resources_sorted(self): | def test_walk_resources_sorted(self): | ||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
s.load() | s.load() | ||||
s.config.plugins = ['hyde.ext.sorter.SorterPlugin'] | |||||
s.config.plugins = ['hyde.ext.meta.SorterPlugin'] | |||||
s.config.sorter = Expando(dict(kind=dict(attr=['source_file.kind', 'name']))) | s.config.sorter = Expando(dict(kind=dict(attr=['source_file.kind', 'name']))) | ||||
SorterPlugin(s).begin_site() | SorterPlugin(s).begin_site() | ||||
@@ -54,7 +59,7 @@ class TestSorter(object): | |||||
def test_walk_resources_sorted_reverse(self): | def test_walk_resources_sorted_reverse(self): | ||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
s.load() | s.load() | ||||
s.config.plugins = ['hyde.ext.sorter.SorterPlugin'] | |||||
s.config.plugins = ['hyde.ext.meta.SorterPlugin'] | |||||
s.config.sorter = Expando(dict(kind=dict(attr=['source_file.kind', 'name'], reverse=True))) | s.config.sorter = Expando(dict(kind=dict(attr=['source_file.kind', 'name'], reverse=True))) | ||||
SorterPlugin(s).begin_site() | SorterPlugin(s).begin_site() | ||||
@@ -80,7 +85,7 @@ class TestSorter(object): | |||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
cfg = """ | cfg = """ | ||||
plugins: | plugins: | ||||
- hyde.ext.sorter.SorterPlugin | |||||
- hyde.ext.meta.SorterPlugin | |||||
sorter: | sorter: | ||||
kind2: | kind2: | ||||
filters: | filters: | ||||
@@ -104,7 +109,7 @@ class TestSorter(object): | |||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
cfg = """ | cfg = """ | ||||
plugins: | plugins: | ||||
- hyde.ext.sorter.SorterPlugin | |||||
- hyde.ext.meta.SorterPlugin | |||||
sorter: | sorter: | ||||
multi: | multi: | ||||
attr: | attr: | ||||
@@ -142,7 +147,7 @@ class TestSorter(object): | |||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
cfg = """ | cfg = """ | ||||
plugins: | plugins: | ||||
- hyde.ext.sorter.SorterPlugin | |||||
- hyde.ext.meta.SorterPlugin | |||||
sorter: | sorter: | ||||
kind2: | kind2: | ||||
filters: | filters: | ||||
@@ -167,7 +172,7 @@ class TestSorter(object): | |||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
cfg = """ | cfg = """ | ||||
plugins: | plugins: | ||||
- hyde.ext.sorter.SorterPlugin | |||||
- hyde.ext.meta.SorterPlugin | |||||
sorter: | sorter: | ||||
kind2: | kind2: | ||||
filters: | filters: | ||||
@@ -203,7 +208,7 @@ class TestSorter(object): | |||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
cfg = """ | cfg = """ | ||||
plugins: | plugins: | ||||
- hyde.ext.sorter.SorterPlugin | |||||
- hyde.ext.meta.SorterPlugin | |||||
sorter: | sorter: | ||||
folder_name: | folder_name: | ||||
attr: | attr: | ||||
@@ -244,7 +249,7 @@ class TestSorter(object): | |||||
title: NahNahNah | title: NahNahNah | ||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
sorter: | sorter: | ||||
time: | time: | ||||
attr: meta.time | attr: meta.time | ||||
@@ -290,7 +295,7 @@ class TestSorterMeta(object): | |||||
def test_attribute_checker_no_meta(self): | def test_attribute_checker_no_meta(self): | ||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
s.load() | s.load() | ||||
from hyde.ext.plugins.sorter import attributes_checker | |||||
from hyde.ext.plugins.meta import attributes_checker | |||||
for r in s.content.walk_resources(): | for r in s.content.walk_resources(): | ||||
assert not attributes_checker(r, ['meta.index']) | assert not attributes_checker(r, ['meta.index']) | ||||
@@ -298,7 +303,7 @@ class TestSorterMeta(object): | |||||
s = Site(TEST_SITE) | s = Site(TEST_SITE) | ||||
s.load() | s.load() | ||||
MetaPlugin(s).begin_site() | MetaPlugin(s).begin_site() | ||||
from hyde.ext.plugins.sorter import attributes_checker | |||||
from hyde.ext.plugins.meta import attributes_checker | |||||
have_index = ["angry-post.html", | have_index = ["angry-post.html", | ||||
"another-sad-post.html", | "another-sad-post.html", | ||||
"happy-post.html"] | "happy-post.html"] | ||||
@@ -4,7 +4,7 @@ media_url: /media # URL where the media files are served from. | |||||
base_url: / # The base url for autogenerated links. | base_url: / # The base url for autogenerated links. | ||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.structure.PaginatorPlugin | - hyde.ext.plugins.structure.PaginatorPlugin | ||||
meta: | meta: | ||||
nodemeta: meta.yaml | nodemeta: meta.yaml | ||||
@@ -5,7 +5,7 @@ base_url: / # The base url for autogenerated links. | |||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.meta.AutoExtendPlugin | - hyde.ext.plugins.meta.AutoExtendPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.text.TextlinksPlugin | - hyde.ext.plugins.text.TextlinksPlugin | ||||
meta: | meta: | ||||
nodemeta: meta.yaml | nodemeta: meta.yaml | ||||
@@ -5,7 +5,7 @@ base_url: / # The base url for autogenerated links. | |||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.meta.AutoExtendPlugin | - hyde.ext.plugins.meta.AutoExtendPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.meta.TaggerPlugin | - hyde.ext.plugins.meta.TaggerPlugin | ||||
- hyde.ext.plugins.text.TextlinksPlugin | - hyde.ext.plugins.text.TextlinksPlugin | ||||
meta: | meta: | ||||
@@ -5,7 +5,7 @@ base_url: / # The base url for autogenerated links. | |||||
plugins: | plugins: | ||||
- hyde.ext.plugins.meta.MetaPlugin | - hyde.ext.plugins.meta.MetaPlugin | ||||
- hyde.ext.plugins.meta.AutoExtendPlugin | - hyde.ext.plugins.meta.AutoExtendPlugin | ||||
- hyde.ext.plugins.sorter.SorterPlugin | |||||
- hyde.ext.plugins.meta.SorterPlugin | |||||
- hyde.ext.plugins.meta.TaggerPlugin | - hyde.ext.plugins.meta.TaggerPlugin | ||||
- hyde.ext.plugins.text.SyntextPlugin | - hyde.ext.plugins.text.SyntextPlugin | ||||
- hyde.ext.plugins.text.TextlinksPlugin | - hyde.ext.plugins.text.TextlinksPlugin | ||||