| @@ -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 | ||||