diff --git a/hyde/ext/plugins/sorter.py b/hyde/ext/plugins/sorter.py index 4b28df9..ed6b58e 100644 --- a/hyde/ext/plugins/sorter.py +++ b/hyde/ext/plugins/sorter.py @@ -4,11 +4,12 @@ Contains classes and utilities related to sortin resources and nodes in hyde. """ import re +from hyde.model import Expando from hyde.plugin import Plugin from hyde.site import Node, Resource from functools import partial -from itertools import ifilter, izip, tee +from itertools import ifilter, izip, tee, product from operator import attrgetter def pairwalk(iterable): @@ -68,6 +69,29 @@ def add_method(obj, method_name, method_, 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): """ Sorter plugin for hyde. Adds the ability to do @@ -109,6 +133,7 @@ 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) @@ -127,3 +152,30 @@ class SorterPlugin(Plugin): for prev, next in pairwalk(walker()): 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) \ No newline at end of file diff --git a/hyde/generator.py b/hyde/generator.py index f4c8e48..fcf6283 100644 --- a/hyde/generator.py +++ b/hyde/generator.py @@ -31,41 +31,7 @@ class Generator(object): self.template = None Plugin.load_all(site) - class PluginProxy(object): - """ - A proxy class to raise events in registered plugins - """ - - def __init__(self, site): - super(PluginProxy, self).__init__() - self.site = site - - def __getattr__(self, method_name): - if hasattr(Plugin, method_name): - def __call_plugins__(*args): - #logger.debug("Calling plugin method [%s]", method_name) - res = None - if self.site.plugins: - for plugin in self.site.plugins: - if hasattr(plugin, method_name): - #logger.debug( - # "\tCalling plugin [%s]", - # plugin.__class__.__name__) - function = getattr(plugin, method_name) - res = function(*args) - if res: - targs = list(args) - last = None - if len(targs): - last = targs.pop() - targs.append(res if res else last) - args = tuple(targs) - return res - - return __call_plugins__ - raise HydeException( - "Unknown plugin method [%s] called." % method_name) - self.events = PluginProxy(self.site) + self.events = Plugin.get_proxy(self.site) @contextmanager def context_for_resource(self, resource): diff --git a/hyde/layouts/doc/layout/doc.j2 b/hyde/layouts/doc/layout/doc.j2 index 95ecdf0..d6a16cb 100644 --- a/hyde/layouts/doc/layout/doc.j2 +++ b/hyde/layouts/doc/layout/doc.j2 @@ -1,7 +1,7 @@ {% extends "root.j2" %} {% block main -%}
-
+

{{ resource.meta.title }}

{{ resource.meta.subtitle }}

