From cb18e2cd0c0b1b9fba474d556e340afb978c42fc Mon Sep 17 00:00:00 2001 From: pantor Date: Mon, 14 May 2018 20:21:29 +0200 Subject: [PATCH] add in-memory includes via include_template --- README.md | 9 +++++++-- src/inja.hpp | 23 +++++++++++++++++------ test/src/unit-renderer.cpp | 23 +++++++++++++++++------ 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 9a59048..628c075 100644 --- a/README.md +++ b/README.md @@ -157,9 +157,14 @@ render("{% if not guest_count %}…{% endif %}", data); // True #### Includes -This includes other template files, relative from the current file location. +You can either include other template files or already parsed templates. ``` -{% include "footer.html" %} +// Other template files are included relative from the current file location +render({% include "footer.html" %}, data); + +// To include in-memory templates, add them to the environment first +env.include_template("footer", temp); +render({% include "footer" %}, data); ``` ### Functions diff --git a/src/inja.hpp b/src/inja.hpp index b1d4c65..56f051b 100644 --- a/src/inja.hpp +++ b/src/inja.hpp @@ -614,6 +614,10 @@ class Parser { public: ElementNotation element_notation = ElementNotation::Pointer; + std::map> regex_map_callbacks; + + std::map included_templates; + /*! @brief create a corresponding regex for a function name with a number of arguments seperated by , */ @@ -704,8 +708,6 @@ public: {Parsed::Function::ReadJson, Regex{"\\s*([^\\(\\)]*\\S)\\s*"}} }; - std::map> regex_map_callbacks; - Parser() { } Parsed::ElementExpression parse_expression(const std::string& input) { @@ -859,11 +861,16 @@ public: break; } case Parsed::Statement::Include: { - std::string included_filename = path + match_statement.str(1); - Template included_template = parse_template(included_filename); - for (auto& element: included_template.parsed_template().children) { - result.emplace_back(element); + std::string template_name = match_statement.str(1); + Template included_template; + if (included_templates.find( template_name ) != included_templates.end()) { + included_template = included_templates[template_name]; + } else { + included_template = parse_template(path + template_name); } + + auto children = included_template.parsed_template().children; + result.insert(result.end(), children.begin(), children.end()); break; } } @@ -1022,6 +1029,10 @@ public: renderer.map_callbacks[signature] = callback; } + void include_template(std::string name, const Template& temp) { + parser.included_templates[name] = temp; + } + template T get_argument(const Parsed::Arguments& args, int index, const json& data) { return renderer.eval_expression(args[index], data); diff --git a/test/src/unit-renderer.cpp b/test/src/unit-renderer.cpp index 4acad8c..d2f8a88 100644 --- a/test/src/unit-renderer.cpp +++ b/test/src/unit-renderer.cpp @@ -288,19 +288,30 @@ TEST_CASE("combinations") { } TEST_CASE("templates") { - inja::Environment env = inja::Environment(); - inja::Template temp = env.parse("{% if is_happy %}{{ name }}{% else %}{{ city }}{% endif %}"); - json data; data["name"] = "Peter"; data["city"] = "Brunswick"; data["is_happy"] = true; - CHECK( env.render_template(temp, data) == "Peter" ); + SECTION("reuse") { + inja::Environment env = inja::Environment(); + inja::Template temp = env.parse("{% if is_happy %}{{ name }}{% else %}{{ city }}{% endif %}"); - data["is_happy"] = false; + CHECK( env.render_template(temp, data) == "Peter" ); - CHECK( env.render_template(temp, data) == "Brunswick" ); + data["is_happy"] = false; + + CHECK( env.render_template(temp, data) == "Brunswick" ); + } + + SECTION("include") { + inja::Environment env = inja::Environment(); + inja::Template t1 = env.parse("Hello {{ name }}"); + env.include_template("greeting", t1); + + inja::Template t2 = env.parse("{% include \"greeting\" %}!"); + CHECK( env.render_template(t2, data) == "Hello Peter!" ); + } } TEST_CASE("other-syntax") {