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