Skip to content

Commit 2c43d96

Browse files
refactor and clean up slot templatetag (#161)
1 parent 17a5ed4 commit 2c43d96

File tree

2 files changed

+37
-41
lines changed

2 files changed

+37
-41
lines changed

src/django_bird/templatetags/tags/slot.py

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@
22
from __future__ import annotations
33

44
from typing import cast
5+
from typing import final
56

67
from django import template
78
from django.template.base import NodeList
89
from django.template.base import Parser
910
from django.template.base import Token
1011
from django.template.context import Context
1112
from django.utils.safestring import SafeString
12-
from django.utils.safestring import mark_safe
1313

14-
from django_bird._typing import TagBits
1514
from django_bird._typing import override
1615

1716
TAG = "bird:slot"
@@ -21,52 +20,42 @@
2120

2221

2322
def do_slot(parser: Parser, token: Token) -> SlotNode:
24-
bits = token.split_contents()
25-
name = parse_slot_name(bits)
26-
nodelist = parse_nodelist(parser)
27-
return SlotNode(name, nodelist)
28-
29-
30-
def parse_slot_name(bits: TagBits) -> str:
31-
if len(bits) == 1:
32-
return DEFAULT_SLOT
33-
elif len(bits) == 2:
34-
name = bits[1]
35-
if name.startswith("name="):
36-
name = name.split("=")[1]
37-
else:
38-
name = name
39-
return name.strip("'\"")
40-
else:
41-
msg = f"{TAG} tag requires either no arguments, one argument, or 'name=\"slot_name\"'"
23+
_tag, *bits = token.split_contents()
24+
if len(bits) > 1:
25+
msg = f"{TAG} tag requires either one or no arguments"
4226
raise template.TemplateSyntaxError(msg)
4327

28+
if len(bits) == 0:
29+
name = DEFAULT_SLOT
30+
else:
31+
name = bits[0]
32+
if name.startswith("name="):
33+
_, name = name.split("=")
34+
name = name.strip("'\"")
4435

45-
def parse_nodelist(parser: Parser) -> NodeList:
4636
nodelist = parser.parse((END_TAG,))
4737
parser.delete_first_token()
48-
return nodelist
38+
39+
return SlotNode(name, nodelist)
4940

5041

42+
@final
5143
class SlotNode(template.Node):
5244
def __init__(self, name: str, nodelist: NodeList):
5345
self.name = name
5446
self.nodelist = nodelist
5547

5648
@override
5749
def render(self, context: Context) -> SafeString:
58-
default_content: str = self.nodelist.render(context)
5950
slots = context.get("slots")
6051

6152
if not slots or not isinstance(slots, dict):
62-
return mark_safe(default_content)
53+
return self.nodelist.render(context)
6354

6455
slots_dict = cast(dict[str, str], slots)
6556
slot_content = slots_dict.get(self.name)
6657

6758
if slot_content is None or slot_content == "":
68-
return mark_safe(default_content)
59+
return self.nodelist.render(context)
6960

70-
t = template.Template(slot_content)
71-
content = t.render(context)
72-
return mark_safe(content)
61+
return template.Template(slot_content).render(context)

tests/templatetags/test_slot.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,39 @@
33
import pytest
44
from django.template import Context
55
from django.template import Template
6+
from django.template.base import Parser
7+
from django.template.base import Token
8+
from django.template.base import TokenType
69
from django.template.exceptions import TemplateSyntaxError
710

8-
from django_bird.templatetags.tags.slot import parse_slot_name
11+
from django_bird.templatetags.tags.slot import DEFAULT_SLOT
12+
from django_bird.templatetags.tags.slot import END_TAG
13+
from django_bird.templatetags.tags.slot import TAG
14+
from django_bird.templatetags.tags.slot import SlotNode
15+
from django_bird.templatetags.tags.slot import do_slot
916
from tests.utils import TestComponent
1017
from tests.utils import TestComponentCase
1118
from tests.utils import normalize_whitespace
1219

1320

1421
@pytest.mark.parametrize(
15-
"bits,expected",
22+
"contents,expected",
1623
[
17-
(["slot"], "default"),
18-
(["slot", "foo"], "foo"),
19-
(["slot", "'foo'"], "foo"),
20-
(["slot", '"foo"'], "foo"),
21-
(["slot", 'name="foo"'], "foo"),
22-
(["slot", "name='foo'"], "foo"),
24+
("", SlotNode(name=DEFAULT_SLOT, nodelist=None)),
25+
("foo", SlotNode(name="foo", nodelist=None)),
26+
("'foo'", SlotNode(name="foo", nodelist=None)),
27+
('"foo"', SlotNode(name="foo", nodelist=None)),
28+
('name="foo"', SlotNode(name="foo", nodelist=None)),
29+
("name='foo'", SlotNode(name="foo", nodelist=None)),
2330
],
2431
)
25-
def test_parse_slot_name(bits, expected):
26-
assert parse_slot_name(bits) == expected
32+
def test_parse_slot_name(contents, expected):
33+
start_token = Token(TokenType.BLOCK, f"{TAG} {contents}")
34+
end_token = Token(TokenType.BLOCK, END_TAG)
2735

36+
node = do_slot(Parser([end_token]), start_token)
2837

29-
def test_parse_slot_name_no_args():
30-
with pytest.raises(TemplateSyntaxError):
31-
assert parse_slot_name([])
38+
assert node.name == expected.name
3239

3340

3441
class TestTemplateTag:

0 commit comments

Comments
 (0)