An attempt to make something similar to the motivation behind Swift's Result Builders proposal. Note that this is not a good way to actually design an HTML library -- see more here.
-
-
Save lsh/6ca8864a9cffef9e503d6262eb876893 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from utils.variant import Variant | |
from collections.dict import Dict | |
from collections.list import List | |
trait Htmlable: | |
fn render_as_html(self, inout stream: String): | |
... | |
@value | |
struct HtmlNode(Htmlable): | |
var tag: String | |
var attributes: Dict[String, String] | |
var children: List[Html] | |
fn __init__(inout self, tag: String, *children: Html, **attributes: String): | |
var children_ = List[Html]() | |
for child in children: | |
children_.append(child[]) | |
self.children = children_ | |
self.tag = tag | |
self.attributes = attributes._dict | |
fn render_as_html(self, inout stream: String): | |
stream += "<" | |
stream += self.tag | |
for item in self.attributes.items(): | |
stream += " " | |
stream += item[].key | |
stream += '="' | |
stream += item[].value | |
stream += '"' | |
if len(self.children) == 0: | |
stream += "/>" | |
else: | |
stream += ">" | |
for child in self.children: | |
child[].render_as_html(stream) | |
stream += "</" | |
stream += self.tag | |
stream += ">" | |
@value | |
struct Html(Htmlable): | |
alias _type = Variant[String, HtmlNode] | |
var data: Self._type | |
@always_inline | |
fn render_as_html(self, inout stream: String): | |
if self.data.isa[String](): | |
stream += self.data.get[String]()[] | |
else: | |
var node = self.data.get[HtmlNode]() | |
node[].render_as_html(stream) | |
fn __init__(inout self, node: HtmlNode): | |
self.data = node | |
fn __init__(inout self, text: String): | |
self.data = text | |
fn __init__(inout self, text: StringLiteral): | |
self.data = str(text) | |
@always_inline | |
fn Division(*children: Html, **attributes: String) -> Html: | |
var children_ = List[Html]() | |
for child in children: | |
children_.append(child[]) | |
return HtmlNode(tag="div", children=children_, attributes=attributes._dict) | |
@always_inline | |
fn Paragraph(*children: Html, **attributes: String) -> Html: | |
var children_ = List[Html]() | |
for child in children: | |
children_.append(child[]) | |
return HtmlNode(tag="p", children=children_, attributes=attributes._dict) | |
@always_inline | |
fn Body(*children: Html, **attributes: String) -> Html: | |
var children_ = List[Html]() | |
for child in children: | |
children_.append(child[]) | |
return HtmlNode(tag="body", children=children_, attributes=attributes._dict) | |
@always_inline | |
fn Header1(*children: Html, **attributes: String) -> Html: | |
var children_ = List[Html]() | |
for child in children: | |
children_.append(child[]) | |
return HtmlNode(tag="h1", children=children_, attributes=attributes._dict) | |
fn render() -> String: | |
var maybe_maybe = True | |
var stream = String() | |
Body( | |
Division( | |
Header1("Chapter 1. Loomings."), | |
Paragraph("Call me Ishmael. Some years ago"), | |
Paragraph( | |
"There is now your insular city", | |
style="padding-top: 5px", | |
), | |
style="background: #ccc; border: 1px solid black;", | |
), | |
Division( | |
Header1("Chapter 2. The Carpet-Bag."), | |
Paragraph("I stuffed a shirt or two"), | |
style="margin-top: 5px;", | |
), | |
"Heya!" if maybe_maybe else "", | |
).render_as_html(stream) | |
return stream | |
fn main(): | |
print(render()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment