A Reference to Fabricate's Page Templates

This page has an informal explanation of the parts that make up a Fabricate page, using inputs and outputs paired together for demonstration purposes.

A formal definition of the grammar is included in the documentation for the site.fabricate.prototype.read.grammar namespace.

Basic Expressions

An expression starts and ends with the asterisk and END emojis: ✳🔚. You can then use some optional control characters to change how that expression will be used by Fabricate. All expressions in those emoji will be evaluated after Fabricate reads the page template and parses it.

One thing that makes Fabricate different is the fact that templates can appear anywhere in the text. So if you wanted to write a sentence generated by a Clojure program in the middle of an ordinary paragraph, you can do that. If you want to define a variable naming all the sections and write a sentence like "this page has 3 sections," you can do that. Fabricate, by default, uses inline expressions instead of Markdown.

✳ - Run expressions

If you don't specify any additional characters, Fabricate evaluates the expression without putting the result in the page.

Useful for: namespace declarations, variable definitions, and other side effects - anything where you don't need to see the result of what you run.

Examples
✳(ns my-demo-ns (:require [site.fabricate.prototype.page :as page]))🔚
✳(def metadata {:title "My page"})🔚


✳= - Yield expressions

If you add the "=" character after the asterisk - ✳=, the expression's results get added into the page. Hiccup expressions, like [:code "example inline code"] are included in the document tree and will be transformed into HTML all at once after the document is evaluated.

Useful for: anything you'd use HTML for.

Examples
✳=[:code {:class "language-clojure"} "(map inc (range 40 29 -1))"]🔚

(map inc (range 40 29 -1))

✳=[:figure [:blockquote "People are alive -- they behave and respond. Creations within the computer can also live, behave, and respond... if they are allowed to."] [:figcaption "Bret Victor, " [:a {:href "https://vimeo.com/64895205"} [:em "Stop Drawing Dead Fish"]]]]🔚
People are alive -- they behave and respond. Creations within the computer can also live, behave, and respond... if they are allowed to.
Bret Victor, Stop Drawing Dead Fish
✳=[:img {:src "https://live.staticflickr.com/3770/11073365765_6dd38cce29_z.jpg"}]🔚


✳+Insert expressions

Use this for when you want to evaluate some code and insert the expression into the result, but not its output.

Useful for: when you want to demonstrate some code that contributes to the page but its output isn't important. You could show the code used to define a variable, but use the the contents of that variable later on in the page. It's also useful for instructive function definitions, where the return value of a function definition is just a var.

Examples
✳+(defn de-jong "Returns a Peter de Jong attractor function. Use with iterate." [a b c d] (fn [[x y]] [(- (Math/sin (* a y)) (Math/cos (* b x))) (- (Math/sin (* c x)) (Math/cos (* d y)))]))🔚
(defn de-jong "Returns a Peter de Jong attractor function. Use with iterate." [a b c d] (fn [[x y]] [(- (Math/sin (* a y)) (Math/cos (* b x))) (- (Math/sin (* c x)) (Math/cos (* d y)))]))
✳+(defn clifford "Returns a Clifford attractor function. Use with iterate." [a b c d] (fn [[x y]] [(- (Math/sin (* a y)) (* c (Math/cos (* a x)))) (- (Math/sin (* b x)) (* d (Math/cos (* b y))))]))🔚
(defn clifford "Returns a Clifford attractor function. Use with iterate." [a b c d] (fn [[x y]] [(- (Math/sin (* a y)) (* c (Math/cos (* a x)))) (- (Math/sin (* b x)) (* d (Math/cos (* b y))))]))
✳+(def de-jong-example (de-jong 1.517 -2.001 3.45 2.07))🔚
(def de-jong-example (de-jong 1.517 -2.001 3.45 2.07))
✳+(def clifford-example (clifford 1.24 1.14 1.23 1.89))🔚
(def clifford-example (clifford 1.24 1.14 1.23 1.89))


✳+=Composing control characters

You can use both the "+" and "=" characters together to display a form along with its output.

Useful for: showing off your art alongside the code that produced it.

Examples
✳+=(let [w 300 h 400] (into [:svg {:width w, :id "de-jong-fractal", :height h}] (map (fn [[^{Double true} x ^{Double true} y]] [:circle {:r 1.0, :style {:fill "#606456", :opacity 0.3}, :cx (* w (+ 0.5 (/ x 4.0))), :cy (* h (+ 0.5 (/ y 5.0)))}]) (take 15000 (iterate de-jong-example [1.4 3.9])))))🔚
✳+=(let [w 300 h 400] (into [:svg {:width w, :id "clifford-fractal", :height h}] (map (fn [[^{Double true} x ^{Double true} y]] [:circle {:r 1.0, :style {:fill "#606456", :opacity 0.3}, :cx (* w (+ 0.5 (/ x 4.0))), :cy (* h (+ 0.5 (/ y 5.0)))}]) (take 15000 (iterate clifford-example [1.4 3.9])))))🔚


Interlude: (code) documentation as data

