Browse Source

Added hierarchical metadata plugin

main
Lakshmi Vyasarajan 14 years ago
parent
commit
713a00d909
6 changed files with 245 additions and 13 deletions
  1. +45
    -6
      hyde/ext/plugins/meta.py
  2. +6
    -0
      hyde/model.py
  3. +18
    -0
      hyde/site.py
  4. +150
    -7
      hyde/tests/ext/test_meta.py
  5. +12
    -0
      hyde/tests/test_model.py
  6. +14
    -0
      hyde/tests/test_site.py

+ 45
- 6
hyde/ext/plugins/meta.py View File

@@ -16,9 +16,23 @@ class Metadata(Expando):
"""
Container class for yaml meta data.
"""
def __init__(self, text):
super(Metadata, self).__init__(yaml.load(text))

def __init__(self, data, parent=None):

super(Metadata, self).__init__({})
if parent:
self.update(parent.__dict__)
if data:
self.update(data)

def update(self, data):
"""
Updates the metadata with new stuff
"""
if isinstance(data, dict):
super(Metadata, self).update(data)
else:
super(Metadata, self).update(yaml.load(data))


class MetaPlugin(Plugin):
@@ -38,21 +52,46 @@ class MetaPlugin(Plugin):
def __init__(self, site):
super(MetaPlugin, self).__init__(site)

def begin_site(self):
metadata = self.site.config.meta if hasattr(self.site.config, 'meta') else {}
self.site.meta = Metadata(metadata)

def begin_node(self, node):
"""
Look for nodemeta.yaml. Load and assign it to the node.
"""
nodemeta = node.get_resource('nodemeta.yaml')
parent_meta = node.parent.meta if node.parent else self.site.meta
if nodemeta:
nodemeta.is_processable = False
metadata = nodemeta.source_file.read_all()
if hasattr(node, 'meta') and node.meta:
node.meta.update(metadata)
else:
node.meta = Metadata(metadata, parent=parent_meta)
else:
node.meta = Metadata({}, parent=parent_meta)

def begin_text_resource(self, resource, text):
"""
Load meta data by looking for the marker.
Once loaded, remove the meta area from the text.
"""

logger.info("Trying to load metadata from resource [%s]" % resource)
# re from spjwebster's lanyon
yaml_finder = re.compile( r"^\s*---\s*\n((?:.|\n)+?)\n---\s*\n", re.MULTILINE)
yaml_finder = re.compile(
r"^\s*---\s*\n((?:.|\n)+?)\n\s*---\s*\n",
re.MULTILINE)
match = re.match(yaml_finder, text)
if not match:
logger.info("No metadata found in resource [%s]" % resource)
return text
text = text[match.end():]
resource.meta = Metadata(match.group(1))
data = match.group(1)
if not hasattr(resource, 'meta') or not resource.meta:
resource.meta = Metadata(data, resource.node.meta)
else:
resource.meta.update(data)
logger.info("Successfully loaded metadata from resource [%s]"
% resource)
return text
return text

+ 6
- 0
hyde/model.py View File

@@ -11,6 +11,12 @@ class Expando(object):

def __init__(self, d):
super(Expando, self).__init__()
self.update(d)

def update(self, d):
"""
Updates the expando with a new dictionary
"""
d = d or {}
for key, value in d.items():
setattr(self, key, Expando.transform(value))


+ 18
- 0
hyde/site.py View File

@@ -85,6 +85,24 @@ class Node(Processable):
self.child_nodes = []
self.resources = []

def contains_resource(self, resource_name):
"""
Returns True if the given resource name exists as a file
in this node's source folder.
"""

return File(self.source_folder.child(resource_name)).exists

def get_resource(self, resource_name):
"""
Gets the resource if the given resource name exists as a file
in this node's source folder.
"""

if self.contains_resource(resource_name):
return self.root.resource_from_path(self.source_folder.child(resource_name))
return None

def add_child_node(self, folder):
"""
Creates a new child node and adds it to the list of child nodes.


+ 150
- 7
hyde/tests/ext/test_meta.py View File

@@ -20,18 +20,16 @@ class TestMeta(object):

def setUp(self):
TEST_SITE.make()
TEST_SITE.parent.child_folder('sites/test_jinja').copy_contents_to(TEST_SITE)
TEST_SITE.parent.child_folder(
'sites/test_jinja').copy_contents_to(TEST_SITE)

def tearDown(self):
TEST_SITE.delete()


def test_can_load_front_matter(self):
d = {
'title': 'A nice title',
d = {'title': 'A nice title',
'author': 'Lakshmi Vyas',
'twitter': 'lakshmivyas'
}
'twitter': 'lakshmivyas'}
text = """
---
title: %(title)s
@@ -68,4 +66,149 @@ twitter: %(twitter)s
text = target.read_all()
q = PyQuery(text)
for k, v in d.items():
assert v in q("span." + k).text()
assert v in q("span." + k).text()

