diff --git a/hyde/ext/plugins/meta.py b/hyde/ext/plugins/meta.py
index b4a6627..fe80f35 100644
--- a/hyde/ext/plugins/meta.py
+++ b/hyde/ext/plugins/meta.py
@@ -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
\ No newline at end of file
+ return text
diff --git a/hyde/model.py b/hyde/model.py
index fb664bc..0632df1 100644
--- a/hyde/model.py
+++ b/hyde/model.py
@@ -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))
diff --git a/hyde/site.py b/hyde/site.py
index badcae6..26b2465 100644
--- a/hyde/site.py
+++ b/hyde/site.py
@@ -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.
diff --git a/hyde/tests/ext/test_meta.py b/hyde/tests/ext/test_meta.py
index d6df1d6..791ac27 100644
--- a/hyde/tests/ext/test_meta.py
+++ b/hyde/tests/ext/test_meta.py
@@ -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()
\ No newline at end of file
+ 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.
+ {{resource.meta.title}}
+ {{resource.meta.author}}
+
+{%% 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.
+ {{resource.meta.title}}
+ {{resource.meta.author}}
+
+{%% 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.
+ {{resource.meta.title}}
+ {{resource.meta.author}}
+
+{%% 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()
diff --git a/hyde/tests/test_model.py b/hyde/tests/test_model.py
index 1854c09..865d99f 100644
--- a/hyde/tests/test_model.py
+++ b/hyde/tests/test_model.py
@@ -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):
diff --git a/hyde/tests/test_site.py b/hyde/tests/test_site.py
index 52f0e84..499c9ed 100644
--- a/hyde/tests/test_site.py
+++ b/hyde/tests/test_site.py
@@ -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):