Swiccup

I’ve been playing around with some server-side Swift the past couple of days. One of the things I really enjoyed when playing with ClojureScript was the Hiccup library. Sure, all the cool kids might be using something else, but all the time invested in templating languages felt like time spent on the wrong problem. I personally would rather just write the code to construct the view. To each their own, I guess.

If you’ve not played with Hiccup, it basically looks like this:


(html [:ul
(for [x (range 1 4)]
[:li x])])

view raw

html.cljs

hosted with ❤ by GitHub

That will generate the HTML:


<ul><li>1</li><li>2</li><li>3</li></ul>

view raw

output.html

hosted with ❤ by GitHub

Well, I wanted something similar in Swift. I’m still playing around a bit, but this is what I’ve got so far:


html([
body([
h1(["class": "welcome"],
["Welcome to Swiccup"]),
div(["This is only the beginning!"]),
ol((1…4).map() {
li([string("item #\($0)")]) })])])

view raw

swiccup.swift

hosted with ❤ by GitHub

The above generates the following HTML:


<html>
<body>
<h1 class="welcome">Welcome to Swiccup</h1>
<div>This is only the beginning!</div>
<ol>
<li>item #1</li>
<li>item #2</li>
<li>item #3</li>
<li>item #4</li>
</ol>
</body>
</html>

view raw

output.html

hosted with ❤ by GitHub

I call it Swiccup.

So far, it’s working out alright. Though, I’m not terribly happy with implementation side of things. There is a lot of duplicated code. So much so, that after I’m done with the prototyping, the only reasonable thing to do is to write a code generator for it.

You know, like I’d do with C++. 😝

Improving the Flow

 

However, the code was still too clunky. In order for this to actually be useful, it needs to be streamlined and as much as the syntax needs to be removed as much as possible. So I came up with this:


html |>
body |>
[h1(["class": "welcome"]) |> "Welcome to Swiccup",
div |> "This is only the beginning!",
ol |> (1…4).map() {
li([string("item #\($0)")])
}]

view raw

swiccup2.swift

hosted with ❤ by GitHub

I’m pretty happy with the above usage. Unfortunately, I still have that errant call to string() that I cannot get rid of. For some reason, within the closure, Swift is unable to convert my string literal properly to an HtmlElement.

Implementation Woes

Like I briefly mentioned above though, the implementation sucks. Maybe I can do this a little better, but at first pass, I need the three following functions to make this work:


public func h1(_ attributes: [String:String]) -> ([HtmlElement]) -> HtmlElement {
return { content in return HtmlElement.Node(tagName: "h1", attributes: attributes, content: content) }
}
public func h1(_ attributes: [String:String], _ content: [HtmlElement]) -> HtmlElement {
return h1(attributes)(content)
}
public func h1(_ content: [HtmlElement]) -> HtmlElement {
return h1([:], content)
}

view raw

h1.swift

hosted with ❤ by GitHub

The first is is to allow for partial application. This is the magic function that allows the |> operator to work as the left hand side expects a function signature of: ([HtmlElement]) -> HtmlElement. And since Swift cannot do partial applications automatically, we need to hand roll it.

The next second function is the full signature. Now, you might ask why not put the attributes parameter at the end and mark it with a default value. Surely, that would reduce this boiler plate code, right?

Well… yes, but the API call would be backwards. I don’t want to group the nested children before configuring all of the details of the the current element. So, this means that I end up with three different functions.

The real problem is that I need one of these functions for every single HTML tag I want to support. This is where I really wish Swift had a proper macro or meta programming surface to make use of. Instead, I’ll be writing a simple code generator that will generate all of these methods for me.

 

Swiccup

2 thoughts on “Swiccup

Comments are closed.