diff options
| author | Sean Brant | 2013-03-13 22:23:50 -0500 | 
|---|---|---|
| committer | Sean Brant | 2013-03-13 22:23:50 -0500 | 
| commit | c7d7aad2913d666a9ad09d74976bb90eff03acd1 (patch) | |
| tree | 2085154feb77942ef8760f9c4eb4486cc24687f7 | |
| parent | 083e4dd9ed498ba2ef5133943fadb1fab7e71276 (diff) | |
| download | pykss-c7d7aad2913d666a9ad09d74976bb90eff03acd1.tar.bz2 | |
Adds support for adding examples inside comments
| -rw-r--r-- | examples/djangoproject/djangoproject/static/css/forms.css | 12 | ||||
| -rw-r--r-- | examples/djangoproject/djangoproject/templates/base.html | 1 | ||||
| -rw-r--r-- | examples/djangoproject/djangoproject/templates/styleguide.html | 21 | ||||
| -rw-r--r-- | pykss/contrib/django/templates/pykss/styleguideblock.html | 10 | ||||
| -rw-r--r-- | pykss/contrib/django/templatetags/pykss.py | 137 | ||||
| -rw-r--r-- | pykss/modifier.py | 4 | ||||
| -rw-r--r-- | pykss/section.py | 24 | ||||
| -rw-r--r-- | tests/templates/django.html | 9 | ||||
| -rw-r--r-- | tests/test_contrib/test_django/test_templatetags/test_pykss.py | 24 | ||||
| -rw-r--r-- | tests/test_modifier.py | 7 | ||||
| -rw-r--r-- | tests/test_section.py | 6 | 
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" %} -    <button class="{{ modifier_class }}">Example Button</button> +    <button class="$modifier_class">Example Button</button>  {% 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'], '<i class="main"></i>') + + +#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') | 
