retain scope when including a template (#118)
* apply documentation changes to single_include
* retain scope when including a template
* Use data from current scope when rendering an included template.
This allows included templates to access loop variables, which
was not possible before.
* Add test
diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp
index 4cd530d..d3ced6f 100644
--- a/include/inja/renderer.hpp
+++ b/include/inja/renderer.hpp
@@ -454,7 +454,7 @@
break;
}
case Bytecode::Op::Include:
- Renderer(m_included_templates, m_callbacks).render_to(os, m_included_templates.find(get_imm(bc)->get_ref<const std::string&>())->second, data);
+ Renderer(m_included_templates, m_callbacks).render_to(os, m_included_templates.find(get_imm(bc)->get_ref<const std::string&>())->second, *m_data);
break;
case Bytecode::Op::Callback: {
auto callback = m_callbacks.find_callback(bc.str, bc.args);
diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp
index 80b3d68..a6ad38e 100644
--- a/single_include/inja/inja.hpp
+++ b/single_include/inja/inja.hpp
@@ -1360,6 +1360,9 @@
Pointer
};
+/*!
+ * \brief Class for lexer configuration.
+ */
struct LexerConfig {
std::string statement_open {"{%"};
std::string statement_close {"%}"};
@@ -1390,6 +1393,9 @@
}
};
+/*!
+ * \brief Class for parser configuration.
+ */
struct ParserConfig {
ElementNotation notation {ElementNotation::Dot};
};
@@ -1547,6 +1553,9 @@
using Arguments = std::vector<const json*>;
using CallbackFunction = std::function<json(Arguments& args)>;
+/*!
+ * \brief Class for builtin functions and user-defined callbacks.
+ */
class FunctionStorage {
public:
void add_builtin(nonstd::string_view name, unsigned int num_args, Bytecode::Op op) {
@@ -1637,6 +1646,9 @@
namespace inja {
+/*!
+ * \brief Helper-class for the inja Parser.
+ */
struct Token {
enum class Kind {
Text,
@@ -1748,6 +1760,9 @@
namespace inja {
+/*!
+ * \brief Class for lexing an inja Template.
+ */
class Lexer {
enum class State {
Text,
@@ -2052,6 +2067,9 @@
namespace inja {
+/*!
+ * \brief The main inja Template.
+ */
struct Template {
std::vector<Bytecode> bytecodes;
std::string content;
@@ -2115,6 +2133,9 @@
FunctionStorage functions;
};
+/*!
+ * \brief Class for parsing an inja Template.
+ */
class Parser {
public:
explicit Parser(const ParserConfig& parser_config, const LexerConfig& lexer_config, TemplateStorage& included_templates): m_config(parser_config), m_lexer(lexer_config), m_included_templates(included_templates), m_static(ParserStatic::get_instance()) { }
@@ -2691,6 +2712,9 @@
return nonstd::string_view(out.data(), out.size());
}
+/*!
+ * \brief Class for rendering a Template with data.
+ */
class Renderer {
std::vector<const json*>& get_args(const Bytecode& bc) {
m_tmp_args.clear();
@@ -3118,7 +3142,7 @@
break;
}
case Bytecode::Op::Include:
- Renderer(m_included_templates, m_callbacks).render_to(os, m_included_templates.find(get_imm(bc)->get_ref<const std::string&>())->second, data);
+ Renderer(m_included_templates, m_callbacks).render_to(os, m_included_templates.find(get_imm(bc)->get_ref<const std::string&>())->second, *m_data);
break;
case Bytecode::Op::Callback: {
auto callback = m_callbacks.find_callback(bc.str, bc.args);
@@ -3251,6 +3275,9 @@
using namespace nlohmann;
+/*!
+ * \brief Class for changing the configuration.
+ */
class Environment {
class Impl {
public:
diff --git a/test/unit-renderer.cpp b/test/unit-renderer.cpp
index 1243470..b56cc45 100644
--- a/test/unit-renderer.cpp
+++ b/test/unit-renderer.cpp
@@ -380,6 +380,16 @@
CHECK( env.render(t2, data) == "Hello Peter!" );
CHECK_THROWS_WITH( env.parse("{% include \"does-not-exist\" %}!"), "[inja.exception.file_error] failed accessing file at 'does-not-exist'" );
}
+
+ SECTION("include-in-loop") {
+ json loop_data;
+ loop_data["cities"] = json::array({{{"name", "Munich"}}, {{"name", "New York"}}});
+
+ inja::Environment env;
+ env.include_template("city.tpl", env.parse("{{ loop.index }}:{{ city.name }};"));
+
+ CHECK( env.render("{% for city in cities %}{% include \"city.tpl\" %}{% endfor %}", loop_data) == "0:Munich;1:New York;" );
+ }
}