diff --git a/hyde/layouts/doc/layout/root.j2 b/hyde/layouts/doc/layout/root.j2 index 1d2c5c1..63ef6e9 100644 --- a/hyde/layouts/doc/layout/root.j2 +++ b/hyde/layouts/doc/layout/root.j2 @@ -23,7 +23,7 @@ compatibility mode is within the first 1K bytes code.google.com/p/chromium/issues/detail?id=23003 --> - {% block title %}{{ resource.meta.title }} / Hyde Docs{% endblock %} + {% block title %}{{ resource.meta.title }}{% endblock %} diff --git a/hyde/plugin.py b/hyde/plugin.py index 2267f1a..d6735d1 100644 --- a/hyde/plugin.py +++ b/hyde/plugin.py @@ -8,6 +8,44 @@ from hyde import loader from hyde.util import getLoggerWithNullHandler from functools import partial + +logger = getLoggerWithNullHandler('hyde.engine') + +class PluginProxy(object): + """ + A proxy class to raise events in registered plugins + """ + + def __init__(self, site): + super(PluginProxy, self).__init__() + self.site = site + + def __getattr__(self, method_name): + if hasattr(Plugin, method_name): + def __call_plugins__(*args): + # logger.debug("Calling plugin method [%s]", method_name) + res = None + if self.site.plugins: + for plugin in self.site.plugins: + if hasattr(plugin, method_name): + # logger.debug( + # "\tCalling plugin [%s]", + # plugin.__class__.__name__) + function = getattr(plugin, method_name) + res = function(*args) + if res: + targs = list(args) + last = None + if len(targs): + last = targs.pop() + targs.append(res if res else last) + args = tuple(targs) + return res + + return __call_plugins__ + raise HydeException( + "Unknown plugin method [%s] called." % method_name) + class Plugin(object): """ The plugin protocol @@ -132,6 +170,9 @@ class Plugin(object): """ pass + def raise_event(self, event_name): + return getattr(Plugin.proxy, event_name)() + @staticmethod def load_all(site): """ @@ -140,3 +181,7 @@ class Plugin(object): """ site.plugins = [loader.load_python_object(name)(site) for name in site.config.plugins] + + @staticmethod + def get_proxy(site): + return PluginProxy(site) diff --git a/hyde/tests/ext/test_less.py b/hyde/tests/ext/test_less.py index 011187b..329042b 100644 --- a/hyde/tests/ext/test_less.py +++ b/hyde/tests/ext/test_less.py @@ -29,7 +29,7 @@ class TestLess(object): def test_can_execute_less(self): s = Site(TEST_SITE) s.config.plugins = ['hyde.ext.plugins.less.LessCSSPlugin'] - s.config.less = Expando(dict(app='/Users/lvfp/local/bin/lessc')) + s.config.less = Expando(dict(app='~/local/bin/lessc')) source = TEST_SITE.child('content/media/css/site.less') target = File(Folder(s.config.deploy_root_path).child('media/css/site.css')) gen = Generator(s) diff --git a/hyde/tests/ext/test_sorter.py b/hyde/tests/ext/test_sorter.py index 04fb7bb..ac7ab74 100644 --- a/hyde/tests/ext/test_sorter.py +++ b/hyde/tests/ext/test_sorter.py @@ -4,6 +4,7 @@ Use nose `$ pip install nose` `$ nosetests` """ +from hyde.ext.plugins.meta import MetaPlugin from hyde.ext.plugins.sorter import SorterPlugin from hyde.fs import File, Folder from hyde.generator import Generator @@ -136,55 +137,6 @@ class TestSorter(object): File(p).parent.name]))] assert pages == expected_sorted - # def test_walk_resources_sorted_with_grouping_one_level(self): - # s = Site(TEST_SITE) - # cfg = """ - # plugins: - # - hyde.ext.sorter.SorterPlugin - # sorter: - # multi: - # groups: sections.yaml - # attr: - # - source_file.kind - # - node.name - # - # """ - # sections = """ - # group_name: section - # groups: - # - - # name: support - # description: All site support pages - # - - # name: media - # description: Media files - # """ - # s.config = Config(TEST_SITE, config_dict=yaml.load(cfg)) - # s.load() - # SorterPlugin(s).begin_site() - # - # assert hasattr(s.content, 'walk_resources_sorted_by_multi') - # expected = ["content/404.html", - # "content/about.html", - # "content/apple-touch-icon.png", - # "content/blog/2010/december/merry-christmas.html", - # "content/crossdomain.xml", - # "content/favicon.ico", - # "content/robots.txt", - # "content/site.css" - # ] - # - # pages = [page.name for page in s.content.walk_resources_sorted_by_multi()] - # - # expected_sorted = [File(page).name - # for page in - # sorted(expected, - # key=lambda p: tuple( - # [File(p).kind, - # File(p).parent.name]))] - # assert pages == expected_sorted - - def test_walk_resources_sorted_no_default_is_processable(self): s = Site(TEST_SITE) cfg = """ @@ -318,3 +270,67 @@ class TestSorter(object): 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 \ No newline at end of file diff --git a/hyde/tests/sites/test_grouper/content/blog/installation.html b/hyde/tests/sites/test_grouper/content/blog/installation.html index 6fd8880..8d4c7d3 100644 --- a/hyde/tests/sites/test_grouper/content/blog/installation.html +++ b/hyde/tests/sites/test_grouper/content/blog/installation.html @@ -1,8 +1 @@ -{% extends "base.html" %} - -{% block main %} - Hi! - - I am a test template to make sure jinja2 generation works well with hyde. - {{resource.name}} -{% endblock %} \ No newline at end of file +# Installation Guide \ No newline at end of file diff --git a/hyde/tests/sites/test_grouper/content/blog/meta.yaml b/hyde/tests/sites/test_grouper/content/blog/meta.yaml new file mode 100644 index 0000000..a55e02a --- /dev/null +++ b/hyde/tests/sites/test_grouper/content/blog/meta.yaml @@ -0,0 +1,3 @@ +extends: base.html +default_block: main +section: start diff --git a/hyde/tests/sites/test_grouper/content/blog/overview.html b/hyde/tests/sites/test_grouper/content/blog/overview.html index 6fd8880..4bba659 100644 --- a/hyde/tests/sites/test_grouper/content/blog/overview.html +++ b/hyde/tests/sites/test_grouper/content/blog/overview.html @@ -1,8 +1 @@ -{% extends "base.html" %} - -{% block main %} - Hi! - - I am a test template to make sure jinja2 generation works well with hyde. - {{resource.name}} -{% endblock %} \ No newline at end of file +# Overview \ No newline at end of file diff --git a/hyde/tests/sites/test_grouper/content/blog/plugins.html b/hyde/tests/sites/test_grouper/content/blog/plugins.html index 6fd8880..242262e 100644 --- a/hyde/tests/sites/test_grouper/content/blog/plugins.html +++ b/hyde/tests/sites/test_grouper/content/blog/plugins.html @@ -1,8 +1,4 @@ -{% extends "base.html" %} - -{% block main %} - Hi! - - I am a test template to make sure jinja2 generation works well with hyde. - {{resource.name}} -{% endblock %} \ No newline at end of file +=== +section: plugins +=== +# Plugins \ No newline at end of file diff --git a/hyde/tests/sites/test_grouper/content/blog/tags.html b/hyde/tests/sites/test_grouper/content/blog/tags.html index 6fd8880..d0c8e7f 100644 --- a/hyde/tests/sites/test_grouper/content/blog/tags.html +++ b/hyde/tests/sites/test_grouper/content/blog/tags.html @@ -1,8 +1,4 @@ -{% extends "base.html" %} - -{% block main %} - Hi! - - I am a test template to make sure jinja2 generation works well with hyde. - {{resource.name}} -{% endblock %} \ No newline at end of file +=== +section: plugins +=== +# Tags \ No newline at end of file diff --git a/hyde/tests/sites/test_grouper/content/blog/templating.html b/hyde/tests/sites/test_grouper/content/blog/templating.html index 6fd8880..b4ca41c 100644 --- a/hyde/tests/sites/test_grouper/content/blog/templating.html +++ b/hyde/tests/sites/test_grouper/content/blog/templating.html @@ -1,8 +1 @@ -{% extends "base.html" %} - -{% block main %} - Hi! - - I am a test template to make sure jinja2 generation works well with hyde. - {{resource.name}} -{% endblock %} \ No newline at end of file +# Templating \ No newline at end of file diff --git a/hyde/tests/sites/test_grouper/site.yaml b/hyde/tests/sites/test_grouper/site.yaml index 4fc9fce..03c4c9e 100644 --- a/hyde/tests/sites/test_grouper/site.yaml +++ b/hyde/tests/sites/test_grouper/site.yaml @@ -2,6 +2,5 @@ mode: development media_root:: media # Relative path from site root (the directory where this file exists) media_url: /media template: hyde.ext.jinja2 -widgets: -plugins: -aggregators: \ No newline at end of file +meta: + nodemeta: meta.yaml \ No newline at end of file