@@ -2,108 +2,111 @@ This file contains some proposals for this project's design decisions.
2
2
3
3
## Different forms of templates
4
4
5
+ If we wanted to make an analogy between this library and the JVM:
6
+ - the text-based, user-facing templates are the JVM languages,
7
+ - the "data template" format is the JVM byte code specification,
8
+ - the template renderers are the JVM runtimes.
9
+
5
10
### User facing templates
6
11
7
- Text-based, described using one of the supported syntax, e.g.
12
+ ** Text-based** , they are described using one of the supported syntax, e.g.
8
13
9
- - ` silly-j ` , Hopen's default syntax.
10
- - Selmer's syntax.
14
+ - Selmer's syntax, inspired from [ Django] ( https://docs.djangoproject.com/en/dev/ref/templates/builtins/ ) .
15
+ - "Silly-j", a syntax designed to feel familiar to Clojure users.
16
+ - Any other syntax that can be transformed into the "data template" format.
11
17
12
18
### Parsed template
13
-
19
+
14
20
> "It's just data"
15
21
>
16
22
> -- Rich Hickey
17
23
18
- It is designed to be read and processed, it could be written down
19
- into an EDN file and be loaded back later. This format is a standard
20
- for this library and it has a spec.
24
+ Also known as the "data template", it is designed to be serialized into
25
+ EDN format, to be read and processed by programs.
26
+
27
+ This format is a standard for this library and it has a spec.
21
28
22
29
Note: In the long run, this format has the potential to become a standard
23
30
to represent parsed templates in the Clojure eco-system, so we * may* want
24
- to provide its spec as a separate project.
31
+ to provide its spec as a separate project at some point .
25
32
26
33
Example of parsed template in the EDN format:
27
34
28
35
``` clojure
29
36
[; ; Some immediate values.
30
37
" hello " :foo-kw bar-symb true 3
31
38
32
- ; ; Access to the context's root .
33
- #get [ root :name ]
34
- #get-in [root [ :persons 0 : name]]
35
- #collect [root [ :persons [ 0 1 2 ] : name]]
39
+ ; ; Referencing data .
40
+ ( hopen/ root :name )
41
+ ( hopen/ctx : name)
42
+ ( my-var : name)
36
43
37
- ; ; Access to the current context.
38
- #get [ctx :name ]
39
- #get-in [ctx [:persons 0 :name ]]
40
- #collect [ctx [:persons [0 1 2 ] :name ]]
44
+ (get-in my-var [:persons 0 :name ])
45
+ (collect my-var [:persons [0 1 2 ] :name ])
41
46
42
- ; ; Scoped alteration of the current context.
43
- #let [[; Note: we can't bind the root symbol.
44
- ctx #get-in [ctx [:persons 0 ]]]
45
- [#get [ctx :name ]]]
47
+ ; ; Scoped redefinition of the current context.
48
+ (let [hopen/ctx (get-in hopen/ctx [:persons 0 ])]
49
+ (hopen/ctx :name ))
46
50
47
51
; ; Scoped binding on an arbitrary symbol.
48
- # let [[ person # get-in [ ctx [:persons 0 ]] ]
49
- [#get [ person :name ]]]
52
+ ( let [person ( get-in hopen/ ctx [:persons 0 ]) ]
53
+ ( person :name ))
50
54
51
55
; ; Iterations, scoped binding on cartesian products.
52
- # for [[ person #get [ ctx :persons ] ]
53
- [#get [ person :name ]]]
56
+ ( for [person ( hopen/ ctx :persons ) ]
57
+ ( person :name ))
54
58
55
59
; ; Conditional rendering.
56
- # if [#get [ ctx :cond? ]
57
- [# get-in [ ctx [:persons 0 :name ]]] ; then clause
58
- [# get-in [ ctx [:persons 1 :name ]]]] ; else clause
60
+ ( if ( hopen/ ctx :something )
61
+ ( get-in hopen/ ctx [:persons 0 :name ]) ; then clause
62
+ ( get-in hopen/ ctx [:persons 1 :name ])) ; else clause
59
63
60
- ; ; Conditional rendering, level up.
61
- #case [#get [ctx :chosen-one ]
62
- [0 [#get-in [ctx [:persons 0 :name ]]]
63
- 1 [#get-in [ctx [:persons 1 :name ]]]
64
- 2 [#get-in [ctx [:persons 2 :name ]]]
65
- 3 [#get-in [ctx [:persons 3 :name ]]]
66
- 4 [#get-in [ctx [:persons 4 :name ]]]]
67
- " else clause" ]
64
+ ; ; This works as well inline.
65
+ (get-in hopen/ctx [:persons (if (hopen/ctx :something ) 0 1 ) :name ])
68
66
69
- ; ; Filters
70
- #square [3 ]
67
+ ; ; More conditional rendering.
68
+ (case (hopen/ctx :chosen-one )
69
+ 0 nil
70
+ :the-one (get-in hopen/ctx [:persons 1 :name ])
71
+ true {:name " Trueman" }
72
+ " else clause" )
71
73
74
+ ; ; Helper functions.
75
+ (inc (hopen/ctx :index ))
76
+ (upper (person :name ))
77
+
78
+ ; ; Helper functions can also be user-defined.
79
+ (sum-of-squares 3 4 ) ; {'sum-of-squares (fn [x y] (+ (* x x) (* y y)))}
72
80
]
73
81
```
74
82
75
- ### Compiled template
83
+ ### Renderer
76
84
77
- As a Clojure transducer, this template form is optimized for rendering.
78
- It outputs a serie of printable data (e.g. numbers, strings, etc ..) .
85
+ This template form is optimized for rendering. How it is doing it and
86
+ how it is used depends on the implementation .
79
87
80
- In addition to the default portable implementation of the
81
- template compiler, some environment specific implementations
82
- could be provided for better performance.
88
+ Just like the JVM runtimes, there are some which are pure interpreters and some
89
+ which optimize using Just-In-Time compilation techniques.
83
90
84
91
## Hopen's API
85
92
93
+ Something like that:
94
+
86
95
``` clojure
87
- (require '[hopen.core :as hopen ]
96
+ (require '[hopen.renderer.xf :as rxf ]
88
97
'[hopen.syntax.silly-j :as silly-j])
89
98
90
99
; ; Parse a template using one of the supported syntax.
91
- (def parsed -template
100
+ (def data -template
92
101
(silly-j/parse " Hello {@:name}, {@:n} * {@:n} = {square @:n}" ))
93
102
94
- ; ; Compile a template for rendering.
95
- (def template-xf
96
- (hopen/compile parsed -template
97
- ( assoc hopen/builtin-filters
103
+ ; ; Prepare a template for rendering using one of the supported renderer .
104
+ (def renderer
105
+ (rxf/renderer data -template
106
+ ( update rxf/default-env :bindings assoc
98
107
'square (fn [x] (* x x)))))
99
108
100
- ; ; Render your data into a string.
101
- (transduce template-xf str [{:name " Alice" , :n 3 }])
109
+ ; ; Use the renderer to output the data into a string.
110
+ (transduce renderer str [{:name " Alice" , :n 3 }])
102
111
; => "Hello Alice, 3 * 3 = 9"
103
112
```
104
-
105
- # Implementation Requirements
106
-
107
- - The filter functions should be standard clojure functions,
108
- they should be used in the same way by any of the different
109
- template syntax available.
0 commit comments