Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returnable template #346

Merged
merged 3 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/guides/templating.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ To return a mustache template, you need to load a page using `#!cpp auto page =
You also need to set up the context by using `#!cpp crow::mustache::context ctx;`. Then you need to assign the keys and values, this can be done the same way you assign values to a json write value (`ctx["key"] = value;`).<br>
With your context and page ready, just `#!cpp return page.render(ctx);`. This will use the context data to return a filled template.<br>
Alternatively you could just render the page without a context using `#!cpp return page.render();`.

!!! note

`#!cpp page.render();` returns a crow::returnable class in order to set the `Content-Type` header. to get a simple string, use `#!cpp page.render_string()` instead.

49 changes: 46 additions & 3 deletions include/crow/mustache.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <functional>
#include "crow/json.h"
#include "crow/logging.h"
#include "crow/returnable.h"
#include "crow/utility.h"

namespace crow
Expand All @@ -29,6 +30,22 @@ namespace crow
std::string msg;
};

struct rendered_template : returnable
{
rendered_template():
returnable("text/html") {}

rendered_template(std::string& body):
returnable("text/html"), body_(std::move(body)) {}

std::string body_;

std::string dump() const override
{
return body_;
}
};

enum class ActionType
{
Ignore,
Expand Down Expand Up @@ -231,7 +248,7 @@ namespace crow
while (execute_result.find("{{") != std::string::npos)
{
template_t result_plug(execute_result);
execute_result = result_plug.render(*(stack[0]));
execute_result = result_plug.render_string(*(stack[0]));
}

if (action.t == ActionType::Tag)
Expand Down Expand Up @@ -339,7 +356,31 @@ namespace crow
}

public:
std::string render() const
/// Output a returnable template from this mustache template
rendered_template render() const
{
context empty_ctx;
std::vector<context*> stack;
stack.emplace_back(&empty_ctx);

std::string ret;
render_internal(0, fragments_.size() - 1, stack, ret, 0);
return rendered_template(ret);
}

/// Apply the values from the context provided and output a returnable template from this mustache template
rendered_template render(context& ctx) const
{
std::vector<context*> stack;
stack.emplace_back(&ctx);

std::string ret;
render_internal(0, fragments_.size() - 1, stack, ret, 0);
return rendered_template(ret);
}

/// Output a returnable template from this mustache template
std::string render_string() const
{
context empty_ctx;
std::vector<context*> stack;
Expand All @@ -349,7 +390,9 @@ namespace crow
render_internal(0, fragments_.size() - 1, stack, ret, 0);
return ret;
}
std::string render(context& ctx) const

/// Apply the values from the context provided and output a returnable template from this mustache template
std::string render_string(context& ctx) const
{
std::vector<context*> stack;
stack.emplace_back(&ctx);
Expand Down
2 changes: 1 addition & 1 deletion tests/template/mustachetest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ int main()
return "";
});
context ctx(data);
cout << templ.render(ctx);
cout << templ.render_string(ctx);
return 0;
}
33 changes: 30 additions & 3 deletions tests/unittest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@ TEST_CASE("template_basic")
auto t = crow::mustache::compile(R"---(attack of {{name}})---");
crow::mustache::context ctx;
ctx["name"] = "killer tomatoes";
auto result = t.render(ctx);
auto result = t.render_string(ctx);
CHECK("attack of killer tomatoes" == result);
} // template_basic

Expand All @@ -1148,7 +1148,7 @@ TEST_CASE("template_function")
ctx["func"] = [&](std::string) {
return std::string("{{name}}, IN SPACE!");
};
auto result = t.render(ctx);
auto result = t.render_string(ctx);
CHECK("attack of killer tomatoes, IN SPACE!" == result);
}

Expand All @@ -1159,11 +1159,38 @@ TEST_CASE("template_load")
auto t = crow::mustache::load("test.mustache");
crow::mustache::context ctx;
ctx["name"] = "killer tomatoes";
auto result = t.render(ctx);
auto result = t.render_string(ctx);
CHECK("attack of killer tomatoes" == result);
unlink("test.mustache");
} // template_load

TEST_CASE("TemplateRouting")
{
SimpleApp app;

CROW_ROUTE(app, "/temp")
([] {
auto t = crow::mustache::compile(R"---(attack of {{name}})---");
crow::mustache::context ctx;
ctx["name"] = "killer tomatoes";
return crow::response(t.render(ctx));
});

app.validate();

{
request req;
response res;

req.url = "/temp";

app.handle(req, res);

CHECK("attack of killer tomatoes" == res.body);
CHECK("text/html" == crow::get_header_value(res.headers, "Content-Type"));
}
} // PathRouting

TEST_CASE("black_magic")
{
using namespace black_magic;
Expand Down