Template concepts
Template concepts
- pxDocGenerators and pxDocModules
- Keyword 'template'
- Keyword 'apply'
- Usages of template and apply keywords
- Keyword 'function'
- var / val
Let's start with the few core concepts that organize your documentation generators:
- pxDocGenerator and pxDocModules,
- templates,
- functions,
- variables.
pxDocGenerators and pxDocModules
pxDocGenerator and pxDocModule share the same set of attributes.
pxDocGenerator <name> <attributes> { ... } pxDocModule <name> <attributes> { ... }
Attributes |
Description |
Possible values (if any) |
Optional |
with: module1, module2, ... |
Comma-separated list of Modules that will be used by this generator |
Any accessible pxDocModule name |
Yes |
stylesheet: MyStylesheet |
Name of a deployed Word stylesheet to use in the generator |
Any valid deployed stylesheet ID |
Yes |
styles: MyStyle1, MyStyle2, ... |
Comma-separated list of variable style names |
Only valid java identifiers (no spaces, no special characters...) |
Yes |
styleBindings: ParamStyle1->RealStyle1, ParamStyle2->RealStyle2, ... |
Comma-separated list of bindings of variable styles to concrete styles |
Source styles are the Module(s) variable styles. Target styles must exist in the chosen stylesheet. All source styles must be bound. |
Yes |
Usage : Basic generator using a Stylesheet
Basic declaration of a generator which uses a stylesheet as a source for the Styles, header/footer, etc.
pxDocGenerator HomePageExample stylesheet:MyStylesheet { root template main(Object model) { ... } }
Usage : Basic generator using variable styles
Basic declaration of a generator which uses 3 variable styles: Title1, Title2 and bulletList. These styles will have to be bound with Styles from a Word stylesheet when generating the document.
pxDocGenerator HomePageExample style: Title1, Titl2, BulletList { root template main(Object model) { ... } }
Usage : Generator with imported modules
A generator with a Module imported. The styles of the Modules are bound with the styles of the Generator stylesheet
pxDocGenerator HomePageExample with: TestModule stylesheet:MyStylesheet styleBindings:moduleTitle1->Title1, moduleTitle2->Title2 { /* content */ }
See “Apply styles” section to learn more about style-binding.
Usage : Declaration of a Module with a stylesheet
pxDocModule MyModule stylesheet:MyStylesheet { }
If you use a stylesheet in a Module, you will have to use the same stylesheet in all the Generators where this Module is imported.
Usage : Declaration of a Module with variable styles
pxDocModule MyModule styles: Title1, Titl2, BulletList { }
Keyword 'template'
Templates is where the magic of pxDoc happens.
Templates can be considered as regular java methods since:
- you can design your template signature (template parameters)
- you can declare local variables
- you can use almost all conditional (if-then-else), switch, or iteration instructions (for, while...).
... but with an extra set of built-in keywords dedicated to document generation:
- about resources: document, subDocument, image
- about styling: #, HeadingN, font, bold, italic, color, underline...
- about navigation: bookmark, hyperlink
- about tables: table, row, cell
- about breaks: newPage, section, nextColumn...
- and misc: table of content, field, language, samePage, ...
<attributes> template templateName(args) { ... }
Attributes |
Description |
Possible values (if any) |
Optional |
root |
Set the template to launch in a pxDocGenerator |
One and only one template must be set as root in a pxDocGenerator |
Yes |
<public|private> |
Template visibility. |
public, private Public by default. |
Yes |
override |
Imported templates can be overridden by a local version of a template with the same java erasure. |
Yes |
|
templateName |
A name for the template |
Any valid java method name |
No |
(Type param1, ...) |
Parameters for the template |
Any valid java parameter declaration expression |
Yes |
Keyword 'apply'
Templates can be invoked using the special keyword apply.
apply templateName(arguments) separator {...}
Attributes |
Description |
Possible values (if any) |
Optional |
templateName |
The template to call |
Any visible template. |
No |
(Type param1, ...) |
Arguments given to the template |
Given parameters must match the signature of a visible template |
No |
separator {...} |
Inserts document elements (text, breaks, ...) between each template invocation |
Can be used in case of template invocation with an Iterable as first parameter. Content to be included between each template invocation is set inside '{' '}' and can contain any valid document elements. |
No |
Usages of template and apply keywords
Usage : Simplest template definition
template myTemplate() { // content }
Usage : Private template
private template myTemplate(Person person) { // content }
Usage : Root template
root template main(Model model) { // content }
Usage : Simple apply of a template
Templates can be invoked using the special keyword apply.
template prettyAddress(Address address) { address.number " " address.street ", " address.postalCode " " address.city } template myTemplate(Person person) { var Address mainAddress = person.mainAddress apply prettyAddress(mainAddress) // <- call to template 'prettyAddress(Address)'
When the first parameter given to the template being called is an Iterable, apply iterates the template invocation on each element.
template firstTemplate(Person person) { // this... apply prettyAddress(person.addresses) // is equivalent to for (address : person.addresses) { apply prettyAddress(address) } }
Usage : Insert a separator when iterating on templates
When iterating on templates, it is sometimes useful to separate template invocations with a separator:
template firstTemplate(Person person) { // the separator instruction includes a paragraph break (§) between each address apply prettyAddress(person.addresses) separator { § } // same behaviour with too much code ;-/ for (var i=0; i<person.addresses.size; i++) { apply prettyAddress(person.addresses.get(i)) if (i <person.addresses.size -1) { § } } }
Usage : A real-life example of template (used to generate this documentation!)
All document keywords used in this example will be explained further. Don't panic!
template toKeyword(Keyword keyword, int level) { // Specify a title with the keyword name HeadingN level:level {"Keyword '" keyword.keywordName "'" } // Insert the keyword declaration description apply toBasicExample(keyword.basicExamples) separator {§ } // Insert the introduction text for the keyword if (keyword.documentation !== null) { apply toDoc(keyword.documentation, level) } // Build the table with the keyword attributes if (!keyword.attributes.empty) { table { row header shadingColor:"0,0,0" { cell {"Attributes" } cell {"Description" } cell {"Possible values (if any)" } cell {"Optional" } } // Insert one row per attribute of the keyword apply attributeRow(keyword.attributes) } § } // Insert the conclusion text of the keyword if (keyword.conclusion !== null) { apply toDoc(keyword.conclusion, level) } // Insert the usages (examples) for the keyword apply toUsageExample(keyword.usageExamples) }
Keyword 'function'
All functions behaviors discussed in this section also apply to templates.
pxDoc functions are very similar to java methods:
function Object myFunction(String param1, boolean param2) { return param1 + param2; }
<attributes> function ReturnType functionName(arguments) {...}
Attributes |
Description |
Possible values (if any) |
Optional |
<public|private> |
Function visibility. |
public, private Public by default. |
Yes |
override |
Imported functions can be overridden by a local version of a function with the same java erasure. |
Yes |
|
functionName |
Function name |
Any valid java method name |
No |
(Type param1, ...) |
Parameters for the function |
Any valid java parameter declaration expression |
Yes |
As pxDoc is based on Xbase, it shares with it many valuable improvements and possible code simplifications (in comparison with java).
Excerpt from the Xbase documentation:
Conceptually and syntactically, Xbase is very close to Java statements and expressions, with a few exceptions:
- No checked exceptions
- Everything is an expression, there are no statements
- Lambda expressions
- Type inference
- Properties
- Simple operator overloading
- Powerful switch expressions
Implicit 'it' parameter
A function (or template) parameter named 'it' will allow you some extra simplifications in your code. Remember the template prettyAddress(Address address) we took as example ?
template prettyAddress(Address address) { address.number " " address.street ", " address.postalCode " " address.city }
With the it parameter, this template could have been written like this:
template prettyAddress(Address it) { number " " street ", " postalCode " " city }
Xbaselib extensions
The org.eclipse.xtext.xbase.lib provides a set of useful extensions that make complex things easy and short:
function void testExtensions(List<Book> books) { // Few IterableExtensions // in our (dummy) example, Book has subclasses Novel, Fantaisy, ... // filter(Class) filters elements instance of the specified class var novels = books.filter(Novel) // filter can take a lambda expression [] to carry out complex (or simple!) filter conditions: // books published in year 1984 var byYearBooks = books.filter[book | book.publicationYear === 1984] // IterableExtensions provides somes additional handy capabilities to express Integer ranges: var twoThousandBooks = books.filter[book | (2000..2009).contains(book.publicationYear)] // you can sort your Lists with sortBy... Just give the name of the attribute to make the sort var booksByYear = books.sortBy[publicationYear] var booksByTitle = books.sortBy[title] // you even sort using more powerful expressions var booksByAuthorName = books.sortBy[author.name] }
var / val
Variables can be declared with the var and val keywords.
- var is used to declare non-final variables.
- val is used to declare final variables. This is useful when you need to access a variable from a closure expression.
Variables can be defined:
- directly under pxDocGenerator or pxDocModule. In this case, they map to public fields under the underlying generator/module generated java classes.
- inside a pxDoc template or function. In this case, they map to a local variable of the underlying generated java method.
<var|val> <type>? name (= <initial>)?
Attributes |
Description |
Possible values (if any) |
Optional |
<var|val> |
Declare a variable |
var: non-final variables val: final variables |
No |
<type> |
The (java) type of the variable |
Any valid java type. Can be omitted since Xbase language support type inference |
Yes |
name |
Name of the variable |
Any valid java variable name. |
No |
= <initial> |
An initial value for the variable |
Any valid xbase/java expression. |
Yes |
Usage : In templates and functions:
var Type name = ... val Type name = ...
Usage : In pxDocGenerators and pxDocModules, you can also set the variable visibility:
private var String privateString = "Hello" public val String publicFinalString = "World"