Browse Source

Adding grouping prototype

main
Lakshmi Vyasarajan 14 years ago
parent
commit
849b816de5
14 changed files with 183 additions and 131 deletions
  1. +53
    -1
      hyde/ext/plugins/sorter.py
  2. +1
    -35
      hyde/generator.py
  3. +1
    -1
      hyde/layouts/doc/layout/doc.j2
  4. +1
    -1
      hyde/layouts/doc/layout/root.j2
  5. +45
    -0
      hyde/plugin.py
  6. +1
    -1
      hyde/tests/ext/test_less.py
  7. +65
    -49
      hyde/tests/ext/test_sorter.py
  8. +1
    -8
      hyde/tests/sites/test_grouper/content/blog/installation.html
  9. +3
    -0
      hyde/tests/sites/test_grouper/content/blog/meta.yaml
  10. +1
    -8
      hyde/tests/sites/test_grouper/content/blog/overview.html
  11. +4
    -8
      hyde/tests/sites/test_grouper/content/blog/plugins.html
  12. +4
    -8
      hyde/tests/sites/test_grouper/content/blog/tags.html
  13. +1
    -8
      hyde/tests/sites/test_grouper/content/blog/templating.html
  14. +2
    -3
      hyde/tests/sites/test_grouper/site.yaml

+ 53
- 1
hyde/ext/plugins/sorter.py View File

@@ -4,11 +4,12 @@ Contains classes and utilities related to sortin
resources and nodes in hyde.
"""
import re
from hyde.model import Expando
from hyde.plugin import Plugin
from hyde.site import Node, Resource

from functools import partial
from itertools import ifilter, izip, tee
from itertools import ifilter, izip, tee, product
from operator import attrgetter

def pairwalk(iterable):
@@ -68,6 +69,29 @@ def add_method(obj, method_name, method_, settings):
setattr(obj, method_name, m)


# class SortGroup(Expando):
# """
# A wrapper around sort groups. Understand hierarchical groups
# and group metadata.
# """
#
# def update(self, d):
# """
# Updates the Sortgroup with a new grouping
# """
#
# d = d or {}
# if isinstance(d, dict):
# for key, value in d.items():
# if key == "groups":
# for group in value:
#
# setattr(self, key, Expando.transform(value))
# elif isinstance(d, Expando):
# self.update(d.__dict__)



