Clojure templating

What do people use for generating clojure code to write to file from clojure? The best I’ve come up with so far is:

(->> (let [bar "baz"]
       (str `(~'ns ~(symbol (str "foo." bar)))
            "\n"
            "\n"
            `(~'def ~'input (~'slurp ~(str bar ".txt")))))
     (spit "foo.clj"))

Anyone have a better approach?

You can use clojure.template which is part of core Clojure: https://clojure.github.io/clojure/clojure.template-api.html

Or this backtick library: https://github.com/brandonbloom/backtick

And because I’m a maniac, I might also just use cl-format: https://clojuredocs.org/clojure.pprint/cl-format

2 Likes

You kind of have two main approaches, the LISP way or the text way.

The beauty of the LISP way is that (= code data), so you can generate some s-expressions and print them out. The downside is that you have no control over formatting, but you can generate the unformatted version first and then run a code formatter over that like zprint.

Another annoying thing is that syntax quote actually does more than what you want for this use case, which is why you end up with all of those ~' in your code. As @didibus mentioned this is a sign you want to look at the backtick library, especially backtick/template.

Or you use something like Mustache, which is actually what most Leiningen templates do. You get a lot more control over formatting this way, and you can print out things that aren’t really homoiconic (what if you want to generate code which contains backticks and reader conditionals?), but getting whitespace right is still a huge pain. When creating Chestnut I put a lot of effort into generating correctly formatted code because it annoyed me a lot when templates didn’t do this, and boy it is not fun. Probably still better to just run a formatter over it afterwards :slight_smile:

1 Like

Yeah, I was trying to keep things as data. I assumed having to ~' was because I was missing something obvious. :sweat_smile:

Thanks for the more in depth explanation. :smiley: