summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Andreoli <dave@gurumeditation.it>2018-01-03 13:58:26 +0100
committerDave Andreoli <dave@gurumeditation.it>2018-01-03 14:00:33 +0100
commitee53d64dcb092ca4c60921f140f89f850775483e (patch)
treed756e5a3fab2138586e3b802e7a1e603bb8d5be9
parentf910ba248e3f8f8390674e79cbbe49582eed861e (diff)
Pyolian: quite complete documentation for usage and template syntax
The same content is available in phab wiki at: https://phab.enlightenment.org/w/pyolian/
-rw-r--r--src/scripts/pyolian/README.md386
1 files changed, 386 insertions, 0 deletions
diff --git a/src/scripts/pyolian/README.md b/src/scripts/pyolian/README.md
new file mode 100644
index 0000000000..61bf0dc52d
--- /dev/null
+++ b/src/scripts/pyolian/README.md
@@ -0,0 +1,386 @@
1
2Pyolian: Eolian python bindings and a template-based Eolian generator
3=====================================================================
4
5If you need to generate something based on the Eolian database you are in the
6right place! Pyolian is the python bindings for Eolian and provide a clean and
7pythonic API to Eolian; as a bonus it also provide a template-based
8generator to render custom template files, filling them with a full eolian
9context available.
10
11The template engine is really powerfull and provide all the functionalities you
12would expect from a full blow template engine. It is comparable in syntax and
13features to [Jinja2](http://jinja.pocoo.org/) or the Django template system. If
14you are interested on the implementation detail this generator is bases on the
15great [Pyratemp](https://www.simple-is-better.org/template/pyratemp.html).
16
17
18Installation
19============
20
21There is nothing to install to use the bindings or the generator, everything is
22included in the efl source tree and it is intended to work directly inside the
23tree, usually at efl compilation time (before the install step).
24
25The only requirement is that **the source tree must be already built** (not
26installed) because pyolian search the eolian .so/.dll inside the source tree.
27
28
29Command line usage
30==================
31The simplest way to use the generator is from the command line, using the
32`src/scripts/pyolian/generator.py` command, the `--help` option state:
33
34```
35usage: generator.py [-h] [--output FILE] [--cls CLASS_NAME] [--ns NAMESPACE]
36 [--struct STRUCT_NAME] [--enum ENUM_NAME]
37 [--alias ALIAS_NAME]
38 template
39
40Pyolian template based generator.
41
42positional arguments:
43 template The template file to use. (REQUIRED)
44
45optional arguments:
46 -h, --help show this help message and exit
47 --output FILE, -o FILE
48 Where to write the rendered output. If not given will
49 print to stdout.
50 --cls CLASS_NAME The full name of the class to render, ex:
51 Efl.Loop.Timer
52 --ns NAMESPACE The namespace to render, ex: Efl.Loop
53 --struct STRUCT_NAME The name of the struct to render, ex:
54 Efl.Loop.Arguments
55 --enum ENUM_NAME The name of the enum to render, ex:
56 Efl.Loop.Handler.Flags
57 --alias ALIAS_NAME The name of the alias to render, ex: Efl.Font.Size
58```
59
60Basically you just need a template file, then call the generator with at least
61the template file and one of the context options (cls, ns, struct, enum or alias)
62
63Two example templates can be found in the `efl/src/scripts/pyolian` folder,
64from that directory you can run:
65
66```
67./generator.py test_gen_class.template --cls Efl.Loop.Timer
68```
69
70This will rendere the template test_gen_class.template with Efl.Loop.Timer as
71**cls** available in the template, you can of course pass any other class you
72want.
73
74As we did not pass the --output-file parameter the rendered text is printed
75on standard out.
76
77
78Python usage
79============
80
81To use pyolian from python code you need to import **eolian** and/or the
82**Template** class from the pyolian directory. As this python package is not
83installed you need a little hack to import the package, something like this
84should work:
85
86```
87# Use pyolian from source (not installed)
88pyolian_path = os.path.join(<efl_root_path>, 'src', 'scripts')
89sys.path.insert(0, pyolian_path)
90from pyolian import eolian
91from pyolian.generator import Template
92```
93
94Now you can use the full eolian library defined in eolian.py (read the file
95to see all available classes and their properties) or just the Template class
96like this:
97
98```
99t = Template('test_gen_class.template')
100t.render('output.txt', cls='Efl.Loop.Timer', verbose=True)
101```
102
103
104Template syntax
105===============
106
107A template is a normal text file, containing some special placeholders and
108control-structures. there are 3 syntax blocks available:
109
110
111Expressions
112-----------
113
114A template needs some kind of "programming-language" to access variables,
115calculate things, format data, check conditions etc. inside the template. So,
116you could invent and implement an own language therefore -- or you could use an
117already existing and well designed language: Python.
118
119The template engine uses embedded Python-expressions. An expression is
120everything which evaluates to a value, e.g. variables, arithmetics,
121comparisons, boolean expressions, function/method calls, list comprehensions
122etc. And such Python expressions can be directly used in the template.
123
124```
125${expression}$
126```
127
128**expression** can be any expression (e.g. a variable-name, an arithmetic
129calculation, a function-/macro-call etc.), and is evaluated when the template
130is rendered. Whitespace after `${` and before `}$` is ignored.
131
132Generic examples:
133
134 * numbers, strings, lists, tuples, dictionaries, ...: 12.34, "hello", [1,2,3], ...
135 * variable-access: var, mylist[i], mydict["key"], myclass.attr
136 * function/method call: myfunc(...), "foobar".upper()
137 * comparison: (i < 0 or j > 1024)
138 * arithmetics: 1+2
139
140For details, please read the Python-documentation about Python expressions.
141
142Examples (for a template rendered with cls='Efl.Loop.Timer'):
143
144 * `${cls.full_name}$` => 'Efl.Loop.Timer'
145 * `${cls.full_name.replace('.', '_').lower()}$` => 'efl_loop_timer'
146 * `${cls.base_class.full_name if cls.base_class else None}$` => 'Efl.Loop.Consumer' or None
147 * `${', '.join([i.full_name for i in cls.hierarchy])}$` => 'Efl.Loop.Consumer, Efl.Object'
148
149note the incredible flexibility of **expression**, they are basically small
150pieces of python code, so you can use quite all the python syntax in them.
151
152Also note that the context of the template (**cls** in this example) is always
153an instance of a class defined in eolian.py (eolian.Class in this example), you
154must read this file to understand all the available classes with their
155properties and methods.
156
157
158Comments
159--------
160
161Comments can be used in a template, and they do not appear in the result. They
162are especially useful for (a) documenting the template, (b) temporarily
163disabling parts of the template or (c) suppressing whitespace.
164
165 * `#!...!#` - single-line comment with start and end tag
166 * `#!...` - single-line-comment until end-of-line, incl. newline!
167
168The second version also comments out the newline, and so can be used at the end
169of a line to remove that newline in the result.
170
171Comments can contain anything, but comments may not appear inside substitutions
172or block-tags.
173
174
175Blocks
176------
177
178The control structures, macros etc. have a special syntax, which consists of a
179start tag (which is named according to the block), optional additional tags,
180and an end-tag:
181
182```
183<!--(...)--> #! start tag
184 ..
185 ..
186<!--(...)--> #! optional additional tags (e.g. for elif)
187 ..
188 ..
189<!--(end)--> #! end tag
190```
191
192All tags must stand on their own line, and no code (except a `#!...` comment) is
193allowed after the tag.
194
195All tags which belong to the same block **must have the same indent!** The
196contents of the block does not need to be indented, although it might improve
197the readability (e.g. in HTML) to indent the contents as well.
198
199Nesting blocks is possible, but the tags of nested blocks must have a different
200indent than the tags of the enclosing blocks. Note that you should either use
201spaces or tabs for indentation. Since the template distinguishes between spaces
202and tabs, if you mix spaces and tabs, two indentations might look the same
203(e.g. 8 spaces or 1 tab) but still be different, which might lead to unexpected
204errors.
205
206There's also a single-line version of a block, which does not need to stand on
207its own line, but can be inserted anywhere in the template. But note that this
208version does not support nesting :
209
210```
211...<!--(...)-->...<!--(...)-->...<!--(end)-->...
212```
213
214if/elif/else
215------------
216
217```
218<!--(if EXPR)-->
219...
220<!--(elif EXPR)-->
221...
222<!--(else)-->
223...
224<!--(end)-->
225```
226
227The `elif` and `else` branches are optional, and there can be any number of
228`elif` branches.
229
230
231for/else
232--------
233
234```
235<!--(for VARS in EXPR)-->
236...
237<!--(else)-->
238...
239<!--(end)-->
240```
241
242VARS can be a single variable name (e.g. myvar) or a comma-separated list of
243variable-names (e.g. i,val).
244
245The `else` branch is optional, and is executed only if the for loop doesn't
246iterate at all.
247
248
249macro
250-----
251
252Macros are user-defined "sub-templates", and so can contain anything a template
253itself can contain. They can have parameters and are normally used to
254encapsulate parts of a template and to create user-defined "functions". Macros
255can be used in expressions, just like a normal variable or function.
256
257```
258<!--(macro MACRONAME)-->
259...
260<!--(end)-->
261```
262
263Note that the last newline (before `<!--(end)-->`) is removed from the macro, so
264that defining and using a macro does not add additional empty lines.
265
266Usage in expressions:
267
268 * `MACRONAME`
269 * `MACRONAME(KEYWORD_ARGS)`
270
271KEYWORD_ARGS can be any number of comma-separated name-value-pairs (name=value,
272...), and these names then will be locally defined inside the macro, in
273addition to those already defined for the whole template.
274
275
276raw
277---
278
279```
280<!--(raw)-->
281...
282<!--(end)-->
283```
284
285Everything inside a `raw` block is passed verbatim to the result.
286
287
288include
289-------
290
291```
292<!--(include)-->FILENAME<!--(end)-->
293```
294
295Include another template-file. Only a single filename (+whitespace) is allowed
296inside of the block; if you want to include several files, use several
297include-blocks.
298
299Note that inclusion of other templates is only supported when loading the
300template from a file. For simplicity and security, FILENAME may not contain a
301path, and only files which are in the same directory as the template itself can
302be included.
303
304
305
306Template context
307================
308
309The following Python-built-in values/functions are available by default in the
310template:
311
312 * `True`
313 * `False`
314 * `None`
315 * `abs()`
316 * `chr()`
317 * `divmod()`
318 * `hash()`
319 * `hex()`
320 * `isinstance()`
321 * `len()`
322 * `max()`
323 * `min()`
324 * `oct()`
325 * `ord()`
326 * `pow()`
327 * `range()`
328 * `round()`
329 * `sorted()`
330 * `sum()`
331 * `unichr()`
332 * `zip()`
333 * `bool()`
334 * `bytes()`
335 * `complex()`
336 * `dict()`
337 * `enumerate()`
338 * `float()`
339 * `int()`
340 * `list()`
341 * `long()`
342 * `reversed()`
343 * `set()`
344 * `str()`
345 * `tuple()`
346 * `unicode()`
347 * `dir()`
348
349Additionally, the functions exists(), default(), setvar() and escape() are
350defined as follows:
351
352 * `exists("varname")` Test if a variable (or any other object) with the given name exists
353 * `default("expr", default=None)` Tries to evaluate the expression expr.
354 If the evaluation succeeds and the result is not None, its value is returned;
355 otherwise, if the expression contains undefined variables/attributes, the
356 default-value is returned instead. Note that expr has to be quoted.
357 * `setvar("name", "expr")` Although there is often a more elegant way,
358 sometimes it is useful or necessary to set variables in the template.
359 Can also be used to capture the output of e.g. an evaluated macro.
360
361Moreover all the Eolian classes and enums (as defined in eolian.py) is available
362in the template, fe:
363
364 * `Function` eolian.Function (class)
365 * `Eolian_Class_Type` eolian.Eolian_Class_Type (enum)
366
367And some other general utilities:
368
369 * `template_file` name of the template used to generate the output
370 * `date` python datetime object (generation time)
371
372
373Where to find more info
374=======================
375
376 * read the eolian.py file (it declare the full eolian API)
377 * read the generator.py file (it's super simple)
378 * read the original [pyratemp docs](https://www.simple-is-better.org/template/pyratemp.html)
379
380
381Note
382====
383
384This markdown file is mirrored in efl src tree (src/scripts/pyolian) and in
385phab wiki (phab.enlightenment.org/w/pyolian). Don't forget to update the other
386if you change one!