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. resources and nodes in hyde.
""" """
import re import re
from hyde.model import Expando
from hyde.plugin import Plugin from hyde.plugin import Plugin
from hyde.site import Node, Resource from hyde.site import Node, Resource


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


def pairwalk(iterable): def pairwalk(iterable):
@@ -68,6 +69,29 @@ def add_method(obj, method_name, method_, settings):
setattr(obj, method_name, m) 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): class SorterPlugin(Plugin):
""" """
Sorter plugin for hyde. Adds the ability to do Sorter plugin for hyde. Adds the ability to do
@@ -109,6 +133,7 @@ class SorterPlugin(Plugin):
return return


for name, settings in config.sorter.__dict__.items(): for name, settings in config.sorter.__dict__.items():
self._add_groups(name, settings)
self.logger.info("Adding sort methods for [%s]" % name) self.logger.info("Adding sort methods for [%s]" % name)
sort_method_name = 'walk_resources_sorted_by_%s' % name sort_method_name = 'walk_resources_sorted_by_%s' % name
add_method(Node, sort_method_name, sort_method, settings) add_method(Node, sort_method_name, sort_method, settings)
@@ -127,3 +152,30 @@ class SorterPlugin(Plugin):
for prev, next in pairwalk(walker()): for prev, next in pairwalk(walker()):
setattr(prev, next_att, next) setattr(prev, next_att, next)
setattr(next, prev_att, prev) 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 self.template = None
Plugin.load_all(site) 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 @contextmanager
def context_for_resource(self, resource): def context_for_resource(self, resource):


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

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


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

@@ -23,7 +23,7 @@
compatibility mode is within the first 1K bytes compatibility mode is within the first 1K bytes
code.google.com/p/chromium/issues/detail?id=23003 --> 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="description" content="{{ resource.meta.description }}">
<meta name="author" content="{{ resource.meta.author }}"> <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 hyde.util import getLoggerWithNullHandler
from functools import partial 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): class Plugin(object):
""" """
The plugin protocol The plugin protocol
@@ -132,6 +170,9 @@ class Plugin(object):
""" """
pass pass


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

@staticmethod @staticmethod
def load_all(site): def load_all(site):
""" """
@@ -140,3 +181,7 @@ class Plugin(object):
""" """
site.plugins = [loader.load_python_object(name)(site) site.plugins = [loader.load_python_object(name)(site)
for name in site.config.plugins] 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): def test_can_execute_less(self):
s = Site(TEST_SITE) s = Site(TEST_SITE)
s.config.plugins = ['hyde.ext.plugins.less.LessCSSPlugin'] 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') source = TEST_SITE.child('content/media/css/site.less')
target = File(Folder(s.config.deploy_root_path).child('media/css/site.css')) target = File(Folder(s.config.deploy_root_path).child('media/css/site.css'))
gen = Generator(s) gen = Generator(s)


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

@@ -4,6 +4,7 @@ Use nose
`$ pip install nose` `$ pip install nose`
`$ nosetests` `$ nosetests`
""" """
from hyde.ext.plugins.meta import MetaPlugin
from hyde.ext.plugins.sorter import SorterPlugin from hyde.ext.plugins.sorter import SorterPlugin
from hyde.fs import File, Folder from hyde.fs import File, Folder
from hyde.generator import Generator from hyde.generator import Generator
@@ -136,55 +137,6 @@ class TestSorter(object):
File(p).parent.name]))] File(p).parent.name]))]
assert pages == expected_sorted 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): def test_walk_resources_sorted_no_default_is_processable(self):
s = Site(TEST_SITE) s = Site(TEST_SITE)
cfg = """ cfg = """
@@ -318,3 +270,67 @@ class TestSorter(object):
q = PyQuery(text) q = PyQuery(text)


assert q('span.latest').text() == 'YayYayYay' 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_root:: media # Relative path from site root (the directory where this file exists)
media_url: /media media_url: /media
template: hyde.ext.jinja2 template: hyde.ext.jinja2
widgets:
plugins:
aggregators:
meta:
nodemeta: meta.yaml

Loading…
Cancel
Save