class SorterPlugin(Plugin):
"""
Sorter plugin for hyde. Adds the ability to do
@@ -109,6 +133,7 @@ class SorterPlugin(Plugin):
return

for name, settings in config.sorter.__dict__.items():
self._add_groups(name, settings)
self.logger.info("Adding sort methods for [%s]" % name)
sort_method_name = 'walk_resources_sorted_by_%s' % name
add_method(Node, sort_method_name, sort_method, settings)
@@ -127,3 +152,30 @@ class SorterPlugin(Plugin):
for prev, next in pairwalk(walker()):
setattr(prev, next_att, next)
setattr(next, prev_att, prev)

def _add_groups(self, sorter_name, settings):
"""
Checks if the given `settings` contains a `groups` attribute.
If it does, it loads the specified groups into the `site` object.
"""
if not hasattr(settings, 'grouping') or \
not hasattr(settings.grouping, 'groups') or \
not hasattr(settings.grouping, 'name'):
return

grouping = Expando(settings.grouping)
setattr(self.site, sorter_name, grouping)

group_dict = dict([(g.name, g) for g in grouping.groups])
for resource in self.site.content.walk_resources():
try:
group_value = getattr(resource.meta, grouping.name)
except AttributeError:
continue
if group_value in group_dict:
group = group_dict[group_value]

if not hasattr(group, 'resources'):
group.resources = []
print "Adding resource[%s] to group[%s]" % (resource, group.name)
group.resources.append(resource)

+ 1
- 35
hyde/generator.py View File

@@ -31,41 +31,7 @@ class Generator(object):
self.template = None
Plugin.load_all(site)

class PluginProxy(object):
"""
A proxy class to raise events in registered plugins
"""

def __init__(self, site):
super(PluginProxy, self).__init__()
self.site = site

def __getattr__(self, method_name):
if hasattr(Plugin, method_name):
def __call_plugins__(*args):
#logger.debug("Calling plugin method [%s]", method_name)
res = None
if self.site.plugins:
for plugin in self.site.plugins:
if hasattr(plugin, method_name):
#logger.debug(
# "\tCalling plugin [%s]",
# plugin.__class__.__name__)
function = getattr(plugin, method_name)
res = function(*args)
if res:
targs = list(args)
last = None
if len(targs):
last = targs.pop()
targs.append(res if res else last)
args = tuple(targs)
return res

return __call_plugins__
raise HydeException(
"Unknown plugin method [%s] called." % method_name)
self.events = PluginProxy(self.site)
self.events = Plugin.get_proxy(self.site)

@contextmanager
def context_for_resource(self, resource):


+ 1
- 1
hyde/layouts/doc/layout/doc.j2 View File

@@ -1,7 +1,7 @@
{% extends "root.j2" %}
{% block main -%}
<article>
<hgroup class="article_head">
<hgroup>
<h1 class="title">{{ resource.meta.title }}</h1>
<h3 class="subtitle">{{ resource.meta.subtitle }}</h3>
</hgroup>


+ 1
- 1
hyde/layouts/doc/layout/root.j2 View File

@@ -23,7 +23,7 @@
compatibility mode is within the first 1K bytes
code.google.com/p/chromium/issues/detail?id=23003 -->

<title>{% block title %}{{ resource.meta.title }} / Hyde Docs{% endblock %}</title>
<title>{% block title %}{{ resource.meta.title }}{% endblock %}</title>
<meta name="description" content="{{ resource.meta.description }}">
<meta name="author" content="{{ resource.meta.author }}">



+ 45
- 0
hyde/plugin.py View File

@@ -8,6 +8,44 @@ from hyde import loader
from hyde.util import getLoggerWithNullHandler
from functools import partial


logger = getLoggerWithNullHandler('hyde.engine')

class PluginProxy(object):
"""
A proxy class to raise events in registered plugins
"""

def __init__(self, site):
super(PluginProxy, self).__init__()
self.site = site

def __getattr__(self, method_name):
if hasattr(Plugin, method_name):
def __call_plugins__(*args):
# logger.debug("Calling plugin method [%s]", method_name)
res = None
if self.site.plugins:
for plugin in self.site.plugins:
if hasattr(plugin, method_name):
# logger.debug(
# "\tCalling plugin [%s]",
# plugin.__class__.__name__)
function = getattr(plugin, method_name)
res = function(*args)
if res:
targs = list(args)
last = None
if len(targs):
last = targs.pop()
targs.append(res if res else last)
args = tuple(targs)
return res

return __call_plugins__
raise HydeException(
"Unknown plugin method [%s] called." % method_name)

class Plugin(object):
"""
The plugin protocol
@@ -132,6 +170,9 @@ class Plugin(object):
"""
pass

def raise_event(self, event_name):
return getattr(Plugin.proxy, event_name)()

@staticmethod
def load_all(site):
"""
@@ -140,3 +181,7 @@ class Plugin(object):
"""
site.plugins = [loader.load_python_object(name)(site)
for name in site.config.plugins]

@staticmethod
def get_proxy(site):
return PluginProxy(site)

+ 1
- 1
hyde/tests/ext/test_less.py View File

@@ -29,7 +29,7 @@ class TestLess(object):
def test_can_execute_less(self):
s = Site(TEST_SITE)
s.config.plugins = ['hyde.ext.plugins.less.LessCSSPlugin']
s.config.less = Expando(dict(app='/Users/lvfp/local/bin/lessc'))
s.config.less = Expando(dict(app='~/local/bin/lessc'))
source = TEST_SITE.child('content/media/css/site.less')
target = File(Folder(s.config.deploy_root_path).child('media/css/site.css'))
gen = Generator(s)


+ 65
- 49
hyde/tests/ext/test_sorter.py View File

@@ -4,6 +4,7 @@ Use nose
`$ pip install nose`
`$ nosetests`
"""
from hyde.ext.plugins.meta import MetaPlugin
from hyde.ext.plugins.sorter import SorterPlugin
from hyde.fs import File, Folder
from hyde.generator import Generator
@@ -136,55 +137,6 @@ class TestSorter(object):
File(p).parent.name]))]
assert pages == expected_sorted

