Skip to content

Instantly share code, notes, and snippets.

@Bost
Forked from attentive/conduit.clj
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bost/0f3e66e5138b2e3a45aa to your computer and use it in GitHub Desktop.
Save Bost/0f3e66e5138b2e3a45aa to your computer and use it in GitHub Desktop.
clojure; enlive - dynamic deftemplate
(ns gist.conduit
(:require [net.cgrand.enlive-html :as html]
[net.cgrand.tagsoup :as tagsoup]))
; The implementations of conduit and defconduit are modified versions of
; the macros template and deftemplate from the guts of Enlive.
; They're named 'conduit' because the selectors and transformations serve as a
; channel between the scaffold of HTML and some data provided as an argument.
; Tagsoup is used to parse a list of HTML nodes from a specified input file at runtime.
(defmacro conduit
[args & forms]
(let [[& body] (list* args forms)]
`(fn [source# ~@args]
(let [nodes# (tagsoup/parser (clojure.java.io/reader source#))]
(html/emit* ((html/snippet* nodes# ~@body) ~@args))))))
(defmacro defconduit
"Defines a group of selectors and transformations to be applied to
a nominated HTML template and arguments."
[name args & forms]
`(def ~name (conduit ~args ~@forms)))
; An example …
(defconduit page
[page-data]
[:head :title] (content (:title page-data))
[:body :div#main] (content (:body page-data)))
; And this is how you use it …
#_(apply str
(page "/path/to/some/file.html"
{:title "This title will be inserted"
:body "As will this body content, if there's a div in the input with id 'main'."}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment