aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/djangoproject/djangoproject/static/css/forms.css12
-rw-r--r--examples/djangoproject/djangoproject/templates/base.html1
-rw-r--r--examples/djangoproject/djangoproject/templates/styleguide.html21
-rw-r--r--pykss/contrib/django/templates/pykss/styleguideblock.html10
-rw-r--r--pykss/contrib/django/templatetags/pykss.py137
-rw-r--r--pykss/modifier.py4
-rw-r--r--pykss/section.py24
-rw-r--r--tests/templates/django.html9
-rw-r--r--tests/test_contrib/test_django/test_templatetags/test_pykss.py24
-rw-r--r--tests/test_modifier.py7
-rw-r--r--tests/test_section.py6
11 files changed, 168 insertions, 87 deletions
diff --git a/examples/djangoproject/djangoproject/static/css/forms.css b/examples/djangoproject/djangoproject/static/css/forms.css
new file mode 100644
index 0000000..3830ebd
--- /dev/null
+++ b/examples/djangoproject/djangoproject/static/css/forms.css
@@ -0,0 +1,12 @@
+/*
+Form input.
+
+.error - When form error.
+
+Example:
+ <input type="text" class="text$modifier_class" />
+
+Styleguide 2.1
+*/
+input.error {
+ border: 1px solid red; }
diff --git a/examples/djangoproject/djangoproject/templates/base.html b/examples/djangoproject/djangoproject/templates/base.html
index f52ed82..ef4a5c4 100644
--- a/examples/djangoproject/djangoproject/templates/base.html
+++ b/examples/djangoproject/djangoproject/templates/base.html
@@ -6,6 +6,7 @@
<title>Styleguide Example</title>
<link rel="stylesheet" href="{% static "css/layout.css" %}" type="text/css" />
<link rel="stylesheet" href="{% static "css/buttons.css" %}" type="text/css" />
+ <link rel="stylesheet" href="{% static "css/forms.css" %}" type="text/css" />
</head>
<body>
<header>Styleguide Example</header>
diff --git a/examples/djangoproject/djangoproject/templates/styleguide.html b/examples/djangoproject/djangoproject/templates/styleguide.html
index 1817a27..05eafb7 100644
--- a/examples/djangoproject/djangoproject/templates/styleguide.html
+++ b/examples/djangoproject/djangoproject/templates/styleguide.html
@@ -14,7 +14,7 @@
{% endcomment %}
{% styleguideblock styleguide "1.1" %}
- <button class="{{ modifier_class }}">Example Button</button>
+ <button class="$modifier_class">Example Button</button>
{% endstyleguideblock %}
{% verbatim %}
@@ -22,9 +22,26 @@
<pre>
<code>
{% styleguideblock styleguide "1.1" %}
- &lt;button class="{{ modifier_class }}"&gt;Example Button&lt;/button&gt;
+ &lt;button class="$modifier_class"&gt;Example Button&lt;/button&gt;
{% endstyleguideblock %}
</code>
</pre>
{% endverbatim %}
+
+{% comment %}
+
+{% renderstyleguide styleguide "2" %}
+{% renderstyleguide styleguide "2" using "custom.html" %}
+
+{% endcomment %}
+{% renderstyleguide styleguide "2" %}
+
+{% verbatim %}
+<p>This block above was created with a simple template call:</p>
+<pre>
+ <code>
+{% renderstyleguide styleguide "2" %}
+ </code>
+</pre>
+{% endverbatim %}
{% endblock %}
diff --git a/pykss/contrib/django/templates/pykss/styleguideblock.html b/pykss/contrib/django/templates/pykss/styleguideblock.html
index 8521ee1..138a2fd 100644
--- a/pykss/contrib/django/templates/pykss/styleguideblock.html
+++ b/pykss/contrib/django/templates/pykss/styleguideblock.html
@@ -18,20 +18,20 @@
{% block styleguide_element %}
<div class="styleguide-element">
- {{ example_html }}
+ {{ section.example|safe }}
</div>
{% endblock %}
{% block styleguide_modifier_elements %}
- {% for example in modifier_examples %}
+ {% for modifier in section.modifiers %}
<div class="styleguide-element styleguide-modifier">
- <span class="styleguide-modifier-name">{{ example.modifier.name }}</span>
- {{ example.html }}
+ <span class="styleguide-modifier-name">{{ modifier.name }}</span>
+ {{ modifier.example|safe }}
</div>
{% endfor %}
{% endblock %}
{% block styleguide_code %}
- <pre class="styleguide-code">{{ escaped_html }}</pre>
+ <pre class="styleguide-code">{{ section.example|escape }}</pre>
{% endblock %}
</div>
diff --git a/pykss/contrib/django/templatetags/pykss.py b/pykss/contrib/django/templatetags/pykss.py
index c1d1411..a711c5e 100644
--- a/pykss/contrib/django/templatetags/pykss.py
+++ b/pykss/contrib/django/templatetags/pykss.py
@@ -1,14 +1,12 @@
from django import template
-from django.conf import settings
from django.template.loader import render_to_string
-from django.utils.safestring import mark_safe
-from django.utils.html import escape
+from django.utils.html import strip_spaces_between_tags
register = template.Library()
-class StyleguideBlockNode(template.Node):
+class BaseStyleguideNode(template.Node):
def __init__(self, styleguide, reference, template_name, nodelist):
self.styleguide = styleguide
@@ -19,84 +17,105 @@ class StyleguideBlockNode(template.Node):
def __repr__(self):
return '<StyleguideBlockNode>'
+ @classmethod
+ def as_tag(cls, parser, token):
+ bits = token.split_contents()[1:]
+
+ if len(bits) < 2:
+ raise template.TemplateSyntaxError("styleguideblock expected at "
+ "least two arguments")
+
+ elif len(bits) == 2:
+ styleguide, reference = bits
+ template_name = '"pykss/styleguideblock.html"'
+
+ elif len(bits) >= 3 and bits[2] != 'using':
+ raise template.TemplateSyntaxError("styleguideblock expected using "
+ "as the third argument")
+
+ elif len(bits) == 3:
+ raise template.TemplateSyntaxError("styleguideblock expects a "
+ "template name after 'using'")
+
+ else:
+ styleguide, reference, _using, template_name = bits
+
+ return cls.dispatch(parser, styleguide, reference, template_name)
+
+ @classmethod
+ def dispatch(cls, parser, styleguide, reference, template_name):
+ raise NotImplementedError
+
def render(self, context):
styleguide = self.styleguide.resolve(context)
reference = self.reference.resolve(context)
template_name = self.template_name.resolve(context)
- try:
- section = styleguide.section(reference)
- except Exception as e:
- if settings.TEMPLATE_DEBUG:
- raise e
- return ''
+ sections = [sec for ref, sec in styleguide.sections.iteritems()
+ if ref.startswith(reference)]
+
+ if self.nodelist:
+ example = self.nodelist.render(context).strip()
+ for section in sections:
+ section.add_example(example)
+
+ output = []
- example_html = self.nodelist.render(context).strip()
+ for section in sections:
+ context.update({'section': section})
+ html = render_to_string(template_name, context)
+ output.append(strip_spaces_between_tags(html))
+ context.pop()
- modifier_examples = []
- for modifier in section.modifiers:
- modifier_context = template.Context({
- 'modifier_class': ' %s' % modifier.class_name,
- })
- html = self.nodelist.render(modifier_context).strip()
- modifier_examples.append({
- 'modifier': modifier,
- 'html': mark_safe(html),
- })
+ return ''.join(output)
- context.update({
- 'section': section,
- 'example_html': mark_safe(example_html),
- 'modifier_examples': modifier_examples,
- 'escaped_html': escape(example_html),
- })
- output = render_to_string(template_name, context)
+class StyleguideBlockNode(BaseStyleguideNode):
- context.pop()
+ @classmethod
+ def dispatch(cls, parser, styleguide, reference, template_name):
+ nodelist = parser.parse(('endstyleguideblock',))
+ parser.delete_first_token()
+ return cls(
+ styleguide=parser.compile_filter(styleguide),
+ reference=parser.compile_filter(reference),
+ template_name=parser.compile_filter(template_name),
+ nodelist=nodelist,
+ )
- return output
+
+class RenderStyleguideNode(BaseStyleguideNode):
+
+ @classmethod
+ def dispatch(cls, parser, styleguide, reference, template_name):
+ return cls(
+ styleguide=parser.compile_filter(styleguide),
+ reference=parser.compile_filter(reference),
+ template_name=parser.compile_filter(template_name),
+ nodelist=None,
+ )
@register.tag
def styleguideblock(parser, token):
"""
{% styleguideblock styleguide "1.1" %}
- <button class="{{ modifier_class }}">Example Button</button>
+ <button class="$modifier_class">Example Button</button>
{% endstyleguideblock %}
{% styleguideblock styleguide "1.1" using "custom.html" %}
- <button class="{{ modifier_class }}">Example Button</button>
+ <button class="$modifier_class">Example Button</button>
{% endstyleguideblock %}
"""
- bits = token.split_contents()[1:]
-
- if len(bits) < 2:
- raise template.TemplateSyntaxError("styleguideblock expected at "
- "least two arguments")
-
- elif len(bits) == 2:
- styleguide, reference = bits
- template_name = '"pykss/styleguideblock.html"'
-
- elif len(bits) >= 3 and bits[2] != 'using':
- raise template.TemplateSyntaxError("styleguideblock expected using "
- "as the third argument")
+ return StyleguideBlockNode.as_tag(parser, token)
- elif len(bits) == 3:
- raise template.TemplateSyntaxError("styleguideblock expects a "
- "template name after 'using'")
- else:
- styleguide, reference, _using, template_name = bits
-
- nodelist = parser.parse(('endstyleguideblock',))
- parser.delete_first_token()
+@register.tag
+def renderstyleguide(parser, token):
+ """
+ {% renderstyleguide styleguide "1.1" %}
- return StyleguideBlockNode(
- styleguide=parser.compile_filter(styleguide),
- reference=parser.compile_filter(reference),
- template_name=parser.compile_filter(template_name),
- nodelist=nodelist,
- )
+ {% renderstyleguide styleguide "1.1" using "custom.html" %}
+ """
+ return RenderStyleguideNode.as_tag(parser, token)
diff --git a/pykss/modifier.py b/pykss/modifier.py
index 0c31dd1..969d164 100644
--- a/pykss/modifier.py
+++ b/pykss/modifier.py
@@ -3,7 +3,11 @@ class Modifier(object):
def __init__(self, name, description):
self.name = name
self.description = description
+ self.example = ''
@property
def class_name(self):
return self.name.replace('.', ' ').replace(':', ' pseudo-class-').strip()
+
+ def add_example(self, example):
+ self.example = example.replace('$modifier_class', ' %s' % self.class_name)
diff --git a/pykss/section.py b/pykss/section.py
index 9a98d0f..8f3ed1a 100644
--- a/pykss/section.py
+++ b/pykss/section.py
@@ -6,6 +6,7 @@ from pykss.modifier import Modifier
CLASS_MODIFIER = '.'
PSEUDO_CLASS_MODIFIER = ':'
MODIFIER_DESCRIPTION_SEPARATOR = ' - '
+EXAMPLE_START = 'Example:'
REFERENCE_START = 'Styleguide'
reference_re = re.compile('%s ([\d\.]+)' % REFERENCE_START)
@@ -20,8 +21,11 @@ class Section(object):
def parse(self):
self._description_lines = []
self._modifiers = []
+ self._example_lines = []
self._reference = None
+ in_example = False
+
for line in self.comment.splitlines():
if line.startswith(CLASS_MODIFIER) or line.startswith(PSEUDO_CLASS_MODIFIER):
try:
@@ -31,12 +35,21 @@ class Section(object):
else:
self._modifiers.append(Modifier(modifier.strip(), description.strip()))
+ elif line.startswith(EXAMPLE_START):
+ in_example = True
+
elif line.startswith(REFERENCE_START):
+ in_example = False
self._reference = reference_re.match(line).groups()[0].rstrip('.')
+
+ elif in_example is True:
+ self._example_lines.append(line)
+
else:
self._description_lines.append(line)
self._description = '\n'.join(self._description_lines).strip()
+ self.add_example('\n'.join(self._example_lines).strip())
@property
def description(self):
@@ -51,7 +64,18 @@ class Section(object):
return self._modifiers
@property
+ def example(self):
+ if not hasattr(self, '_modifiers'):
+ self.parse()
+ return self._example
+
+ @property
def section(self):
if not hasattr(self, '_reference'):
self.parse()
return self._reference
+
+ def add_example(self, example):
+ self._example = example.replace('$modifier_class', '')
+ for modifier in self._modifiers:
+ modifier.add_example(example)
diff --git a/tests/templates/django.html b/tests/templates/django.html
index 7c52f40..7a5cf38 100644
--- a/tests/templates/django.html
+++ b/tests/templates/django.html
@@ -8,11 +8,10 @@
["{{ modifier.name }}","{{ modifier.description }}"]{% if not forloop.last %},{% endif %}
{% endfor %}
],
- "example_html": "{{ example_html|escapejs }}",
+ "example_html": "{{ section.example|escapejs }}",
"modifier_examples": [
- {% for example in modifier_examples %}
- ["{{ example.modifier.name }}","{{ example.html|escapejs }}"]{% if not forloop.last %},{% endif %}
+ {% for modifier in section.modifiers %}
+ ["{{ modifier.name }}","{{ modifier.example|escapejs }}"]{% if not forloop.last %},{% endif %}
{% endfor %}
- ],
- "escaped_html": "{{ escaped_html|escapejs }}"
+ ]
}
diff --git a/tests/test_contrib/test_django/test_templatetags/test_pykss.py b/tests/test_contrib/test_django/test_templatetags/test_pykss.py
index f066499..d24f1ae 100644
--- a/tests/test_contrib/test_django/test_templatetags/test_pykss.py
+++ b/tests/test_contrib/test_django/test_templatetags/test_pykss.py
@@ -7,7 +7,6 @@ from django.utils import simplejson
from mock import patch, ANY
-from pykss.exceptions import SectionDoesNotExist
from pykss.parser import Parser
@@ -17,25 +16,14 @@ class StyleguideBlockTestCase(TestCase):
css = os.path.join(settings.PROJECT_ROOT, 'tests', 'fixtures', 'css')
self.styleguide = Parser(css)
- def test_when_section_does_not_exist_and_in_debug(self):
+ def test_when_section_does_not_exist(self):
template = Template("""
{% load pykss %}
{% styleguideblock styleguide "99" %}
{% endstyleguideblock %}
""")
context = Context({'styleguide': self.styleguide})
- self.assertRaises(SectionDoesNotExist, template.render, context)
-
- def test_when_section_does_not_exist_and_not_in_debug(self):
- with self.settings(TEMPLATE_DEBUG=False):
- template = Template("""
- {% load pykss %}
- {% styleguideblock styleguide "99" %}
- {% endstyleguideblock %}
- """)
- context = Context({'styleguide': self.styleguide})
- results = template.render(context)
- self.assertEqual(results.strip(), '')
+ self.assertEquals(template.render(context).strip(), '')
@patch('pykss.contrib.django.templatetags.pykss.render_to_string')
def test_uses_default_template(self, mock_render_to_string):
@@ -79,7 +67,7 @@ class StyleguideBlockTestCase(TestCase):
template = Template("""
{% load pykss %}
{% styleguideblock styleguide "2.1.1" using "django.html" %}
- <i class="main{{ modifier_class }}"></i>
+ <i class="main$modifier_class"></i>
{% endstyleguideblock %}
""")
context = Context({'styleguide': self.styleguide})
@@ -90,4 +78,8 @@ class StyleguideBlockTestCase(TestCase):
self.assertEqual(results['modifiers'][0], [':hover', 'Highlights when hovering.'])
self.assertEqual(results['example_html'], '<i class="main"></i>')
self.assertEqual(results['modifier_examples'][0], [':hover', '<i class="main pseudo-class-hover"></i>'])
- self.assertEqual(results['escaped_html'], '&lt;i class=&quot;main&quot;&gt;&lt;/i&gt;')
+
+
+#class RenderStyleguideTestCase(TestCase):
+
+# def test_renders_correctly(self):
diff --git a/tests/test_modifier.py b/tests/test_modifier.py
index 1e109d8..8acb594 100644
--- a/tests/test_modifier.py
+++ b/tests/test_modifier.py
@@ -13,3 +13,10 @@ class ModiferTestCase(unittest.TestCase):
def test_handles_multiple_classes(self):
self.assertTrue('callout extreme' in self.modifier.class_name)
+
+ def test_add_example(self):
+ example = '<i class="icon$modifier_class"></i>'
+ expected = '<i class="icon callout extreme pseudo-class-hover"></i>'
+
+ self.modifier.add_example(example)
+ self.assertEqual(self.modifier.example, expected)
diff --git a/tests/test_section.py b/tests/test_section.py
index 7ba8496..6ece110 100644
--- a/tests/test_section.py
+++ b/tests/test_section.py
@@ -16,6 +16,9 @@ Your standard form button.
.primary - Indicates button is the primary action.
.smaller - A smaller button
+Example:
+ <a href="button$modifier_class">Button</a>
+
Styleguide 2.1.1.
"""
self.section = Section(comment.strip(), 'example.css')
@@ -32,5 +35,8 @@ Styleguide 2.1.1.
def test_parses_modifier_descriptions(self):
self.assertEqual(self.section.modifiers[0].description, 'Highlights when hovering.')
+ def test_parses_the_example(self):
+ self.assertEqual(self.section.example, '<a href="button">Button</a>')
+
def test_parses_the_styleguide_reference(self):
self.assertEqual(self.section.section, '2.1.1')