Not only do these examples illustrate how Fabricate's control characters work, they also show how you can build up components of a page by defining them as variables in Clojure and then using them to produce page elements. I was able to use Flexbox attributes to tailor the layout to my examples without tying the whole page to a single way of displaying things. The example expressions above were defined not as ossified strings in a fenced code block, but as quoted Clojure expressions, some of which were evaluated to produce this page. If they encountered an error on evaluation, an error would have surfaced in the page as I was drafting it. Can you be assured of that when putting example code in Markdown documents?

Extended form expressions

Sometimes it's preferable to group multiple forms together along with paragraphs of plain text into a single section. In order to do this without embedding many paragraphs in a single large Fabricate expression, Fabricate also supports extended forms. They allow you to mark the start and end points of an element in a document and continue working within that element normally using Fabricate's mix of plain text and expressions.

Form Definition

✳// [:section {:class "chapter"}

Text in a "chapter" section. Embedded expressions can be included as well, like ✳=[:em "emphasized text."] 🔚

]//🔚


Results


Text in a "chapter" section. Embedded expressions can be included as well, like emphasized text.

A longer example document: this page

This page itself uses many of the "useful for" tips I mentioned in the first section. You might find the source code of the page instructive, so it is included below:

(ns site.fabricate.docs.reference.templates (:require [clojure.string :as str] [site.fabricate.prototype.read :as read] [site.fabricate.prototype.write :as write] [site.fabricate.prototype.read.grammar :as grammar] [garden.core :as garden] [garden.stylesheet :as stylesheet] [site.fabricate.styles :as styles] [site.fabricate.prototype.page :as page]))🔚
   
(def metadata {:page-style (garden/css (concat styles/docs (list [:.example-rows {:grid-column-start 1}]))), :title "A Reference to Fabricate's Page Templates"})🔚
                                    ✳=[:h1 {:class "xl-text"} (:title metadata)]🔚

This page has an informal explanation of the parts that make up a Fabricate page, using inputs and outputs paired together for demonstration purposes.

A formal definition of the grammar is included in the documentation for the ✳=[:a {:href "/reference/namespaces/site.fabricate.prototype.read.grammar.html"} [:code "site.fabricate.prototype.read.grammar"] " namespace"]🔚.

✳=[:h3 "Basic Expressions"]🔚

An expression starts and ends with the asterisk and END emojis: ✳=(into [:code] grammar/delimiters)🔚. You can then use some optional control characters to change how that expression will be used by Fabricate. All expressions in those emoji will be evaluated after Fabricate reads the page template and parses it.

One thing that makes Fabricate different is the fact that templates can appear anywhere in the text. So if you wanted to write a sentence generated by a Clojure program in the middle of an ordinary paragraph, you can do that. If you want to define a variable naming all the sections and write a sentence like "this page has ✳=3🔚 sections," you can do that. Fabricate, by default, uses inline expressions instead of Markdown.

✳=[:h4 (first grammar/delimiters) " - " "Run expressions"]🔚

If you don't specify any additional characters, Fabricate evaluates the expression without putting the result in the page.

Useful for: namespace declarations, variable definitions, and other side effects - anything where you don't need to see the result of what you run.
(def run-exprs (quote [(ns my-demo-ns (:require [site.fabricate.prototype.page :as page])) (def metadata {:title "My page"})]))🔚
     ✳=(list [:h5 {:class "l-text"} "Examples"] (apply conj [:div {:class "small"}] (for [expr run-exprs] [:pre [:code (page/simple-expr expr {:ctrl-char ""})]])))🔚

✳=[:h4 (first grammar/delimiters) "= - " "Yield expressions"]🔚
(def yield-exprs (list [:code {:class "language-clojure"} "(map inc (range 40 29 -1))"] [:figure [:blockquote "People are alive -- they behave and respond. Creations within the computer can also live, behave, and respond... if they are allowed to."] [:figcaption "Bret Victor, " [:a {:href "https://vimeo.com/64895205"} [:em "Stop Drawing Dead Fish"]]]] [:img {:src "https://live.staticflickr.com/3770/11073365765_6dd38cce29_z.jpg"}]))🔚
If you add the "=" character after the asterisk - ✳=[:span (first grammar/delimiters) "="]🔚, the expression's results get added into the page. Hiccup expressions, like ✳=[:code "[:code "example inline code"]"]🔚 are included in the document tree and will be transformed into HTML all at once after the document is evaluated.

Useful for: anything you'd use HTML for.

✳=(list [:h5 {:class "l-text"} "Examples"] [:div (apply list (for [expr yield-exprs] [:div {:class "example-rows"} [:div {:class "example-row"} [:pre (first grammar/delimiters) "=" [:code (page/expr->hiccup expr)] (last grammar/delimiters)]] [:div {:class "example-row"} expr]]))])🔚

✳=[:h4 (first grammar/delimiters) "+" "Insert expressions"]🔚
Use this for when you want to evaluate some code and insert the expression into the result, but not its output.

