diff --git a/hyde/ext/plugins/urls.py b/hyde/ext/plugins/urls.py
new file mode 100644
index 0000000..13fc181
--- /dev/null
+++ b/hyde/ext/plugins/urls.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+"""
+Contains classes and utilities related to hyde urls.
+"""
+import re
+
+from hyde.fs import File, Folder
+from hyde.model import Expando
+from hyde.plugin import Plugin
+from hyde.site import Site, Node, Resource
+
+from functools import wraps
+
+class UrlCleanerPlugin(Plugin):
+ """
+ Url Cleaner plugin for hyde. Adds to hyde the ability to generate clean
+ urls.
+
+ Configuration example
+ ---------------------
+ #yaml
+ urlcleaner:
+ index_file_names:
+ # Identifies the files that represents a directory listing.
+ # These file names are automatically stripped away when
+ # the content_url function is called.
+ - index.html
+ strip_extensions:
+ # The following extensions are automatically removed when
+ # generating the urls using content_url function.
+ - html
+ # This option will append a slash to the end of directory paths
+ append_slash: true
+ """
+
+ def __init__(self, site):
+ super(UrlCleanerPlugin, self).__init__(site)
+
+ def begin_site(self):
+ """
+ Replace the content_url method in the site object with a custom method
+ that cleans urls based on the given configuration.
+ """
+ config = self.site.config
+
+ if not hasattr(config, 'urlcleaner'):
+ return
+
+ if (hasattr(Site, '___url_cleaner_patched___')):
+ return
+
+ settings = config.urlcleaner
+
+ print settings.to_dict()
+
+ def clean_url(urlgetter):
+ @wraps(urlgetter)
+ def wrapper(site, path):
+ url = urlgetter(site, path)
+ index_file_names = getattr(settings,
+ 'index_file_names',
+ ['index.html'])
+ rep = File(url)
+ if rep.name in index_file_names:
+ url = rep.parent.path.rstrip('/')
+ if hasattr(settings, 'append_slash') and \
+ settings.append_slash:
+ url += '/'
+ elif hasattr(settings, 'strip_extensions'):
+ if rep.kind in settings.strip_extensions:
+ url = rep.parent.child(rep.name_without_extension)
+ return url or '/'
+ return wrapper
+
+ Site.___url_cleaner_patched___ = True
+ Site.content_url = clean_url(Site.content_url)
\ No newline at end of file
diff --git a/hyde/tests/ext/test_urlcleaner.py b/hyde/tests/ext/test_urlcleaner.py
new file mode 100644
index 0000000..2db7686
--- /dev/null
+++ b/hyde/tests/ext/test_urlcleaner.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+"""
+Use nose
+`$ pip install nose`
+`$ nosetests`
+"""
+from hyde.fs import File, Folder
+from hyde.generator import Generator
+from hyde.site import Site
+
+import yaml
+
+from hyde.model import Config
+
+TEST_SITE = File(__file__).parent.parent.child_folder('_test')
+
+
+class TestUrlCleaner(object):
+
+ def setUp(self):
+ TEST_SITE.make()
+ TEST_SITE.parent.child_folder(
+ 'sites/test_jinja').copy_contents_to(TEST_SITE)
+
+ def tearDown(self):
+ TEST_SITE.delete()
+
+ def test_url_cleaner(self):
+ s = Site(TEST_SITE)
+ cfg = """
+ plugins:
+ - hyde.ext.plugins.urls.UrlCleanerPlugin
+ urlcleaner:
+ index_file_names:
+ - about.html
+ strip_extensions:
+ - html
+ append_slash: true
+ """
+ s.config = Config(TEST_SITE, config_dict=yaml.load(cfg))
+ text = """
+ {% extends "base.html" %}
+
+ {% block main %}
+
+
+ {% endblock %}
+ """
+
+ about2 = File(TEST_SITE.child('content/test.html'))
+ about2.write(text)
+ gen = Generator(s)
+ gen.generate_all()
+
+ from pyquery import PyQuery
+ target = File(Folder(s.config.deploy_root_path).child('test.html'))
+ text = target.read_all()
+ q = PyQuery(text)
+ assert q('a#index').attr("href") == '/'
+ assert q('a#blog').attr("href") == '/blog/2010/december/merry-christmas'
\ No newline at end of file