-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtemplate.tem
47 lines (46 loc) · 4.83 KB
/
template.tem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
(page "Template operations"
(text "One of the data structures provided by Arc is the template abstraction. Templates act somewhat like structure definitions. A template can be instantiated into a table that represents the structure as key-value pairs, where the keys can be considered field names in the structure, and the values are the values of the fields.
A template defines a structure by defining the allowed keys, potentially with default values. A template is instantiated into a table by providing key-value pairs; these can override the defaults.
<p>
Templates can be used as a convenient mechanism for loading and storing structures in files. The <code>write-table</code>, <code>save-table</code>, or <code>tablist</code> functions can be used to save a table. A template table can be read in with <code>temread</code> or <code>temload</code>, and multiple tables can be read in with <code>temloadall</code>. These template functions have a couple advantages over using the table load functions: if the saved tables are missing fields, the defaults are filled in, and if the saved tables have extra fields, they are dropped. This provides a simple mechanism of upgrading data formats.
<p>The following code defines a circle template with x, y, and radius fields. A couple circles are defined and written to a file. A newcircle template is defined that extends the circle template by adding a color field. The circles are read in using the new template, and pick up the new color field.
<pre class=\"repl\">
arc> (deftem circle x 0 y 0 radius nil)
((x #<procedure>) (y #<procedure>) (radius #<procedure>))
arc> (= c1 (inst 'circle 'radius 10))
#hash((radius . 10) (y . 0) (x . 0))
arc> (= c2 (inst 'circle 'x 100 'y 100 'radius 5))
#hash((radius . 5) (y . 100) (x . 100))
arc> (w/outfile of \"circles.arc\" (write-table c1 of) (write-table c2 of))
nil
arc> (deftem (newcircle circle) color \"blue\")
((x #<procedure>) (y #<procedure>) (radius #<procedure>) (color #<procedure>))
arc> (temloadall 'newcircle \"circles.arc\")
(#hash((radius . 10) (color . \"blue\") (y . 0) (x . 0)) #hash((radius . 5) (color . \"blue\") (y . 100) (x . 100)))
</pre>
<p>
While the template names and keys can be anything usable as a table index, including strings or numbers, it is customary to use symbols.
<p>
Note that the parameters to the different template operations are unexpectedly different. <code>deftem</code> and <code>addtem</code> are macros, so any symbols should not be quoted. However, the other operations are procedures, so symbols need to be quoted. <code>deftem</code>, <code>addtem</code>, and <code>inst</code> take each key and value as separate parameters, but <code>templatize</code> and the file operations based on it take the keys and values in a list of pairs. <code>inst</code> allows new keys that weren't present in the template to be used, while <code>templatize</code> does not.
"
)
(newtable "Template operations"
(mac deftem "template-name(s) key default-value [key default-value] ..." "Creates a template. The template-name can be any table key, but typically a symbol. The template name can also be a list of template names, where the first name is the new template, and it inherits key/value pairs from the following template names. If a default-value is nil, then no default value will be used for that key, but the key is permitted in templatize and related functions."
(tests (deftem tem1 a "def1" b "def2")(deftem (tem2 tem1) b "def3" c "def4")))
(mac addtem "template-name [key value ...]" "Modifies the specified template by adding (or updating) the keys and values.")
(def inst "template-name [key value ...]" "Instantiates a template. A new table is created from the key-value pairs. The table contains the default values from the template, unless they are overridden in the key-value arguments."
(tests (inst 'tem1 'b "newval" 'd 42)))
(def templatize "template-name ([(key value) ...])" "Instantiates a template. The key-value pairs are given as a list of two-element lists. Any keys not defined in the template are ignored." (tests (templatize 'tem1 '((b "newval")(d 42)))))
(def temread "template-name [input-port]" "Instantiates a template from input. Reads a list from input-port or stdin and applies templatize."
(tests (w/instring s "((b newval d 42))" (temread 'tem1 s))))
(def temload "template-name filename" "Instantiates a template from a file. Applies templatize to the given file."
(faketest "(temload 'tem \"foo.txt\")"
"#hash((a . \"value1\") (b . \"newval\"))"))
(def temloadall "template-name file" "Instantiates a template multiple times from a file, which contains multiple lists of key-value lists. Returns a list of tables."
(faketest "(temloadall 'tem \"foo2.txt\")"
"(#hash((a . \"value1\") (b . \"newval\"))
#hash((a . \"value2\") (b . \"newval\")))")
)
(var templates* "" "Global variable holding all templates." (tests))
)
)