Appendix C
A Chapter Written in Code
Every other chapter in this manual is Markdown. This one is a .clj file: the build runs it and uses the value of its last expression as the chapter. The result is the same author Hiccup described in the authoring chapter, so everything downstream is identical. What changes is that the content can be computed.
You do not need prior Clojure to follow along, and you can treat this file as a template to copy. Every form it uses is introduced in the Clojure appendix: the four data shapes, plus def to name a value, for to build rows, and into to pour them into an element. Each section below shows the lines of this file that produce it, included from the file itself, so the source you read is the source that ran.
A table the book writes for itself
The authoring chapter lists the author vocabulary by hand. This appendix asks the build instead: the tag set lives in a var the expansion engine itself uses, and the chapter turns it into rows.
(def tag-names
(sort (map name vocabulary/sugar-tags)))
(def vocabulary-table
(into [:table {:id :tbl-vocab
:caption "The author vocabulary, read from the running build"}]
(for [row (partition-all 3 tag-names)]
(into [:tr] (for [tag row] [:td [:code tag]])))))Line by line: tag-names takes the tag set, turns each tag into its name, and sorts them. partition-all slices the sorted names into rows of three, the for wraps each name in a table cell, and into pours the rows into a captioned table. The result renders as Table 4:
a | admonition | blockquote |
br | button | cite |
code | dd | details |
diagram | dl | dt |
em | epigraph | example |
figure | footnote | h1 |
h2 | h3 | h4 |
h5 | h6 | hr |
img | index | kbd |
keep-together | li | mark |
math | menu | ol |
open | overview | p |
p-first | page-break | pre |
sidebar | span | strong |
sub | sup | table |
tbody | td | th |
thead | tr | ul |
xref |
When a tag joins the vocabulary, the next build updates the table. There is no copy to forget.
Documentation that cannot drift
The theming chapter explains that PDF margins default to the classical 2:3:4:6 construction. Prose can describe the rule; a chapter written in code can run it. The table below calls the same function the PDF compiler calls, once per named trim:
(def canon-table
(into [:table {:id :tbl-canon
:caption "Margins per trim, from the canon function"}]
(cons [:tr [:th "Trim"]
[:th "Inner"] [:th "Top"] [:th "Outer"] [:th "Bottom"]]
(for [[trim {:keys [width]}] (sort-by first theme/page-sizes)]
(let [margins (theme/canon-margins width 2/3)]
[:tr
[:td [:code (str trim)]]
[:td (:margin-inside margins)]
[:td (:margin-top margins)]
[:td (:margin-outside margins)]
[:td (:margin-bottom margins)]])))))| Trim | Inner | Top | Outer | Bottom |
|---|---|---|---|---|
:a4 | 23.3mm | 35.0mm | 46.7mm | 70.0mm |
:digest | 15.6mm | 23.3mm | 31.1mm | 46.7mm |
:letter | 24.0mm | 36.0mm | 48.0mm | 72.0mm |
The table lists 3 trims because that is how many the build knows about; the count in this sentence is computed too. If the canon derivation ever changes, Table 5 follows it on the next build, and a stale number here would be a bug in Smia, not in the manual.
Down to a single formatting object
The same file can reach below the sugar. The end of this appendix carries a small letterspaced colophon line in the PDF editions, written directly as a formatting object and wrapped in a condition so the web editions skip it:
(def pdf-editions
{:any-of [{:equals [:edition :screen]}
{:equals [:edition :print]}
{:equals [:edition :print-x]}]})
(def colophon
[:when pdf-editions
[:fo/block {:text-align "center" :letter-spacing "0.15em"
:font-size "9pt" :color "#666666" :space-before "24pt"}
"SET IN SMIA"]])This is the escape-hatch matrix at its most granular: one element, in one place, in some editions, with no stylesheet layer involved. The condition map is the same :when vocabulary Markdown uses for conditional content.
When to reach for code
- A reference table whose rows already live in your project: a configuration registry, an error catalog, a benchmark output file.
- Values the text must state and the implementation already knows: defaults, limits, version-dependent behavior.
- Structure Markdown cannot express, such as merged table cells.
- Bulk content that follows a pattern: fifty near-identical sections want a
for, not fifty files. - Production at scale: a publisher whose pipeline already holds the content as data can emit chapters from it directly, and the build stays deterministic, scriptable, and headless.
Prose-heavy chapters stay nicer in Markdown; this manual keeps every other chapter there. The two front ends share one vocabulary, so a book can mix them freely, chapter by chapter.
In the PDF editions a small letterspaced colophon closes this page, set directly in FO. This paragraph is its web-edition replacement, chosen by the same condition.