on master help sign in
Merge pull request #190 from urbit/ford-docs
44a55b0Galen Wolfe-Pauly
docs/arvo/internals/ford/commentary.md+3−3
@@ -198,9 +198,9 @@ retrieve it from.
198 == ::
198 == ::
199
199
200This is how we represent the static resources hook files can load. The
200This is how we represent the static resources hook files can load. The
201−discussion of their use from a user's perspective is documented
201+discussion of their use from a user's perspective is documented in the [runes
202+documentation](https://urbit.org/docs/arvo/internals/runes), so we will here
202−elsewhere (link), so we will here only give a description of the data
203+only give a description of the data structure itself.
203−structure itself.
204
204
205A `%ape` horn is simply a twig that gets evaluated and placed in the
205A `%ape` horn is simply a twig that gets evaluated and placed in the
206subject.
206subject.
docs/arvo/internals/ford/runes.mdnew file+422
@@ -0,0 +1,422 @@
1+# `%ford` user manual
2+
3+## ford runes
4+
5+One of the most common ways to use ford is through ford's runes, all of which begin with `/` ("fas"). A ford rune runs a step of a ford build and places the result in the subject. There are various kinds of build steps, some of which take other build steps as parameters. The most common pattern is to have a sequence of ford runes at the top of a hoon source file that import the results of evaluating other hoon files. This is how we "import a library" in urbit: we add the result of compiling another hoon file into the current subject, possibly renaming it by wrapping a face around it.
6+
7+Another common use case is assembling and rendering markdown templates into a single HTML file, to be sent as an HTTP response in urbit's web server `%eyre`. It's important to keep in mind that %ford is quite flexible and generic, and is used in other parts of urbit -- such as the dojo -- that would not traditionally fall under the purview of a build system.
8+
9+### `/+` import from lib/
10+
11+The `/+` rune accepts a filename as an argument. It interprets that filename
12+as a hoon source file within the `lib` directory. This is how we import a shared
13+library in urbit.
14+
15+Example:
16+```
17+/+ time-to-id
18+::
19+(time-to-id now)
20+```
21+produces: `"c.314d"` (or something similar depending on when you run it)
22+
23+### `/-` import from sur/
24+
25+The `/-` rune accepts a filename as an argument. It interprets that filename as
26+a hoon source file within the `sur` directory. The `sur` directory contains
27+shared structures that can be used by other parts of urbit. This is somewhat
28+similar to including a header file in C.
29+
30+Example:
31+```
32+/- talk
33+::
34+*serial:talk
35+```
36+produces: `0v0`
37+
38+### `/~` twig by hand
39+
40+`/~ <twig>` produces a "horn" that evaluates a twig and places the product in
41+the subject. Arbitrary hoon can be in the twig. A
42+[horn](https://urbit.org/docs/arvo/internals/ford/commentary/#-horn) is a data
43+structure representing a `%ford` static resource.
44+
45+Example:
46+```
47+/~ [a=0 b=1]
48+[a b]
49+```
50+produces:
51+`[0 1]`
52+
53+In wide-form, `/~` always takes a tuple (which may be a degenerate tuple of one element), and produces it.
54+
55+Example:
56+```
57+/~[%something]
58+```
59+produces: `%something`
60+
61+```
62+/~[%a %b]
63+```
64+produces: `[%a %b]`
65+
66+### `//` include a file by relative path
67+
68+`// <rel-path>` parses `rel-path` as a hoon twig, and then adds the resulting
69+twig to the subject. Note that the result type of this rune is not a horn, but
70+just a hoon twig, so its result can't be used as an argument to other runes
71+that expect a horn. There is no wide-form for this rune.
72+
73+Example:
74+```
75+// %/file-to-include
76+::
77+(frobnicate:file-to-include %.n)
78+
79+:: contents of file-to-include.hoon
80+|%
81+++ frobnicate
82+ |= a/? ^+ a
83+ !a
84+--
85+```
86+produces: `%.y`
87+
88+_Note: `%` means current directory, which in a hoon file will resolve to the
89+"directory" containing that file. Also, %clay doesn't have first-class
90+directories the way unix filesystems do. Whereas in unix, a directory is a
91+special kind of file, in %clay it's just a path prefix, and there is no file
92+stored at that path._
93+
94+### `/=` wrap a face around an included horn
95+
96+`/=` runs a horn (usually produced by another ford rune), takes the result of
97+that horn, and wraps a face around it.
98+
99+Example:
100+```
101+/= foo /~ [a=0 b=1]
102+::
103+[a.foo b.foo]
104+```
105+produces: `[0 1]`
106+
107+In wide-form, `/=` uses `=` as a delimiter: `/=foo=/~[a=0 b=1]`
108+
109+### `/:` evaluate at path, and `/<mark>/` render mark at current path
110+
111+`/:` takes a path and a horn, and evaluates the horn with the current path set to the supplied path.
112+`/mar/` renders the mark 'mar' at the current path.
113+
114+Example:
115+```
116+/= hoo-source /: /path/to/hoon-file /hoon/
117+::
118+`@t`hoo-source
119+```
120+
121+produces the text of the hoon file at "/path/to/hoon-file/hoon".
122+
123+`/hoon/` renders the current path using the `%hoon` mark, which in this case
124+passes the contents through unchanged. In general, rendering a file with a
125+mark will potentially run the contents through a series of conversion
126+operations. For details on marks, see the
127+[marks docs](https://urbit.org/docs/arvo/marks).
128+
129+Here's an example that includes a mark conversion:
130+```
131+/= page /: /path/to/html/file /mime/
132+::
133+page
134+
135+:: contents of /path/to/html/file:
136+<html><head><title>My Fascinating Blog</title></head></html>
137+```
138+produces:
139+`[[%text %html ~] 60 '<html><head><title>My Fascinating Blog</title></head></html>']`
140+
141+This result includes the MIME type ('text/html'), the content length in bytes,
142+and the HTML itself.
143+
144+In wide-form, `/:` uses `:` as a delimiter: `/=page=/:/path/to/html/file:/mime/`
145+
146+### `/!mark/` evaluate as hoon, then pass through mark
147+
148+Example:
149+```
150+/= mime /: /%/some-hoon-file /!mime/
151+::
152+mime
153+
154+:: contents of /%/some-hoon-file:
155+%produces-a-cord
156+```
157+produces: `[[%text %plain ~] 15 'produces-a-cord']`
158+
159+### `/&` pass through a series of marks
160+
161+`/&` passes a horn through multiple marks, right-to-left. It has both a
162+wide-form and a tall-form syntax. In wide-form, it takes a series of mark
163+arguments followed by a horn. In tall-form, it takes a single mark followed by
164+a horn.
165+
166+```
167+/= some-text /: /%/text-file /&mime&/txt/
168+::
169+some-text
170+```
171+produces: `[[%text %plain ~] p=17 q='Hi I\'m some text\0a']`
172+
173+This example shows two of the ways marks are used. The first way is what
174+happens with the `/txt/` mark: we use it to find a file in clay with that
175+extension, without performing any conversions. Since this file is stored with
176+the `%txt` mark in `%clay`, its type is a `wain`: a list of cords, where each
177+cord is a single line. Once we've read the file, the `%mime` mark converts the
178+`wain` to a triple that includes the MIME type ("text/plain"), the content
179+length in bytes, and the content itself as a cord.
180+
181+```
182+/= page /&html&elem&/~[;div.foo;]
183+::
184+page
185+```
186+produces: `'<html><head></head><body><div class="foo"></div></body></html>'`
187+
188+This runs the sail expression `;div.foo;` through the `%elem` mark, then
189+through the `%html` mark. The `/~` rune produces an item of mark `noun`. The
190+`%elem` mark converts the mark of the expression from `noun` to `elem` by
191+checking that the type fits in `manx` (a hoon/sail type indicating an XML
192+element). The `%html` mark recognizes the `%elem` and converts it to an HTML
193+string with enclosing `<html>`, `<head>`, and `<body>` tags.
194+
195+It's possible to use wide-form `/&` with more than two marks, by using `&` as a
196+delimiter between marks and adding a `/` before the last mark, like:
197+`/&d&c&b&/a/`. The last argument here can actually be any arbitrary horn, not
198+just a mark: `/&c&b&/:path:/mark/`
199+
200+Tall-form `/&` takes only two arguments: a mark and a horn. The mark does not
201+need to be enclosed in `/`'s: `/& html /elem/`
202+
203+### `/|` short-circuiting 'or'
204+
205+`/|` takes a series of horns and produces the first one (left-to-right) that
206+succeeds. If none succeed, it produces stack traces from all of its arguments.
207+
208+Example:
209+```
210+/= res /: /%/path/to/file
211+/|
212+ /!elem/
213+ /elem/
214+==
215+::
216+res
217+```
218+tries to parse the file at `/%/path/to/file` as a hoon expression and evaluate
219+it (`/!elem/`), and then if that fails, tries to convert the file to an HTML
220+element directly (`/elem/`). This is used in urbit's `tree` publishing system
221+to enable a user to place either a hoon file or a static file in a directory,
222+and have them both result in webpages, with preference given to treating the
223+file as hoon to be evaluated.
224+
225+Wide-form `/|` encloses its arguments in parentheses, with a single space as a delimiter:
226+`/|(/!elem/ /elem/)`
227+
228+### `/_` unfiltered: run a horn on each file in the current directory
229+
230+`/_` can be used in two ways: filtered and unfiltered.
231+
232+Unfiltered `/_` takes a horn as an argument. It produces a new horn representing the
233+result of mapping the supplied horn over the list of files in the current
234+directory. The keys in the resulting map are the basenames of the files in the
235+directory, and each value is the result of running that horn on the contents of
236+the file.
237+
238+Example:
239+```
240+/= kids /_ /hoon/
241+::
242+`(map term cord)`kids
243+```
244+
245+produces a value of type `(map term cord)`, where each key is the basename (the
246+filename without the prefix), and each value is the result of running the
247+contents of the file through the `%hoon` mark, which validates that it's valid
248+hoon code and returns it unmodified. So, the resulting map associates basenames
249+with file contents.
250+
251+Wide-form unfiltered `/_` doesn't need a delimiter: `/= kids /_/hoon/`
252+
253+### `/_` filtered: run a horn on each file in the directory matching an aura
254+
255+Filtered `/_` takes an aura and a horn, and filters the list of files in the
256+current directory by whether their filenames can be parsed to an atom of that
257+aura. It then produces a map where each key is the filename after parsing into
258+that atom type, and each value is the result of running the horn on the
259+contents of that file.
260+
261+Example:
262+```
263+/= timed-posts /_ @da /md/
264+`(map @da @t)`timed-posts
265+```
266+produces a map from dates to cords. This product will only contain files whose
267+names are parsable into `@da` dates. The values are the file contents converted
268+to a cord of markdown-formatted text.
269+
270+Wide-form filtered `/_` uses `_` as a delimiter: `/= timed-posts /_@da_/md/`
271+
272+### `/;` operate on
273+
274+`/;` takes a twig and a horn. The twig should evaluate to a gate, which is then slammed
275+with the result of the horn as its sample.
276+
277+Example:
278+```
279+/= goo
280+ /; |=({a/@ b/@} +(b))
281+ /~ [a=0 b=1]
282+::
283+goo
284+```
285+
286+produces: `2`
287+
288+Here's a slightly more complex example with runes that use the filesystem:
289+```
290+/= file-length
291+ /; |=(a/@t (lent (crip a)))
292+ /: /%/path/to/hoon/file /hoon/
293+::
294+file-length
295+```
296+produces the number of bytes in the file "/%/path/to/hoon/file."
297+
298+### `/,` switch by path
299+
300+`/,` is a switch statement, which picks a branch to evaluate based on
301+whether the current path matches the path in the switch statement.
302+Takes a sequence of pairs of (path, horn) terminated by a `==`. No wide-form.
303+
304+Example:
305+```
306+/= just-right
307+ /: /===/right-path :: set path to /%/right-path
308+ /,
309+ /wrong-path /~ ~
310+ /another-wrong-path /~ ~
311+ /right-path /~ %evaluate-me :: only evaluate this horn
312+ ==
313+::
314+`@t`just-right
315+```
316+
317+produces: `'evaluate-me'`
318+
319+### `/.` list
320+
321+Produce a null-terminated list from a sequence of horns, terminated by a `==`. No wide-form.
322+
323+Example:
324+```
325+/= vanes
326+ /.
327+ /~ %ames
328+ /~ %behn
329+ /~ %clay
330+ /~ %dill
331+ /~ %eyre
332+ /~ %ford
333+ /~ %gall
334+ ==
335+::
336+vanes
337+```
338+produces: `[%ames %behn %clay %dill %eyre %ford %gall ~]`.
339+
340+### `/*` heterogeneous map
341+
342+_DEPRECATED_
343+TODO: remove
344+
345+### `/^` cast
346+
347+`/^` takes a mold and a horn, and casts the result of the horn to the mold.
348+
349+Example:
350+```
351+/= liz /^ (list @) :: cast to real list
352+ /~ ~[1 2 3] :: no 'i' or 't' faces
353+::
354+?< ?=($~ liz) :: prevent find-fork
355+i.liz
356+```
357+
358+produces: `1`
359+
360+Without the cast, we wouldn't be able to access the 'i' face of the list.
361+
362+Wide-form `/^` uses `^` as a delimiter: `/^(list @)^/~[1 2 3 ~]`
363+
364+### `/#` insert dephash
365+
366+`/#` takes a horn and produces a cell of the dependency
367+hash of the result of the horn, and the result itself.
368+
369+Example:
370+```
371+/= inline /^ {dep/@uvH txt/@t} /# /: /%/my-script /js/
372+::
373+;= ;script: (trip txt.inline) :: set script contents
374+ ;script@"/~/on/{<dep.inline>}.js"; :: set script src
375+==
376+```
377+produces two `<script>` tags. The first has its contents set to the contents
378+of the JavaScript file we loaded from clay. The second is an auto-update
379+script that polls the server to check whether the dependency hash has changed.
380+This pattern is used in urbit's `tree` web publishing system.
381+
382+Wide-form `/#` does not need a delimiter:
383+`/= inline /^ {dep/@uvH txt/@t} /#/:/%/my-script:/js/`
384+
385+### `/$` process extra arguments
386+
387+`/$` will slam a gate on whatever extra arguments have been supplied to this build.
388+At the moment, only HTTP requests forwarded by `%eyre` contain any extra arguments,
389+and using this rune outside of that context will cause an error. Requests from `%eyre`
390+contain an argument representing the query string, which can be parsed using the
391+standard library gate `++fuel`.
392+
393+Example:
394+```
395+/= gas /$ fuel
396+::
397+:*
398+ %who {<(~(get ju aut.ced.gas) 0)>}
399+ %where {(spud s.bem.gas)}
400+ %case {(scow %ud p.r.bem.gas)}
401+==
402+```
403+produces: [%who '~zod' %where /ford/pages/web %case 60]
404+
405+Wide-form `/$` takes its arguments inside brackets, like `/~`:
406+`/=gas=/$[fuel]`
407+
408+### `/%` propagate extra arguments into renderers
409+
410+`/%` will forward extra arguments (usually from `%eyre`) on to any enclosed `/renderer/`'s. Without this,
411+renderers that use `/$` to read the extra arguments will crash.
412+
413+Example:
414+```
415+/= dat /% /tree-json/
416+::
417+dat
418+```
419+produces the results of running `ren/tree-json` on the current path. This renderer needs the query string,
420+which is one of the extra arguments passed in from `%eyre`.
421+
422+Wide-form `/%` has no delimiter: `/%/tree-json/`