You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
C++ implementation of big subset of Jinja 2 template engine features. This library was inspired by [Jinja2CppLight](https://github.com/hughperkins/Jinja2CppLight) project and brings support of mostly all Jinja 2 templates features into C++ world. Unlike [inja](https://github.com/pantor/inja) lib, you have to build Jinja2Cpp, but it has only one dependence: boost.
11
+
# Table of contents
12
+
13
+
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
14
+
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-[Link with you projects](#link-with-you-projects)
29
+
-[Changelog](#changelog)
30
+
-[Version 0.6](#version-06)
31
+
32
+
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
33
+
34
+
# Introduction
35
+
36
+
C++ implementation of big subset of Jinja2 template engine features. This library was inspired by [Jinja2CppLight](https://github.com/hughperkins/Jinja2CppLight) project and brings support of mostly all Jinja2 templates features into C++ world. Unlike [inja](https://github.com/pantor/inja) lib, you have to build Jinja2Cpp, but it has only one dependence: boost.
10
37
11
38
Main features of Jinja2Cpp:
12
39
- Easy-to-use public interface. Just load templates and render them.
13
-
- Support for both narrow- and wide-character strings both for templates and parameters.
40
+
- Conformance to [Jinja2 specification](http://jinja.pocoo.org/docs/2.10/)
41
+
- Partial support for both narrow- and wide-character strings both for templates and parameters.
14
42
- Built-in reflection for C++ types.
15
-
- Powerful Jinja 2 expressions with filtering (via '|' operator) and 'if' expressions.
16
-
- Main control statements (set, for, if).
43
+
- Powerful full-featured Jinja2 expressions with filtering (via '|' operator) and 'if'-expressions.
44
+
- Basic control statements (set, for, if).
45
+
- Templates extention.
17
46
18
-
For example, this simple code:
47
+
For instance, this simple code:
19
48
20
49
```c++
21
50
std::string source = R"(
@@ -44,7 +73,7 @@ hello; world!!!
44
73
In order to use Jinja2Cpp in your project you have to:
Of course, you can write this producer in the way like this:
138
+
Of course, you can write this producer in the way like [this](https://github.com/flexferrum/autoprogrammer/blob/87a9dc8ff61c7bdd30fede249757b71984e4b954/src/generators/enum2string_generator.cpp#L140). It's too complicated for writing 'from scratch'. Actually, there is a better and simpler way.
110
139
140
+
### The simplest case
141
+
142
+
Firstly, you should define the simple jinja2 template (in the C++ manner):
As you can see, this template is similar to the C++ sample code above, but some parts replaced by placeholders ("parameters"). These placeholders will be replaced with the actual text during template rendering process. In order to this happen, you should fill up the rendering parameters. This is a simple dictionary which maps the parameter name to the corresponding value:
134
158
135
-
Too complicated for writing 'from scratch'. Actually, there is a better and simpler way.
159
+
```c++
160
+
jinja2::ValuesMap params {
161
+
{"enumName", "Animals"},
162
+
{"items", {"Dog", "Cat", "Monkey", "Elephant"}},
163
+
};
164
+
```
165
+
An finally, you can render this template with Jinja2Cpp library:
136
166
137
-
### The simplest case
138
-
Firstly, you have to define enum description structure:
167
+
```c++
168
+
jinja2::Template tpl;
169
+
tpl.Load(enum2StringConvertor);
170
+
std::cout << tpl.RenderAsString(params);
171
+
```
172
+
And you will get on the console the conversion function mentioned above!
173
+
174
+
You can call 'Render' method many times, with different parameters set, from several threads. Everything will be fine: every time you call 'Render' you will get the result depended only on provided params. Also you can render some part of template many times (for different parameters) with help of 'for' loop and 'extend' statement (described below). It allows you to iterate through the list of items from the first to the last one and render the loop body for each item respectively. In this particular sample it allows to put as many 'case' blocks in conversion function as many items in the 'reflected' enum.
175
+
176
+
### Reflection
177
+
Let's imagine you don't want to fill the enum descriptor by hand, but want to fill it with help of some code parsing tool ([autoprogrammer](https://github.com/flexferrum/autoprogrammer) or [cppast](https://github.com/foonathan/cppast)). In this case you can define structure like this:
139
178
140
179
```c++
141
180
// Enum declaration description
142
181
structEnumDescriptor
143
182
{
144
-
// Enumeration name
145
-
std::string enumName;
146
-
// Namespace scope prefix
147
-
std::string nsScope;
148
-
// Collection of enum items
149
-
std::vector<std::string> enumItems;
183
+
// Enumeration name
184
+
std::string enumName;
185
+
// Namespace scope prefix
186
+
std::string nsScope;
187
+
// Collection of enum items
188
+
std::vector<std::string> enumItems;
150
189
};
151
190
```
152
-
153
-
This structure holds the enum name, enum namespace scope prefix, and list of enum items (we need just names). Then, you can create populate instances of this descriptor automatically using clang front-end (ex. here: [clang-based enum2string converter generator](https://github.com/flexferrum/flex_lib/blob/accu2017/tools/codegen/src/main.cpp) ). For our sample we create the instance manually:
154
-
191
+
This structure holds the enum name, enum namespace scope prefix, and list of enum items (we need just names). Then, you can populate instances of this descriptor automatically using chosen tool (ex. here: [clang-based enum2string converter generator](https://github.com/flexferrum/flex_lib/blob/accu2017/tools/codegen/src/main.cpp) ). For our sample we can create the instance manually:
And you will get on the console the conversion function mentioned above.
190
207
191
-
### Reflection
192
-
Actually, with Jinja2Cpp you don't need to transfer data from your internal structures to the Jinja2 values map. Library can do it for you. You just need to define reflection rules. Something like this:
208
+
But actually, with Jinja2Cpp you don't have to do it manually. Library can do it for you. You just need to define reflection rules. Something like this:
Every specified field will be reflected into Jinja2Cpp internal data structures and can be accessed from the template without additional efforts. Quite simply!
249
+
Every specified field will be reflected into Jinja2Cpp internal data structures and can be accessed from the template without additional efforts. Quite simply! As you can see, you can use 'dot' notation to access named members of some parameter as well, as index notation like this: `enum['enumName']`. With index notation you can access to the particular item of a list: `enum.items[3]` or `enum.items[itemIndex]` or `enum['items'][itemIndex]`.
233
250
234
251
### 'set' statement
235
252
But what if enum `Animals` will be in the namespace?
@@ -248,7 +265,8 @@ enum Animals
248
265
```
249
266
In this case you need to prefix both enum name and it's items with namespace prefix in the generated code. Like this:
This template will produce 'world::' prefix for our new enum (and enum itmes). And '::' for the previous one. But you may want to get rid of unnecessary global scope prefix. And you can do it this way:
281
+
This template will produce 'world::' prefix for our new scoped enum (and enum itmes). And '::' for the ones in global scope. But you may want to eliminate the unnecessary global scope prefix. And you can do it this way:
264
282
```c++
265
283
{% set prefix = enum.nsScope + '::' if enum.nsScope else '' %}
I.e. left part of this expression (before 'if') is a true-branch of the statement. Right part (after 'else') - false-branch, which could be omitted. As a condition you can use any expression, convertible to bool.
302
+
I.e. left part of this expression (before 'if') is a true-branch of the statement. Right part (after 'else') - false-branch, which can be omitted. As a condition you can use any expression convertible to bool.
285
303
286
304
## Other features
287
305
The render procedure is stateless, so you can perform several renderings simultaneously in different threads. Even if you pass parameters:
0 commit comments