# def test_walk_resources_sorted_with_grouping_one_level(self):
# s = Site(TEST_SITE)
# cfg = """
# plugins:
# - hyde.ext.sorter.SorterPlugin
# sorter:
# multi:
# groups: sections.yaml
# attr:
# - source_file.kind
# - node.name
#
# """
# sections = """
# group_name: section
# groups:
# -
# name: support
# description: All site support pages
# -
# name: media
# description: Media files
# """
# s.config = Config(TEST_SITE, config_dict=yaml.load(cfg))
# s.load()
# SorterPlugin(s).begin_site()
#
# assert hasattr(s.content, 'walk_resources_sorted_by_multi')
# expected = ["content/404.html",
# "content/about.html",
# "content/apple-touch-icon.png",
# "content/blog/2010/december/merry-christmas.html",
# "content/crossdomain.xml",
# "content/favicon.ico",
# "content/robots.txt",
# "content/site.css"
# ]
#
# pages = [page.name for page in s.content.walk_resources_sorted_by_multi()]
#
# expected_sorted = [File(page).name
# for page in
# sorted(expected,
# key=lambda p: tuple(
# [File(p).kind,
# File(p).parent.name]))]
# assert pages == expected_sorted


def test_walk_resources_sorted_no_default_is_processable(self):
s = Site(TEST_SITE)
cfg = """
@@ -318,3 +270,67 @@ class TestSorter(object):
q = PyQuery(text)

assert q('span.latest').text() == 'YayYayYay'

class TestGrouper(object):

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

def tearDown(self):
TEST_SITE.delete()

def test_walk_resources_sorted_with_grouping_one_level(self):
s = Site(TEST_SITE)
cfg = """
plugins:
- hyde.ext.meta.MetaPlugin
- hyde.ext.sorter.SorterPlugin
sorter:
sectional:
grouping:
name: section
description: Sections in the site
groups:
-
name: start
description: Getting Started
-
name: plugins
description: Plugins
attr:
- source_file.kind
- node.name

"""
s.config = Config(TEST_SITE, config_dict=yaml.load(cfg))
s.load()
MetaPlugin(s).begin_site()
SorterPlugin(s).begin_site()

assert hasattr(s, 'sectional')
assert hasattr(s.sectional, 'groups')
assert len(s.sectional.groups) == 2

groups = dict([(g.name, g) for g in s.sectional.groups])

assert 'start' in groups
assert 'plugins' in groups

start = groups['start']
assert hasattr(start, 'resources')
start_resources = [resource.name for resource in
start.resources if resource.is_processable]
assert len(start_resources) == 3
assert 'installation.html' in start_resources
assert 'overview.html' in start_resources
assert 'templating.html' in start_resources

plugin = groups['plugins']
assert hasattr(plugin, 'resources')
plugin_resources = [resource.name for resource in
plugin.resources if resource.is_processable]
assert len(plugin_resources) == 2
assert 'plugins.html' in plugin_resources
assert 'tags.html' in plugin_resources

+ 1
- 8
hyde/tests/sites/test_grouper/content/blog/installation.html View File

@@ -1,8 +1 @@
{% extends "base.html" %}

{% block main %}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
{{resource.name}}
{% endblock %}
# Installation Guide

+ 3
- 0
hyde/tests/sites/test_grouper/content/blog/meta.yaml View File

@@ -0,0 +1,3 @@
extends: base.html
default_block: main
section: start

+ 1
- 8
hyde/tests/sites/test_grouper/content/blog/overview.html View File

@@ -1,8 +1 @@
{% extends "base.html" %}

{% block main %}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
{{resource.name}}
{% endblock %}
# Overview

+ 4
- 8
hyde/tests/sites/test_grouper/content/blog/plugins.html View File

@@ -1,8 +1,4 @@
{% extends "base.html" %}

{% block main %}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
{{resource.name}}
{% endblock %}
===
section: plugins
===
# Plugins

+ 4
- 8
hyde/tests/sites/test_grouper/content/blog/tags.html View File

@@ -1,8 +1,4 @@
{% extends "base.html" %}

{% block main %}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
{{resource.name}}
{% endblock %}
===
section: plugins
===
# Tags

+ 1
- 8
hyde/tests/sites/test_grouper/content/blog/templating.html View File

@@ -1,8 +1 @@
{% extends "base.html" %}

{% block main %}
Hi!

I am a test template to make sure jinja2 generation works well with hyde.
{{resource.name}}
{% endblock %}
# Templating

+ 2
- 3
hyde/tests/sites/test_grouper/site.yaml View File

@@ -2,6 +2,5 @@ mode: development
media_root:: media # Relative path from site root (the directory where this file exists)
media_url: /media
template: hyde.ext.jinja2
widgets:
plugins:
aggregators:
meta:
nodemeta: meta.yaml

Loading…
Cancel
Save