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. 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): class MetaPlugin(Plugin):
@@ -38,21 +52,46 @@ class MetaPlugin(Plugin):
def __init__(self, site): def __init__(self, site):
super(MetaPlugin, self).__init__(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): def begin_text_resource(self, resource, text):
""" """
Load meta data by looking for the marker. Load meta data by looking for the marker.
Once loaded, remove the meta area from the text. Once loaded, remove the meta area from the text.
""" """

logger.info("Trying to load metadata from resource [%s]" % resource) 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) match = re.match(yaml_finder, text)
if not match: if not match:
logger.info("No metadata found in resource [%s]" % resource) logger.info("No metadata found in resource [%s]" % resource)
return text return text
text = text[match.end():] 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]" logger.info("Successfully loaded metadata from resource [%s]"
% resource) % resource)
return text
return text

+ 6
- 0
hyde/model.py View File

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


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

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


+ 18
- 0
hyde/site.py View File

@@ -85,6 +85,24 @@ class Node(Processable):
self.child_nodes = [] self.child_nodes = []
self.resources = [] 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): def add_child_node(self, folder):
""" """
Creates a new child node and adds it to the list of child nodes. 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): def setUp(self):
TEST_SITE.make() 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): def tearDown(self):
TEST_SITE.delete() TEST_SITE.delete()



def test_can_load_front_matter(self): def test_can_load_front_matter(self):
d = {
'title': 'A nice title',
d = {'title': 'A nice title',
'author': 'Lakshmi Vyas', 'author': 'Lakshmi Vyas',
'twitter': 'lakshmivyas'
}
'twitter': 'lakshmivyas'}
text = """ text = """
--- ---
title: %(title)s title: %(title)s
@@ -68,4 +66,149 @@ twitter: %(twitter)s
text = target.read_all() text = target.read_all()
q = PyQuery(text) q = PyQuery(text)
for k, v in d.items(): 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.c == d['b']['c']
assert x.b.d.e == d['b']['d']['e'] 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') TEST_SITE_ROOT = File(__file__).parent.child_folder('sites/test_jinja')
import yaml import yaml
class TestConfig(object): class TestConfig(object):


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

@@ -82,6 +82,20 @@ def test_walk_resources():
expected.sort() expected.sort()
assert pages == expected 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): class TestSiteWithConfig(object):




Loading…
Cancel
Save