Awhile back I released
OMG! SMACKDOWN!!!, which
still holds the title for dumbest Clojure app in existence. To make up
for that ludicrostrosity, I've created
Grateful Place. This time I around I
didn't use Noir, instead going closer to the metal with Compojure and
Enlive. The experience was a lot easier than I anticipated, perhaps
easier than using Noir. This post will cover some of the more
interesting bits of code:

Templating heaven with Enlive and Middleman

Using macros to enforce full stack consistency

Roll-your-own validations

Pagination is more fun with macros

Using fierce mustaches to run tasks

Fun utilities

You can find all source code on
github. Also,
I'm going to be at the Clojure Conj and would love do meet folks. If
you'd like to chat, please do tweet me (@nonrecursive) or find me at
the conj!

App Overview

Grateful Place is a social app with only a few models: Users,
Comments, Posts, and Likes. Nothing too fancy. If you're interested in
why I made it, here's a post I wrote about
gratitude.

Templating heaven with Enlive and Middleman

Enlive is the bee's knees

I can say without reservation that
[Enlive]:(https://github.com/cgrand/enlive) is the best templating
library I've ever used. I absolutely love it! If you try out one thing
from this post, try out the workflow I describe here. Enlive is
completely different from Hiccup, ERB, HAML and the like and it's
worth giving it a shot.

If you're not familiar with Enlive, it's a selector-based templating
library. In the same way that CSS allows you to separate structure and
presentation, Enlive lets you separate structure and view logic. This
is huge! Unless you're the kind of person who still likes to use
@font@ and @bold@ tags in your HTML, you should give Enlive a try.

Middleman/Enlive Workflow

Using Enlive allowed me to do all my design work using the Ruby
library Middleman. This allowed me to
build stand-alone web pages so that I could see how they looked
without worrying about any view logic. For example, here's the example
home page I put together:

You might have noticed a few weird things. First, this is written
using HAML. Yep, HAML. I prefer HAML over HTML because it's more
concise and the consistent structure allows me to visually scan it
more easily. And since my HTML templates and view logic are completely
separate, I can write my designs in HAML, preview them with Middleman,
and then generate an HTML file for Enlive to work with. Here's my
process in full:

Build on every change by cd'ing to assets/generator/ and running
fswatch . ./g. This runs a bash script which generates the HTML,
CSS, and Javascript files and moves them to the proper directories.

Start up Middleman by cd'ing to assets/generator/ and running
middleman

View site at http://localhost:4567 and make changes to my heart's
content

When I'm happy with the changes, create or recompile a Clojure file
which makes use of the HTML file with Enlive. It's necessary to
recompile the files so that Enlive uses the updated HTML. That
doesn't happen automatically.

Another thing you might have noticed is that in the HAML file I'm
showing two example posts. With Enlive, you actually have to add some
logic to remove one of the post divs:

(defpageall"index.html"[postscurrent-authrecord-countpagemax-pages];; don't show the second post as it's just an example[[:.post(h/nth-of-type2)]]nil

The ultimate purpose of this code is the defpage macro. This helps
me in a few ways. It lets me easily write view code for each page
without having to worry about the surrounding layout. For example,
before writing the above code I had to include the navigation
transformations in every page, which quickly got annoying.

The defpage macro also bundles up the template-dir variable,
saving me some keystrokes and some duplication. Finally, it
establishes a consistent way of interacting with the controller, a
topic I'll explore more in the next section. Before that, here's an
example of defpage in action:

As you can see, each route captures variables in a completely
different way. At first I thought this made sense; I was passing
exactly the data that was needed to each controller.

However, this quickly became a pain in the ass. For example, if I
wanted to make a request param available to a view, I had to modify
functions all up and down the stack: in the routes, in the controller
function, and in the view function. I ended up making all routes send
the full request object to their functions:

The @route@ macro is very handy. It saves me from typing and (for the most part) from burning precious brain cells on thinking, and it enforces the "send the full request" constraint by not allowing me to deviate. Of course, I can still deviate, and this is useful if you're using a library:

(friend/logout(ANY"/logout"[](ring.util.response/redirect"/")))

If I want to get to the params, I just use a let; no big deal:

(defn show[req](let [id(get-inreq[:params:id])

Creating a controller->view interface

In the same way that it was useful to create a route->controller
interface, it became useful to create a controller->view
interface. That was accomplished with this macro:

(defmacro view"provides defaults for the map provided to view functions and allows you to provide additional key value pairs. Assumes that a variable named req exists"[view-fn&keys]`(let [x#{:current-auth(friend/current-authentication):errors{}:params(:params~'req):req~'req}](~view-fn(into x#(map vec(partition2~(veckeys)))))))

This also helped with one weird problem I ran into with cemerick's
friend library where (friend/current-authentication) returns nil
from within an anonymous function (and there are many anonymous
functions in my view code). I could circumvent this problem by
assigning doing something like (let
[current-auth (friend/current-authentication)]). But it seemed to
make more sense to just always pass that data along when calling view
functions, as you can see in the macro above.

The defpage macro also helped in establishing this interface in that
it allowed me to destructure the arguments sent by the controller. For
example, if a controller had

(viewposts/show{:postpost})

I could create the corresponding view with

(defpageshow[postcurrent-authentication])

And I wouldn't even have to worry about the order of the arguments. It
really reduced some "incidental complexity" (and I'm almost certainly
using that term incorrectly).

Roll-your-own validations

It wasn't too difficult to write my own way of doing validations, and
I'm satisfied with it for now. Here's a description of the data
structure, with an example following:

Validation: a combination of a key and "validation check groups"

Validation check group: first element is an error message and the
rest are "validation checks". If any validation check returns false
then the error message is added to a list of error messages for the
given key.

Validation check: a boolean function to apply to one of a record's
values. The value corresponds to the validation key

if-valid wasn't strictly necessary but I made it and ended up liking
it. It's a small improvement, but a handy one.

Pagination is more fun with macros

It was a bit difficult for me to pull the pagination code together. I
tried many approaches, and I'm not 100% satisfied with what I have,
but it's better than nothing! The basic approach was to add a couple
Korma clauses to a base set of clauses. Here are the base clauses,
along with a macro that allows me to add more clauses willy-nilly:

I definitely think there's room for improvement here and would love
suggestions.

Using fierce mustaches to run tasks

So it turns out that you can use leiningen to run tasks, kind of like
Rake. As far as I know, it's not as powerful in that you can't specify
dependencies, but it's still better than nothing! Here's a file I
wrote to allow me to rebuild and re-seed by db:

The End

And that's it! I hope you've found this useful. I'd love any feedback,
so please do leave a comment or tweet me or email me. And like I
mentioned above - it'd be great to meet some folks at the Conj next
week!