Useful for: when you want to demonstrate some code that contributes to the page but its output isn't important. You could show the code used to define a variable, but use the the contents of that variable later on in the page. It's also useful for instructive function definitions, where the return value of a function definition is just a var.

(def insert-exprs (quote [(defn de-jong "Returns a Peter de Jong attractor function. Use with iterate." [a b c d] (fn [[x y]] [(- (Math/sin (* a y)) (Math/cos (* b x))) (- (Math/sin (* c x)) (Math/cos (* d y)))])) (defn clifford "Returns a Clifford attractor function. Use with iterate." [a b c d] (fn [[x y]] [(- (Math/sin (* a y)) (* c (Math/cos (* a x)))) (- (Math/sin (* b x)) (* d (Math/cos (* b y))))])) (def de-jong-example (de-jong 1.517 -2.001 3.45 2.07)) (def clifford-example (clifford 1.24 1.14 1.23 1.89))]))🔚

✳=(list [:h5 "Examples"] (apply conj [:div {:class "small"}] (for [expr insert-exprs] [:div {:class "example-rows"} [:pre {:class "example-row"} [:code (first grammar/delimiters) "+" (page/expr->hiccup expr) (last grammar/delimiters)]] [:pre {:class "example-row"} [:code (page/expr->hiccup expr)]]])))🔚

✳=[:h4 (first grammar/delimiters) "+=" "Composing control characters"]🔚

You can use both the "+" and "=" characters together to display a form along with its output.


Useful for: showing off your art alongside the code that produced it.

(doseq [expr insert-exprs] (eval expr))🔚

(def insert-display-exprs (quote [(let [w 300 h 400] (into [:svg {:width w, :id "de-jong-fractal", :height h}] (map (fn [[^{Double true} x ^{Double true} y]] [:circle {:r 1.0, :style {:fill "#606456", :opacity 0.3}, :cx (* w (+ 0.5 (/ x 4.0))), :cy (* h (+ 0.5 (/ y 5.0)))}]) (take 15000 (iterate de-jong-example [1.4 3.9]))))) (let [w 300 h 400] (into [:svg {:width w, :id "clifford-fractal", :height h}] (map (fn [[^{Double true} x ^{Double true} y]] [:circle {:r 1.0, :style {:fill "#606456", :opacity 0.3}, :cx (* w (+ 0.5 (/ x 4.0))), :cy (* h (+ 0.5 (/ y 5.0)))}]) (take 15000 (iterate clifford-example [1.4 3.9])))))]))🔚



✳=(list [:h5 "Examples"] (apply conj [:div] (for [expr insert-display-exprs] [:div {:class "example-rows"} [:pre {:class "example-row"} [:code (first grammar/delimiters) "+=" (page/expr->hiccup expr) (last grammar/delimiters)]] [:div {:class "example-row"} (eval expr)]])))🔚

✳=[:h4 "Interlude: (code) documentation as data"]🔚

Not only do these examples illustrate how Fabricate's control characters work, they also show how you can build up components of a page by defining them as variables in Clojure and then using them to produce page elements. I was able to use Flexbox attributes to tailor the layout to my examples without tying the whole page to a single way of displaying things. The example expressions above were defined not as ossified strings in a fenced code block, but as quoted Clojure expressions, some of which were evaluated to produce this page. If they encountered an error on evaluation, an error would have surfaced in the page as I was drafting it. Can you be assured of that when putting example code in Markdown documents?

✳=[:h3 "Extended form expressions"]🔚

Sometimes it's preferable to group multiple forms together along with paragraphs of plain text into a single section. In order to do this without embedding many paragraphs in a single large Fabricate expression, Fabricate also supports extended forms. They allow you to mark the start and end points of an element in a document and continue working within that element normally using Fabricate's mix of plain text and expressions.

(def extended-form-example {:open (str (first grammar/delimiters) "// [:section {:class "chapter"}"), :close (str "]//" (last grammar/delimiters)), :contents (format "Text in a "chapter" section. Embedded expressions can be included as well, like %s=[:em "emphasized text."] %s" (first grammar/delimiters) (last grammar/delimiters))})🔚

✳=[:h4 "Form Definition"]🔚
✳=[:pre [:p [:code (:open extended-form-example)]] [:p [:code (:contents extended-form-example)]] [:p [:code (:close extended-form-example)]]]🔚

✳=[:h4 "Results"]🔚

✳=(-> (:contents extended-form-example) read/parse (read/eval-all) (#()))🔚

✳=[:h2 "A longer example document: this page"]🔚

This page itself uses many of the "useful for" tips I mentioned in the first section. You might find the source code of the page instructive, so it is included below:

✳=[:pre {:class "small"} [:code (->> "pages/reference/template-structure.html.fab" slurp (#()) (clojure.walk/postwalk (fn [i] (if (read/fabricate-expr? i) (let [[start end] grammar/delimiters ctrl-char (cond (and (contains? i :expr) (:display i)) "+=" (:display i) "+" (contains? i :expr) "=" (contains? i :exec) "")] [:span start ctrl-char (page/expr->hiccup (or (:expr i) (:exec i))) end]) i))) (apply list))]]🔚