https://github.com/pantor/inja
#include <inja/inja.hpp>
// Just for convenience
using namespace inja;
void testFile() {
Environment env;
json data;
// Render a string with json data
std::string result = env.render("Hello {{ name }}!", data); // "Hello world!"
// Or directly read a template file
Template temp = env.parse_template("./templates/greeting.txt");
result = env.render(temp, data); // "Hello world!"
data["name"] = "Inja";
result = env.render(temp, data); // "Hello Inja!"
// Or read the template file (and/or the json file) directly from the environment
result = env.render_file("./templates/greeting.txt", data);
result = env.render_file_with_json_file("./templates/greeting.txt", "./data.json");
// Or write a rendered template file
env.write(temp, data, "./result.txt");
env.write_with_json_file("./templates/greeting.txt", "./data.json", "./result.txt");
}
void testFunc() {
Environment env;
json data;
// Upper and lower function, for string cases
render("Hello {{ upper(neighbour) }}!", data); // "Hello PETER!"
render("Hello {{ lower(neighbour) }}!", data); // "Hello peter!"
// Range function, useful for loops
render("{% for i in range(4) %}{{ loop.index1 }}{% endfor %}", data); // "1234"
render("{% for i in range(3) %}{{ at(guests, i) }} {% endfor %}", data); // "Jeff Tom Patrick "
// Length function (please don't combine with range, use list directly...)
render("I count {{ length(guests) }} guests.", data); // "I count 3 guests."
// Get first and last element in a list
render("{{ first(guests) }} was first.", data); // "Jeff was first."
render("{{ last(guests) }} was last.", data); // "Patir was last."
// Sort a list
render("{{ sort([3,2,1]) }}", data); // "[1,2,3]"
render("{{ sort(guests) }}", data); // "[\"Jeff\", \"Patrick\", \"Tom\"]"
// Join a list with a separator
render("{{ join([1,2,3], \" + \") }}", data); // "1 + 2 + 3"
render("{{ join(guests, \", \") }}", data); // "Jeff, Patrick, Tom"
// Round numbers to a given precision
render("{{ round(3.1415, 0) }}", data); // 3
render("{{ round(3.1415, 3) }}", data); // 3.142
// Check if a value is odd, even or divisible by a number
render("{{ odd(42) }}", data); // false
render("{{ even(42) }}", data); // true
render("{{ divisibleBy(42, 7) }}", data); // true
// Maximum and minimum values from a list
render("{{ max([1, 2, 3]) }}", data); // 3
render("{{ min([-2.4, -1.2, 4.5]) }}", data); // -2.4
// Convert strings to numbers
render("{{ int(\"2\") == 2 }}", data); // true
render("{{ float(\"1.8\") > 2 }}", data); // false
// Set default values if variables are not defined
render("Hello {{ default(neighbour, \"my friend\") }}!", data); // "Hello Peter!"
render("Hello {{ default(colleague, \"my friend\") }}!", data); // "Hello my friend!"
// Access an objects value dynamically
render("{{ at(time, \"start\") }} to {{ time.end }}", data); // "16 to 22"
// Check if a key exists in an object
render("{{ exists(\"guests\") }}", data); // "true"
render("{{ exists(\"city\") }}", data); // "false"
render("{{ existsIn(time, \"start\") }}", data); // "true"
render("{{ existsIn(time, neighbour) }}", data); // "false"
// Check if a key is a specific type
render("{{ isString(neighbour) }}", data); // "true"
render("{{ isArray(guests) }}", data); // "true"
// Implemented type checks: isArray, isBoolean, isFloat, isInteger, isNumber, isObject, isString,
}
void testCallback() {
Environment env;
json data;
/*
* Callbacks are defined by its:
* - name,
* - (optional) number of arguments,
* - callback function.
*/
env.add_callback("double", 1, [](Arguments& args) {
int number = args.at(0)->get<int>(); // Adapt the index and type of the argument
return 2 * number;
});
// You can then use a callback like a regular function
env.render("{{ double(16) }}", data); // "32"
// Inja falls back to variadic callbacks if the number of expected arguments is omitted.
env.add_callback("argmax", [](Arguments& args) {
auto result = std::max_element(args.begin(), args.end(), [](const json* a, const json* b) { return *a < *b; });
return std::distance(args.begin(), result);
});
env.render("{{ argmax(4, 2, 6) }}", data); // "2"
env.render("{{ argmax(0, 2, 6, 8, 3) }}", data); // "3"
// A callback without argument can be used like a dynamic variable:
std::string greet = "Hello";
env.add_callback("double-greetings", 0, [greet](Arguments args) {
return greet + " " + greet + "!";
});
env.render("{{ double-greetings }}", data); // "Hello Hello!"
env.add_void_callback("log", 1, [greet](Arguments args) {
std::cout << "logging: " << args[0] << std::endl;
});
env.render("{{ log(neighbour) }}", data); // Prints nothing to result, only to cout...
}
void test() {
json data;
data["name"] = "world";
render("Hello {{ name }}!", data); // Returns std::string "Hello world!"
render_to(std::cout, "Hello {{ name }}!", data); // Writes "Hello world!" to stream
//testFile(); // 文件读写
// With default settings
Environment env_default;
// With global path to template files and where files will be saved
Environment env_1{ "../path/templates/" };
// With separate input and output path
Environment env_2{ "../path/templates/", "../path/results/" };
// With other opening and closing strings (here the defaults)
Environment env;
env.set_expression("{{", "}}"); // Expressions
env.set_comment("{#", "#}"); // Comments
env.set_statement("{%", "%}"); // Statements {% %} for many things, see below
env.set_line_statement("##"); // Line statements ## (just an opener)
// json成员解析
data["neighbour"] = "Peter";
data["guests"] = { "Jeff", "Tom", "Patrick" };
data["time"]["start"] = 16;
data["time"]["end"] = 22;
// Indexing in array
render("{{ guests.1 }}", data); // "Tom"
// Objects
render("{{ time.start }} to {{ time.end + 1 }}pm", data); // "16 to 23pm"
// If no variable is found, valid JSON is printed directly, otherwise an inja::RenderError is thrown.
// Combining loops and line statements
//render(R"(Guest List: ## for guest in guests {{ loop.index1 }}: {{ guest }} ## endfor )", data);
// loop.is_first loop.is_last loop.parent.index {% for key, value in time %}
// Conditions
// Standard comparisons with a variable
render("{% if time.hour >= 20 %}Serve{% else if time.hour >= 18 %}Make{% endif %} dinner.", data); // Serve dinner.
// Variable in list
render("{% if neighbour in guests %}Turn up the music!{% endif %}", data); // Turn up the music!
// Logical operations
render("{% if guest_count < (3+2) and all_tired %}Sleepy...{% else %}Keep going...{% endif %}", data); // Sleepy...
// Negations
render("{% if not guest_count %}The End{% endif %}", data); // The End
// To include in-memory templates, add them to the environment first
inja::Template content_template = env.parse("Hello {{ neighbour }}!");
env.include_template("content", content_template);
env.render("Content: {% include \"content\" %}", data); // "Content: Hello Peter!"
// Other template files are included relative from the current file location
render("{% include \"footer.html\" %}", data);
// The callback takes the current path and the wanted include name and returns a template
env.set_include_callback([&env](const std::string& path, const std::string& template_name) {
return env.parse("Hello {{ neighbour }} from " + template_name);
});
// You can disable to search for templates in the file system via
env.set_search_included_templates_in_files(false); // env.set_throw_at_missing_includes(false)
render("{% set new_hour=23 %}{{ new_hour }}pm", data); // "23pm"
render("{% set time.start=18 %}{{ time.start }}pm", data); // using json pointers
env.set_trim_blocks(true);
env.set_lstrip_blocks(true);
render("Hello{# Todo #}!", data); // "Hello!"
// INJA_NOEXCEPTION
}
// 从模板创建单例类
void createSingletonClass() {
std::string tmplH = "class {{port}} {{name}} \n{\npublic:\n using SP = std::shared_ptr<{{name}}>;\n\n static {{name}} *getInstance();\n static void release();\npublic:\n static {{name}} *m_instance;\n};\n";
std::string tmplCpp = "{{name}} *{{name}}::m_instance = nullptr;\n{{name}} *{{name}}::getInstance(){\n if(!m_instance){\n m_instnace = new {{name}}();\n }\n return m_instance;\n}\n";
std::string tmplCpp2 = "void *{{name}}::release(){\n if(m_instance){\n\tdelete m_instnace; \n }\n m_instance = nullptr;\n}\n";
json data;
data["name"] = "Singleton";
data["port"] = "";
render_to(std::cout, tmplH, data);
render_to(std::cout, tmplCpp + tmplCpp2, data);
}
输出:
class Singleton
{
public:
using SP = std::shared_ptr<Singleton>;
static Singleton *getInstance();
static void release();
public:
static Singleton *m_instance;
};
Singleton *Singleton::m_instance = nullptr;
Singleton *Singleton::getInstance(){
if(!m_instance){
m_instnace = new Singleton();
}
return m_instance;
}
void *Singleton::release(){
if(m_instance){
delete m_instnace;
}
m_instance = nullptr;
}