use node as lambda return type
This commit is contained in:
parent
e122db3d14
commit
355601bc3a
15
README.md
15
README.md
@ -103,15 +103,17 @@ Output:
|
||||
|
||||
C++11 lambda expressions can be used to add logic to your templates. Like a
|
||||
`const char*` literal, lambdas can be implicitly converted to `bool`, so they
|
||||
must be wrapped in a `mstch::lambda` object when used in a `mstch::node`.
|
||||
must be wrapped in a `mstch::lambda` object when used in a `mstch::node`. The
|
||||
lambda expression passed to `mstch::lambda` must itself return a `mstch::node`.
|
||||
The returned node will be rendered to a string, then it will be parsed as a
|
||||
template.
|
||||
|
||||
The lambda expression passed to `mstch::lambda` returns a `std::string` and
|
||||
accepts either no parameters:
|
||||
The lambda expression accepts either no parameters:
|
||||
|
||||
```c++
|
||||
std::string view{"Hello {{lambda}}!"};
|
||||
mstch::map context{
|
||||
{"lambda", mstch::lambda{[]() {
|
||||
{"lambda", mstch::lambda{[]() -> mstch::node {
|
||||
return std::string{"World"};
|
||||
}}}
|
||||
};
|
||||
@ -125,14 +127,13 @@ Output:
|
||||
Hello World!
|
||||
```
|
||||
|
||||
Or it accepts a `const std::string&` that gets the unrendered literal block.
|
||||
The returned string will be parsed in both cases:
|
||||
Or it accepts a `const std::string&` that gets the unrendered literal block:
|
||||
|
||||
```c++
|
||||
std::string view{"{{#bold}}{{yay}} :){{/bold}}"};
|
||||
mstch::map context{
|
||||
{"yay", std::string{"Yay!"}},
|
||||
{"bold", mstch::lambda{[](const std::string& text) {
|
||||
{"bold", mstch::lambda{[](const std::string& text) -> mstch::node {
|
||||
return "<b>" + text + "</b>";
|
||||
}}}
|
||||
};
|
||||
|
@ -35,7 +35,7 @@ class object_t {
|
||||
mutable std::map<std::string, N> cache;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template<class T, class N>
|
||||
class is_fun {
|
||||
private:
|
||||
using not_fun = char;
|
||||
@ -43,9 +43,9 @@ class is_fun {
|
||||
using fun_with_args = char[3];
|
||||
template <typename U, U> struct really_has;
|
||||
template <typename C> static fun_without_args& test(
|
||||
really_has<std::string(C::*)() const, &C::operator()>*);
|
||||
really_has<N(C::*)() const, &C::operator()>*);
|
||||
template <typename C> static fun_with_args& test(
|
||||
really_has<std::string(C::*)(const std::string&) const,
|
||||
really_has<N(C::*)(const std::string&) const,
|
||||
&C::operator()>*);
|
||||
template <typename> static not_fun& test(...);
|
||||
|
||||
@ -54,36 +54,48 @@ class is_fun {
|
||||
static bool const has_args = sizeof(test<T>(0)) == sizeof(fun_with_args);
|
||||
};
|
||||
|
||||
}
|
||||
template<class N>
|
||||
using node_renderer = std::function<std::string(const N& n)>;
|
||||
|
||||
class lambda {
|
||||
template<class N>
|
||||
class lambda_t {
|
||||
public:
|
||||
template<class F>
|
||||
lambda(F f, typename std::enable_if<internal::is_fun<F>::no_args>::type* =0):
|
||||
fun([f](const std::string&){return f();})
|
||||
lambda_t(F f, typename std::enable_if<is_fun<F, N>::no_args>::type* = 0):
|
||||
fun([f](node_renderer<N> renderer, const std::string&) {
|
||||
return renderer(f());
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
template<class F>
|
||||
lambda(F f, typename std::enable_if<internal::is_fun<F>::has_args>::type* =0):
|
||||
fun(f)
|
||||
lambda_t(F f, typename std::enable_if<is_fun<F, N>::has_args>::type* = 0):
|
||||
fun([f](node_renderer<N> renderer, const std::string& text) {
|
||||
return renderer(f(text));
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
std::string operator()(const std::string& text = "") const {
|
||||
return fun(text);
|
||||
std::string operator()(node_renderer<N> renderer,
|
||||
const std::string& text = "") const
|
||||
{
|
||||
return fun(renderer, text);
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<std::string(const std::string&)> fun;
|
||||
std::function<std::string(node_renderer<N> renderer, const std::string&)> fun;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using node = boost::make_recursive_variant<
|
||||
std::nullptr_t, std::string, int, double, bool, lambda,
|
||||
std::nullptr_t, std::string, int, double, bool,
|
||||
internal::lambda_t<boost::recursive_variant_>,
|
||||
std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
|
||||
std::map<const std::string, boost::recursive_variant_>,
|
||||
std::vector<boost::recursive_variant_>>::type;
|
||||
using object = internal::object_t<node>;
|
||||
using lambda = internal::lambda_t<node>;
|
||||
using map = std::map<const std::string, node>;
|
||||
using array = std::vector<node>;
|
||||
|
||||
|
@ -37,7 +37,10 @@ class render_node: public boost::static_visitor<std::string> {
|
||||
}
|
||||
|
||||
std::string operator()(const lambda& value) const {
|
||||
auto rendered = render_context::push(ctx).render(template_type{value()});
|
||||
template_type interpreted{value([this](const mstch::node& n) {
|
||||
return visit(render_node(ctx), n);
|
||||
})};
|
||||
auto rendered = render_context::push(ctx).render(interpreted);
|
||||
return (m_flag == flag::escape_html) ? html_escape(rendered) : rendered;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "render_context.hpp"
|
||||
#include "mstch/mstch.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "render_node.hpp"
|
||||
|
||||
namespace mstch {
|
||||
|
||||
@ -28,8 +29,10 @@ class render_section: public boost::static_visitor<std::string> {
|
||||
std::string section_str;
|
||||
for(auto& token: section)
|
||||
section_str += token.raw();
|
||||
|
||||
return render_context::push(ctx).render(template_type{fun(section_str)});
|
||||
template_type interpreted{fun([this](const mstch::node& n) {
|
||||
return visit(render_node(ctx), n);
|
||||
}, section_str)};
|
||||
return render_context::push(ctx).render(interpreted);
|
||||
}
|
||||
|
||||
std::string operator()(const array& array) const {
|
||||
|
@ -1,3 +1,3 @@
|
||||
const mstch::node comments_data = mstch::map{
|
||||
{"title", mstch::lambda{[](){return std::string{"A Comedy of Errors"};}}}
|
||||
{"title", mstch::lambda{[]()->mstch::node{return std::string{"A Comedy of Errors"};}}}
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
const mstch::node escaped_data = mstch::map{
|
||||
{"title", mstch::lambda{[](){ return std::string{"Bear > Shark"}; }}},
|
||||
{"entities", mstch::lambda{[](){ return std::string{"" \"'<>/"}; }}}
|
||||
{"title", mstch::lambda{[]()->mstch::node{ return std::string{"Bear > Shark"}; }}},
|
||||
{"entities", mstch::lambda{[]()->mstch::node{ return std::string{"" \"'<>/"}; }}}
|
||||
};
|
@ -19,7 +19,7 @@ class higher_order_sections: public mstch::object {
|
||||
}
|
||||
|
||||
mstch::node bolder() {
|
||||
return mstch::lambda{[this](const std::string& text) {
|
||||
return mstch::lambda{[this](const std::string& text) -> mstch::node {
|
||||
return "<b>" + text + "</b> " + m_helper;
|
||||
}};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
const mstch::node nested_higher_order_sections_data = mstch::map{
|
||||
{"bold", mstch::lambda{[](const std::string& text) {
|
||||
{"bold", mstch::lambda{[](const std::string& text) -> mstch::node {
|
||||
return std::string{"<b>"} + text + std::string{"</b>"};
|
||||
}}},
|
||||
{"person", mstch::map{{"name", std::string{"Jonas"}}}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
const mstch::node partial_template_data = mstch::map{
|
||||
{"title", mstch::lambda{[](){ return std::string{"Welcome"}; }}},
|
||||
{"again", mstch::lambda{[](){ return std::string{"Goodbye"}; }}},
|
||||
{"title", mstch::lambda{[]()->mstch::node{ return std::string{"Welcome"}; }}},
|
||||
{"again", mstch::lambda{[]()->mstch::node{ return std::string{"Goodbye"}; }}},
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
const mstch::node section_functions_in_partials_data = mstch::map{
|
||||
{"bold", mstch::lambda{[](const std::string& text) {
|
||||
{"bold", mstch::lambda{[](const std::string& text) -> mstch::node {
|
||||
return std::string{"<b>"} + text + std::string{"</b>"};
|
||||
}}}
|
||||
};
|
@ -1,3 +1,3 @@
|
||||
const mstch::node unescaped_data = mstch::map{
|
||||
{"title", mstch::lambda{[](){ return std::string{"Bear > Shark"}; }}}
|
||||
{"title", mstch::lambda{[]()->mstch::node{ return std::string{"Bear > Shark"}; }}}
|
||||
};
|
@ -1,26 +1,26 @@
|
||||
std::map<std::string,std::function<std::string(const std::string&)>> specs_lambdas {
|
||||
std::map<std::string,std::function<mstch::node(const std::string&)>> specs_lambdas {
|
||||
{"Interpolation", [](const std::string&) {
|
||||
return "world";
|
||||
return std::string{"world"};
|
||||
}},
|
||||
{"Interpolation - Expansion", [](const std::string&) {
|
||||
return "{{planet}}";
|
||||
return std::string{"{{planet}}"};
|
||||
}},
|
||||
{"Interpolation - Multiple Calls", [](const std::string&) {
|
||||
static int calls = 0; return std::to_string(++calls);
|
||||
static int calls = 0; return ++calls;
|
||||
}},
|
||||
{"Escaping", [](const std::string&) {
|
||||
return ">";
|
||||
return std::string{">"};
|
||||
}},
|
||||
{"Section", [](const std::string& txt) {
|
||||
return (txt == "{{x}}") ? "yes" : "no";
|
||||
return std::string{(txt == "{{x}}") ? "yes" : "no"};
|
||||
}},
|
||||
{"Section - Expansion", [](const std::string& txt) {
|
||||
return txt + "{{planet}}" + txt;
|
||||
return txt + std::string{"{{planet}}"} + txt;
|
||||
}},
|
||||
{"Section - Multiple Calls", [](const std::string& txt) {
|
||||
return "__" + txt + "__";
|
||||
}},
|
||||
{"Inverted Section", [](const std::string& txt) {
|
||||
return "";
|
||||
return false;
|
||||
}}
|
||||
};
|
Loading…
Reference in New Issue
Block a user