Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve docs #7

Merged
merged 37 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
19012f7
Simplify first example use of get_context_data
tbrlpld Jan 5, 2024
400dc3a
Add sections about constructor arguments and dataclasses
tbrlpld Jan 7, 2024
e5373e5
Rework the intro section
tbrlpld Jan 7, 2024
5d64fba
Restructure the README
tbrlpld Jan 7, 2024
a9f62a2
Add example for parent context use
tbrlpld Jan 7, 2024
1f75d34
Update parent context explanations
tbrlpld Jan 7, 2024
9b2c351
Refine section on extra features of the component template tag
tbrlpld Jan 7, 2024
5685708
Fix sentence beginning
tbrlpld Jan 7, 2024
9b2cf2a
Move installation into a "getting started" section
tbrlpld Jan 13, 2024
13e3d23
Fix typo
tbrlpld Jan 13, 2024
0becf6c
Reduce repetition in sentence
tbrlpld Jan 13, 2024
74c7b5f
Simplify the first media example
tbrlpld Jan 13, 2024
fff12b7
Reorder example components
tbrlpld Jan 13, 2024
9ec7272
Test usage of media defining component
tbrlpld Jan 13, 2024
c61a8d3
Add more background on how to output media in templates
tbrlpld Jan 13, 2024
25e49f4
Add section about `MediaContainer`
tbrlpld Jan 13, 2024
953231d
Simplify sentence
tbrlpld Jan 13, 2024
aa80421
Add example for media container usage
tbrlpld Jan 14, 2024
7718660
Don't use title case
tbrlpld Jan 14, 2024
ca730b8
Expand dataclasses section a little
tbrlpld Jan 14, 2024
f7b1c62
Add section on custom constructor methods
tbrlpld Jan 15, 2024
6be0425
Add section on nested components
tbrlpld Jan 15, 2024
de07eae
Mention testing
tbrlpld Jan 15, 2024
486d68e
Add sections on nested groups and container components
tbrlpld Jan 18, 2024
891ed84
Rework the intro paragraph
tbrlpld Jan 18, 2024
4ce9f7b
Add name explainer
tbrlpld Jan 18, 2024
781f94c
Extra paragraph split in intro
tbrlpld Jan 18, 2024
26f28f6
Improve Slippers reference
tbrlpld Jan 18, 2024
25325f2
Move "supported version down
tbrlpld Jan 18, 2024
93a329e
Turn links more into TOC
tbrlpld Jan 18, 2024
ecbc798
Fix markup assertion for Django 3.2
tbrlpld Jan 22, 2024
a205093
Update changelog
tbrlpld Feb 1, 2024
57a3339
Unify changelog verbiage
tbrlpld Feb 1, 2024
8cecfc8
Blacken the docs
tbrlpld Feb 2, 2024
453ae4f
Add type hints to functions
tbrlpld Feb 10, 2024
dfd4529
Add type hints and better assertion to tests
tbrlpld Feb 10, 2024
9a83501
Move media assertion mixin to utils module
tbrlpld Feb 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add more tests and example usage. ([#6](https://github.com/tbrlpld/laces/pull/6))
- Added more tests and example usage. ([#6](https://github.com/tbrlpld/laces/pull/6))
- Added support for Python 3.12 and Django 5.0. ([#15](https://github.com/tbrlpld/laces/pull/15))
- Added type hints and type checking with `mypy` in CI. ([#18](https://github.com/tbrlpld/laces/pull/18))

### Changed

- Fixed tox configuration to actually run Django 3.2 in CI. Tox also uses the "testing" dependencies without the need to duplicate them in the `tox.ini`. ([#10](https://github.com/tbrlpld/laces/pull/10))
- Bumped GitHub Actions to latest versions. This removes a reliance on the now deprecated Node 16. ([#10](https://github.com/tbrlpld/laces/pull/10))
- Extend documentation in README to simplify first examples and improve structure. ([#7](https://github.com/tbrlpld/laces/pull/7))

### Removed

Expand Down
592 changes: 539 additions & 53 deletions README.md

Large diffs are not rendered by default.

70 changes: 54 additions & 16 deletions laces/test/example/components.py
tbrlpld marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@


if TYPE_CHECKING:
from typing import Any, Dict, Optional
from typing import Any, Dict, List, Optional

from django.utils.safestring import SafeString

Expand Down Expand Up @@ -109,6 +109,24 @@ def get_context_data(
}


class ListSectionComponent(Component):
template_name = "components/list-section.html"

def __init__(self, heading: "HeadingComponent", items: "List[Component]") -> None:
super().__init__()
self.heading = heading
self.items = items

def get_context_data(
self,
parent_context: "Optional[RenderContext]" = None,
) -> "RenderContext":
return {
"heading": self.heading,
"items": self.items,
}


class HeadingComponent(Component):
def __init__(self, text: str):
super().__init__()
Expand All @@ -133,31 +151,51 @@ def render_html(
return format_html("<p>{}</p>\n", self.text)


class ListSectionComponent(Component):
template_name = "components/list-section.html"

def __init__(self, heading: "HeadingComponent", items: "list[Component]"):
class BlockquoteComponent(Component):
def __init__(self, text: str):
super().__init__()
self.heading = heading
self.items = items
self.text = text

def render_html(
self,
parent_context: "Optional[RenderContext]" = None,
) -> "SafeString":
return format_html("<blockquote>{}</blockquote>\n", self.text)


class MediaDefiningComponent(Component):
template_name = "components/hello-name.html"

def get_context_data(
self,
parent_context: "Optional[RenderContext]" = None,
) -> "RenderContext":
return {
"heading": self.heading,
"items": self.items,
}
return {"name": "Media"}

class Media:
css = {"all": ("component.css",)}
js = ("component.js",)

class BlockquoteComponent(Component):
def __init__(self, text: str):
super().__init__()
self.text = text

class HeaderWithMediaComponent(Component):
def render_html(
self,
parent_context: "Optional[RenderContext]" = None,
) -> "SafeString":
return format_html("<blockquote>{}</blockquote>\n", self.text)
return format_html("<header>Header with Media</header>")

class Media:
css = {"all": ("header.css",)}
js = ("header.js", "common.js")


class FooterWithMediaComponent(Component):
def render_html(
self,
parent_context: "Optional[RenderContext]" = None,
) -> "SafeString":
return format_html("<footer>Footer with Media</footer>")

class Media:
css = {"all": ("footer.css",)}
js = ("footer.js", "common.js")
6 changes: 6 additions & 0 deletions laces/test/example/templates/pages/kitchen-sink.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<html>
<head>
<title>Kitchen Sink</title>
{{ media_defining_component.media }}
{{ components_with_media.media }}
</head>
<body>
{% component fixed_content_template %}
Expand All @@ -29,5 +31,9 @@

{% component section_with_heading_and_paragraph %}
{% component list_section %}
{% component media_defining_component %}
{% for comp in components_with_media %}
{% component comp %}
{% endfor %}
</body>
</html>
13 changes: 13 additions & 0 deletions laces/test/example/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

from django.shortcuts import render

from laces.components import MediaContainer
from laces.test.example.components import (
BlockquoteComponent,
DataclassAsDictContextComponent,
FooterWithMediaComponent,
HeaderWithMediaComponent,
HeadingComponent,
ListSectionComponent,
MediaDefiningComponent,
ParagraphComponent,
PassesFixedNameToContextComponent,
PassesInstanceAttributeToContextComponent,
Expand Down Expand Up @@ -43,6 +47,13 @@ def kitchen_sink(request: "HttpRequest") -> "HttpResponse":
ParagraphComponent(text="Item 3"),
],
)
media_defining_component = MediaDefiningComponent()
components_with_media = MediaContainer(
[
HeaderWithMediaComponent(),
FooterWithMediaComponent(),
]
)

return render(
request,
Expand All @@ -58,5 +69,7 @@ def kitchen_sink(request: "HttpRequest") -> "HttpResponse":
"name": "Dan", # Provide as an example of parent context.
"section_with_heading_and_paragraph": section_with_heading_and_paragraph,
"list_section": list_section,
"media_defining_component": media_defining_component,
"components_with_media": components_with_media,
},
)
24 changes: 24 additions & 0 deletions laces/test/tests/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
desired. More thorough tests can be found in the `laces.tests.test_components` module.
"""

from django.forms import widgets
from django.test import SimpleTestCase

from laces.test.example.components import (
DataclassAsDictContextComponent,
HeadingComponent,
ListSectionComponent,
MediaDefiningComponent,
ParagraphComponent,
PassesFixedNameToContextComponent,
PassesInstanceAttributeToContextComponent,
Expand All @@ -20,6 +22,7 @@
ReturnsFixedContentComponent,
SectionWithHeadingAndParagraphComponent,
)
from laces.tests.utils import MediaAssertionMixin


class TestRendersTemplateWithFixedContentComponent(SimpleTestCase):
Expand Down Expand Up @@ -250,3 +253,24 @@ def test_render_html(self) -> None:
</section>
""",
)


class TestMediaDefiningComponent(MediaAssertionMixin, SimpleTestCase):
def setUp(self) -> None:
self.component = MediaDefiningComponent()

def test_media(self) -> None:
self.assertMediaEqual(
self.component.media,
widgets.Media(
css={
"all": [
"component.css",
]
},
js=[
"component.js",
"test.js",
],
),
)
43 changes: 43 additions & 0 deletions laces/test/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from http import HTTPStatus

import django

from django.test import RequestFactory, TestCase

from laces.test.example.views import kitchen_sink
Expand Down Expand Up @@ -54,3 +56,44 @@ def test_get(self) -> None:
""",
response_html,
)
self.assertInHTML("<h1>Hello Media</h1>", response_html)
if django.VERSION < (4, 0):
# Before Django 4.0 the markup was including the (useless)
# `type="text/css"` attribute.
self.assertInHTML(
'<link href="/static/component.css" type="text/css" media="all" rel="stylesheet">', # noqa: E501
response_html,
)
else:
self.assertInHTML(
'<link href="/static/component.css" media="all" rel="stylesheet">',
response_html,
)
self.assertInHTML('<script src="/static/component.js"></script>', response_html)
self.assertInHTML("<header>Header with Media</header>", response_html)
self.assertInHTML("<footer>Footer with Media</footer>", response_html)
if django.VERSION < (4, 0):
self.assertInHTML(
'<link href="/static/header.css" type="text/css" media="all" rel="stylesheet">', # noqa: E501
response_html,
)
self.assertInHTML(
'<link href="/static/footer.css" type="text/css" media="all" rel="stylesheet">', # noqa: E501
response_html,
)
else:
self.assertInHTML(
'<link href="/static/header.css" media="all" rel="stylesheet">',
response_html,
)
self.assertInHTML(
'<link href="/static/footer.css" media="all" rel="stylesheet">',
response_html,
)
self.assertInHTML('<script src="/static/header.js"></script>', response_html)
self.assertInHTML('<script src="/static/footer.js"></script>', response_html)
self.assertInHTML(
'<script src="/static/common.js"></script>',
response_html,
count=1,
)
27 changes: 1 addition & 26 deletions laces/tests/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.utils.safestring import SafeString

from laces.components import Component, MediaContainer
from laces.tests.utils import MediaAssertionMixin


if TYPE_CHECKING:
Expand All @@ -19,32 +20,6 @@
from laces.typing import RenderContext


class MediaAssertionMixin:
@staticmethod
def assertMediaEqual(first: widgets.Media, second: widgets.Media) -> bool:
"""
Compare two `Media` instances.

The `Media` class does not implement `__eq__`, but its `__repr__` shows how to
recreate the instance.
We can use this to compare two `Media` instances.

Parameters
----------
first : widgets.Media
First `Media` instance.
second : widgets.Media
Second `Media` instance.

Returns
-------
bool
Whether the two `Media` instances are equal.

"""
return repr(first) == repr(second)


class TestComponent(MediaAssertionMixin, SimpleTestCase):
"""Directly test the Component class."""

Expand Down
29 changes: 29 additions & 0 deletions laces/tests/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Utilities for tests in the `laces` package."""

from django.forms import widgets


class MediaAssertionMixin:
@staticmethod
def assertMediaEqual(first: widgets.Media, second: widgets.Media) -> bool:
"""
Compare two `Media` instances.

The `Media` class does not implement `__eq__`, but its `__repr__` shows how to
recreate the instance.
We can use this to compare two `Media` instances.

Parameters
----------
first : widgets.Media
First `Media` instance.
second : widgets.Media
Second `Media` instance.

Returns
-------
bool
Whether the two `Media` instances are equal.

"""
return repr(first) == repr(second)
Loading