def test_can_load_from_node_meta(self):
d = {'title': 'A nice title',
'author': 'Lakshmi Vyas',
'twitter': 'lakshmivyas'}
text = """
---
title: Even nicer title
---
{%% extends "base.html" %%}

{%% block main %%}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
<span class="title">{{resource.meta.title}}</span>
<span class="author">{{resource.meta.author}}</span>
<span class="twitter">{{resource.meta.twitter}}</span>
{%% endblock %%}
"""
about2 = File(TEST_SITE.child('content/about2.html'))
about2.write(text % d)
meta = File(TEST_SITE.child('content/nodemeta.yaml'))
meta.write(yaml.dump(d))
s = Site(TEST_SITE)
s.config.plugins = ['hyde.ext.plugins.meta.MetaPlugin']
gen = Generator(s)
gen.generate_all()
res = s.content.resource_from_path(about2.path)
assert hasattr(res, 'meta')
assert hasattr(res.meta, 'title')
assert hasattr(res.meta, 'author')
assert hasattr(res.meta, 'twitter')
assert res.meta.title == "Even nicer title"
assert res.meta.author == "Lakshmi Vyas"
assert res.meta.twitter == "lakshmivyas"
target = File(Folder(s.config.deploy_root_path).child('about2.html'))
text = target.read_all()
q = PyQuery(text)
for k, v in d.items():
if not k == 'title':
assert v in q("span." + k).text()
assert q("span.title").text() == "Even nicer title"

def test_can_load_from_site_meta(self):
d = {'title': 'A nice title',
'author': 'Lakshmi Vyas'}
text = """
---
title: Even nicer title
---
{%% extends "base.html" %%}

{%% block main %%}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
<span class="title">{{resource.meta.title}}</span>
<span class="author">{{resource.meta.author}}</span>
<span class="twitter">{{resource.meta.twitter}}</span>
{%% endblock %%}
"""
about2 = File(TEST_SITE.child('content/about2.html'))
about2.write(text % d)
meta = File(TEST_SITE.child('content/nodemeta.yaml'))
meta.write(yaml.dump(d))
s = Site(TEST_SITE)
s.config.plugins = ['hyde.ext.plugins.meta.MetaPlugin']
s.config.meta = {
'author': 'Lakshmi',
'twitter': 'lakshmivyas'
}
gen = Generator(s)
gen.generate_all()
res = s.content.resource_from_path(about2.path)
assert hasattr(res, 'meta')
assert hasattr(res.meta, 'title')
assert hasattr(res.meta, 'author')
assert hasattr(res.meta, 'twitter')
assert res.meta.title == "Even nicer title"
assert res.meta.author == "Lakshmi Vyas"
assert res.meta.twitter == "lakshmivyas"
target = File(Folder(s.config.deploy_root_path).child('about2.html'))
text = target.read_all()
q = PyQuery(text)
for k, v in d.items():
if not k == 'title':
assert v in q("span." + k).text()
assert q("span.title").text() == "Even nicer title"


def test_multiple_levels(self):

page_d = {'title': 'An even nicer title'}

blog_d = {'author': 'Lakshmi'}

content_d = {'title': 'A nice title',
'author': 'Lakshmi Vyas'}

site_d = {'author': 'Lakshmi',
'twitter': 'lakshmivyas'}
text = """
---
title: %(title)s
---
{%% extends "base.html" %%}

{%% block main %%}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
<span class="title">{{resource.meta.title}}</span>
<span class="author">{{resource.meta.author}}</span>
<span class="twitter">{{resource.meta.twitter}}</span>
{%% endblock %%}
"""
about2 = File(TEST_SITE.child('content/blog/about2.html'))
about2.write(text % page_d)
content_meta = File(TEST_SITE.child('content/nodemeta.yaml'))
content_meta.write(yaml.dump(content_d))
content_meta = File(TEST_SITE.child('content/blog/nodemeta.yaml'))
content_meta.write(yaml.dump(blog_d))
s = Site(TEST_SITE)
s.config.plugins = ['hyde.ext.plugins.meta.MetaPlugin']
s.config.meta = site_d
gen = Generator(s)
gen.generate_all()
expected = {}

expected.update(site_d)
expected.update(content_d)
expected.update(blog_d)
expected.update(page_d)

res = s.content.resource_from_path(about2.path)
assert hasattr(res, 'meta')
for k, v in expected.items():
assert hasattr(res.meta, k)
assert getattr(res.meta, k) == v
target = File(Folder(s.config.deploy_root_path).child('blog/about2.html'))
text = target.read_all()
q = PyQuery(text)
for k, v in expected.items():
assert v in q("span." + k).text()

+ 12
- 0
hyde/tests/test_model.py View File

@@ -26,6 +26,18 @@ def test_expando_three_levels():
assert x.b.c == d['b']['c']
assert x.b.d.e == d['b']['d']['e']

def test_expando_update():
d1 = {"a": 123, "b": "abc"}
x = Expando(d1)
assert x.a == d1['a']
assert x.b == d1['b']
d = {"b": {"c": 456, "d": {"e": "abc"}}, "f": "lmn"}
x.update(d)
assert x.a == d1['a']
assert x.b.c == d['b']['c']
assert x.b.d.e == d['b']['d']['e']
assert x.f == d["f"]

TEST_SITE_ROOT = File(__file__).parent.child_folder('sites/test_jinja')
import yaml
class TestConfig(object):


+ 14
- 0
hyde/tests/test_site.py View File

@@ -82,6 +82,20 @@ def test_walk_resources():
expected.sort()
assert pages == expected

def test_contains_resource():
s = Site(TEST_SITE_ROOT)
s.load()
path = 'blog/2010/december'
node = s.content.node_from_relative_path(path)
assert node.contains_resource('merry-christmas.html')
def test_get_resource():
s = Site(TEST_SITE_ROOT)
s.load()
path = 'blog/2010/december'
node = s.content.node_from_relative_path(path)
resource = node.get_resource('merry-christmas.html')
assert resource == s.content.resource_from_relative_path(Folder(path).child('merry-christmas.html'))

class TestSiteWithConfig(object):



Loading…
Cancel
Save