| @@ -15,10 +15,39 @@ from itertools import ifilter, izip, tee, product | |||||
| from operator import attrgetter | from operator import attrgetter | ||||
| def get_tagger_sort_method(site): | |||||
| config = site.config | |||||
| content = site.content | |||||
| walker = 'walk_resources' | |||||
| sorter = None | |||||
| try: | |||||
| sorter = attrgetter('tagger.sorter')(config) | |||||
| walker = walker + '_sorted_by_%s' % sorter | |||||
| except AttributeError: | |||||
| pass | |||||
| try: | |||||
| walker = getattr(content, walker) | |||||
| except AttributeError: | |||||
| raise self.template.exception_class( | |||||
| "Cannot find the sorter: %s" % sorter) | |||||
| return walker | |||||
| def walk_resources_tagged_with(node, tag): | |||||
| tags = set(tag.split('+')) | |||||
| walker = get_tagger_sort_method(node.site) | |||||
| for resource in walker(): | |||||
| try: | |||||
| taglist = set(attrgetter("meta.tags")(resource)) | |||||
| except AttributeError: | |||||
| continue | |||||
| if tags <= taglist: | |||||
| yield resource | |||||
| class TaggerPlugin(Plugin): | class TaggerPlugin(Plugin): | ||||
| """ | """ | ||||
| Tagger plugin for hyde. Adds the ability to do | |||||
| tag resources and search based on the tags. | |||||
| Tagger plugin for hyde. Adds the ability to do tag resources and search | |||||
| based on the tags. | |||||
| Configuration example | Configuration example | ||||
| --------------------- | --------------------- | ||||
| @@ -27,35 +56,40 @@ class TaggerPlugin(Plugin): | |||||
| kind: | kind: | ||||
| atts: source.kind | atts: source.kind | ||||
| tagger: | tagger: | ||||
| blog: | |||||
| sorter: kind # How to sort the resources in a tag | |||||
| source: blog # The source folder to look for resources | |||||
| target: blog/tags # The target folder to deploy the archives | |||||
| sorter: kind # How to sort the resources in a tag | |||||
| archives: | |||||
| template: tagged_posts.j2 | |||||
| target: tags | |||||
| archive_extension: html | |||||
| """ | """ | ||||
| def __init__(self, site): | def __init__(self, site): | ||||
| super(GrouperPlugin, self).__init__(site) | |||||
| super(TaggerPlugin, self).__init__(site) | |||||
| def begin_site(self): | def begin_site(self): | ||||
| """ | """ | ||||
| Initialize plugin. Add the specified groups to the | |||||
| site context variable. | |||||
| Initialize plugin. Add tag to the site context variable. | |||||
| """ | """ | ||||
| self.logger.debug("Adding tags from metadata") | |||||
| config = self.site.config | 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 | |||||
| prev_att = 'prev_in_%s' % name | |||||
| next_att = 'next_in_%s' % name | |||||
| setattr(Resource, prev_att, None) | |||||
| setattr(Resource, next_att, None) | |||||
| self.site.grouper[name] = Group(grouping) | |||||
| walker = Group.walk_resources( | |||||
| self.site.content, self.site.grouper[name]) | |||||
| for prev, next in pairwalk(walker): | |||||
| setattr(next, prev_att, prev) | |||||
| setattr(prev, next_att, next) | |||||
| content = self.site.content | |||||
| tags = {} | |||||
| add_method(Node, | |||||
| 'walk_resources_tagged_with', walk_resources_tagged_with) | |||||
| walker = get_tagger_sort_method(self.site) | |||||
| for resource in walker(): | |||||
| try: | |||||
| taglist = attrgetter("meta.tags")(resource) | |||||
| except AttributeError: | |||||
| continue | |||||
| for tag in taglist: | |||||
| if not tag in tags: | |||||
| tags[tag] = [resource] | |||||
| add_method(Node, | |||||
| 'walk_resources_tagged_with_%s' % tag, | |||||
| walk_resources_tagged_with, | |||||
| tag=tag) | |||||
| else: | |||||
| tags[tag].append(resource) | |||||
| self.site.tagger = Expando(dict(tags=tags)) | |||||
| @@ -49,7 +49,6 @@ depends: index.html | |||||
| gen.template.env.filters['dateformat'] = dateformat | gen.template.env.filters['dateformat'] = dateformat | ||||
| gen.generate_resource_at_path(inc.name) | gen.generate_resource_at_path(inc.name) | ||||
| res = s.content.resource_from_relative_path(inc.name) | res = s.content.resource_from_relative_path(inc.name) | ||||
| print res.__dict__ | |||||
| assert len(res.depends) == 1 | assert len(res.depends) == 1 | ||||
| assert 'index.html' in res.depends | assert 'index.html' in res.depends | ||||
| deps = list(gen.get_dependencies(res)) | deps = list(gen.get_dependencies(res)) | ||||
| @@ -140,7 +140,6 @@ class TestGrouperSingleLevel(object): | |||||
| res = self.s.content.resource_from_relative_path('blog/' + page) | res = self.s.content.resource_from_relative_path('blog/' + page) | ||||
| assert hasattr(res, 'section_group') | assert hasattr(res, 'section_group') | ||||
| res_group = getattr(res, 'section_group') | res_group = getattr(res, 'section_group') | ||||
| print "%s, %s=%s" % (page, group.name, res_group.name) | |||||
| assert res_group == group | assert res_group == group | ||||
| def test_resource_belongs_to(self): | def test_resource_belongs_to(self): | ||||
| @@ -30,35 +30,41 @@ class TestTagger(object): | |||||
| def test_tagger_walker(self): | def test_tagger_walker(self): | ||||
| gen = Generator(self.s) | gen = Generator(self.s) | ||||
| gen.load_site_if_needed() | gen.load_site_if_needed() | ||||
| gen.generate_all() | |||||
| tags = self.s.taggger['blog'].tags | |||||
| assert hasattr(self.s, 'tagger') | |||||
| assert hasattr(self.s.tagger, 'tags') | |||||
| assert self.s.tagger.tags | |||||
| tags = self.s.tagger.tags.to_dict() | |||||
| assert tags.length == 5 | |||||
| assert len(tags) == 5 | |||||
| for tag in ['sad', 'happy', 'angry', 'thoughts', 'events']: | for tag in ['sad', 'happy', 'angry', 'thoughts', 'events']: | ||||
| assert tag in tags | assert tag in tags | ||||
| # sad_posts = [post.name for post in | |||||
| # self.s.content.walk_resources_tagged_with('sad')] | |||||
| # assert sad_posts.length == 2 | |||||
| # assert "sad-post.html" in sad_posts | |||||
| # assert "another-sad-post.html" in sad_posts | |||||
| # | |||||
| # happy_posts = [post.name for post in | |||||
| # self.s.content.walk_resources_tagged_with('happy')] | |||||
| # assert happy_posts.length == 1 | |||||
| # assert "happy-post.html" in happy_posts | |||||
| # | |||||
| # angry_posts = [post.name for post in | |||||
| # self.s.content.walk_resources_tagged_with('angry')] | |||||
| # assert angry_posts.length == 1 | |||||
| # assert "angry-post.html" in angry_posts | |||||
| # sad_thought_posts = [post.name for post in | |||||
| # self.s.content.walk_resources_tagged_with('sad')] | |||||
| # assert sad_posts.length == 2 | |||||
| # assert "sad-post.html" in sad_posts | |||||
| # assert "another-sad-post.html" in sad_posts | |||||
| sad_posts = [post.name for post in tags['sad']] | |||||
| assert len(sad_posts) == 2 | |||||
| assert "sad-post.html" in sad_posts | |||||
| assert "another-sad-post.html" in sad_posts | |||||
| sad_posts == [post.name for post in | |||||
| self.s.content.walk_resources_tagged_with('sad')] | |||||
| happy_posts = [post.name for post in | |||||
| self.s.content.walk_resources_tagged_with('happy')] | |||||
| assert len(happy_posts) == 1 | |||||
| assert "happy-post.html" in happy_posts | |||||
| angry_posts = [post.name for post in | |||||
| self.s.content.walk_resources_tagged_with('angry')] | |||||
| assert len(angry_posts) == 1 | |||||
| assert "angry-post.html" in angry_posts | |||||
| sad_thought_posts = [post.name for post in | |||||
| self.s.content.walk_resources_tagged_with('sad+thoughts')] | |||||
| assert len(sad_thought_posts) == 1 | |||||
| assert "sad-post.html" in sad_thought_posts | |||||
| @@ -20,11 +20,10 @@ sorter: | |||||
| reverse: true | reverse: true | ||||
| filters: | filters: | ||||
| source.kind: html | source.kind: html | ||||
| meta.listable: true | |||||
| tagger: | tagger: | ||||
| blog: | |||||
| sorter: time | |||||
| archives: | |||||
| sorter: time | |||||
| archives: | |||||
| blog: | |||||
| template: tagged_posts.j2 | template: tagged_posts.j2 | ||||
| source: blog | source: blog | ||||
| target: blog/tags | target: blog/tags | ||||
| @@ -94,8 +94,8 @@ logging.ColorFormatter = ColorFormatter | |||||
| def make_method(method_name, method_): | def make_method(method_name, method_): | ||||
| def method__(self): | |||||
| return method_(self) | |||||
| def method__(*args, **kwargs): | |||||
| return method_(*args, **kwargs) | |||||
| method__.__name__ = method_name | method__.__name__ = method_name | ||||
| return method__ | return method__ | ||||