Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adds 'active' template helper and improve testability

  • Loading branch information...
commit 260f234186e26a20e3fd4db1f616448f501dfb3d 1 parent 2fdf91b
@jpscaletti jpscaletti authored
View
6 AUTHORS.md
@@ -5,10 +5,10 @@ Clay is written and maintained by the Lúcuma Team and various contributors.
Project Leader / Developer:
-- Juan-Pablo Scaletti <juanpablo@lucumalabs.com>
+- Juan-Pablo Scaletti (jpscaletti / lucuma)
Contributors:
-- Muhammad Alkarouri (https://github.com/malkarouri)
-- Alexander Zayats (https://github.com/z4y4ts)
+- Muhammad Alkarouri (malkarouri)
+- Alexander Zayats (z4y4ts)
View
13 CHANGES.md
@@ -3,11 +3,8 @@
## Version 2.0
-Complete TDD rewrite in Flask + few awesome Lucuma libraries.
-Most important new features:
-
- - _index.html now is viewable in run mode.
- - Adaptative run port (if it is taken, Clay try to use the next one).
- - No need to filter non-html files. Only those ending in ".html" or ".tmpl" are processed as templates.
-
-
+TDD rewrite. Most important new features:
+- _index.html now is viewable in run mode.
+- No need to filter non-html files. Only those ending in ".html" or ".tmpl" are processed as templates.
+- Adaptative run port (if it is taken, Clay try to use the next one).
+- The "not found" page now shows the real missing templates (it could be "imported" inside the current page).
View
7 README.md
@@ -48,11 +48,6 @@ To generate a static version of your site, stop the server (with `Control + C`)
and all the templates will be processed and the result stored inside the `build` folder.
-## Not just for HTML
-
-Clay can automatically compiles Less, Sass, CleverCSS & CoffeeScript files directly from your `static` dir (Less and CoffeeScript has to be installed in node first).
-
-
## How to install
Just run
@@ -92,6 +87,6 @@ Jinja2 templates are much more than just template inheritance. For more advaced
---------------------------------------
by [Lúcuma] (http://lucumalabs.com).<br />
+© [Lúcuma] (http://lucumalabs.com).<br />
See `AUTHORS.md` for more details.<br />
License: [MIT License] (http://www.opensource.org/licenses/mit-license.php).
View
9 clay/main.py
@@ -17,7 +17,7 @@
from .helpers import (read_content, make_dirs, create_file,
copy_if_updated, get_updated_datetime)
-from .tglobals import link_to, to_unicode
+from .tglobals import link_to, active, to_unicode
SOURCE_DIRNAME = 'source'
@@ -30,9 +30,9 @@
DEFAULT_HOST = '0.0.0.0'
DEFAULT_PORT = 8080
-WELCOME = " # Clay (by Lucuma labs)"
-ADDRINUSE = " ---- Address already in use. Trying another port..."
-SOURCE_NOT_FOUND = """We couldn't found a "%s" dir.
+WELCOME = u" # Clay (by Lucuma labs)"
+ADDRINUSE = u" ---- Address already in use. Trying another port..."
+SOURCE_NOT_FOUND = u"""We couldn't found a "%s" dir.
Are you sure you're in the correct folder? """ % SOURCE_DIRNAME
rx_abs_url = re.compile(r'\s(src|href)=[\'"](\/(?:[a-z0-9][^\'"]*)?)[\'"]',
@@ -79,6 +79,7 @@ def inject_globals():
'now': datetime.utcnow(),
'enumerate': enumerate,
+ 'active': active,
'link_to': link_to,
}
View
52 clay/tglobals.py
@@ -5,10 +5,7 @@
from xml.sax.saxutils import quoteattr
from jinja2 import Markup
-from flask import request, url_for
-
-
-rx_url = re.compile(ur'^([a-z]{3,7}:(//)?)?([^/:]+%s|([0-9]{1,3}\.){3}[0-9]{1,3})(:[0-9]+)?(\/.*)?$')
+from flask import request
def to_unicode(s, encoding='utf8', errors='strict'):
@@ -17,6 +14,23 @@ def to_unicode(s, encoding='utf8', errors='strict'):
return s.decode(encoding, errors)
+def norm_url(url):
+ return '/' + url.strip('/')
+
+
+def active(url='/', partial=False):
+ path = request.path.rstrip('/')
+ resp = u''
+ patterns = url if isinstance(url, (list, tuple)) else [url]
+
+ for url in patterns:
+ url = norm_url(url)
+ if path == url or (partial and path.startswith(url)):
+ return 'active'
+
+ return resp
+
+
def format_html_attrs(**kwargs):
"""Generate HTML attributes from the provided keyword arguments.
@@ -55,7 +69,7 @@ def format_html_attrs(**kwargs):
return u' '.join(attrs)
-def link_to(text='', endpoint='', wrapper=None, partial=False, **kwargs):
+def link_to(text='', url='/', wrapper=None, partial=False, **kwargs):
"""Build an HTML anchor element for the provided URL.
If the url match the beginning of that in the current request, an `active`
class is added. This is intended to be use to build navigation links.
@@ -81,10 +95,9 @@ class is added. This is intended to be use to build navigation links.
:param text:
The text (or HTML) of the link.
- :param endpoint:
- URL or endpoint name. This can also be a *list* of URLs and/or
- endpoint names. The first one will be used for the link, the rest only
- to match the current page
+ :param url:
+ This can also be a *list* of URLs. The first one will be used for the
+ link, the rest only to match the current page
:param wrapper:
Optional tag name of a wrapper element for the link.
@@ -95,27 +108,18 @@ class is added. This is intended to be use to build navigation links.
u'<li title="Hi"><a href="/hello/">Hello</a></li>'
:param partial:
- If True, the endpoint will be matched against the beginning of the
+ If True, the url will be matched against the beginning of the
current URL. For instance, if the current URL is `/foo/bar/123/`,
- an endpoint like `/foo/bar/` will be considered a match.
+ an url like `/foo/bar/` will be considered a match.
"""
- path = request.path.rstrip('/')
-
- patterns = endpoint if isinstance(endpoint, (list, tuple)) else [endpoint]
- patterns = [p
- if p.startswith('/') or re.match(rx_url, p) else url_for(p)
- for p in patterns]
-
classes = kwargs.pop('classes', '').strip()
- for url in patterns:
- url = url.rstrip('/')
- if path == url or (partial and path.startswith(url)):
- classes += ' active'
- break
+ active_class = active(url, partial)
+ classes += u' ' + active_class if active_class else u''
+ url = url[0] if isinstance(url, (list, tuple)) else url
data = {
- 'url': patterns[0],
+ 'url': url,
'text': text,
'attrs': format_html_attrs(classes=classes, **kwargs),
}
View
4 tests/helpers.py
@@ -22,12 +22,12 @@
BUILD_DIR = join(TESTS, 'build')
-@pytest.fixture(scope="module")
+@pytest.fixture()
def c():
return Clay(TESTS)
-@pytest.fixture(scope="module")
+@pytest.fixture()
def t(c):
return c.get_test_client()
View
56 tests/test_tglobals.py
@@ -1,11 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
-from clay.tglobals import link_to
+from clay.tglobals import link_to, active
from .helpers import *
+def setup_module():
+ remove_test_dirs()
+ make_dirs(SOURCE_DIR)
+
+
+def teardown_module():
+ remove_test_dirs()
+
+
def _test_link_to(path):
html = link_to(u'Hello', '/hello/', title='click me')
expected = u'<a href="/hello/" title="click me">Hello</a>'
@@ -45,3 +54,48 @@ def test_link_to(c):
with c.app.test_request_context(path, method='GET'):
_test_link_to(path)
+
+def test_link_to_in_templates(t):
+ setup_module()
+ make_dirs(SOURCE_DIR)
+
+ path = 'aaaa.html'
+ content = u"{{ link_to('', '%s') }}" % path
+ create_file(get_source_path(path), content)
+
+ expected = u'<a href="%s" class="active"></a>' % path
+ resp = t.get('/' + path)
+ assert resp.data == expected
+
+
+def _test_active_case(path, as_expected, partial=False):
+ html = active(path, partial=partial)
+ assert (html == 'active') is as_expected
+
+
+def _test_active(path):
+ _test_active_case('/hello/', False)
+ _test_active_case(path, True)
+ _test_active_case('/foo/', True, partial=True)
+ _test_active_case(['/hello/', path], True)
+ _test_active_case(['/hello/', '/world/'], False)
+
+
+def test_active(c):
+ path = '/foo/bar/'
+ with c.app.test_request_context(path, method='GET'):
+ _test_active(path)
+
+
+def test_active_in_templates(t):
+ setup_module()
+ make_dirs(SOURCE_DIR)
+
+ path = 'bbbb.html'
+ content = u'''class="{{ active('%s') }}"''' % path
+ create_file(get_source_path(path), content)
+
+ expected = u'class="active"'
+ resp = t.get('/' + path)
+ assert resp.data == expected
+
Please sign in to comment.
Something went wrong with that request. Please try again.