full lambda support

This commit is contained in:
Daniel Sipka 2015-04-23 15:55:18 +02:00
parent f4dd438fcc
commit 7bdde0783f
38 changed files with 142 additions and 207 deletions

View file

@ -40,17 +40,25 @@ using renderer = std::function<std::string(const std::string&)>;
class lambda {
public:
lambda(std::function<std::string(const std::string&,renderer)> fun):
lambda(std::function<std::string()> fun):
fun([fun](const std::string&, renderer){return fun();})
{
}
lambda(std::function<std::string(const std::string&, renderer)> fun):
fun(fun)
{
}
std::string operator()(const std::string& text, renderer renderer) const {
std::string operator()(
const std::string& text = "",
renderer renderer = renderer()) const
{
return fun(text, renderer);
}
private:
std::function<std::string(const std::string&,renderer)> fun;
std::function<std::string(const std::string&, renderer)> fun;
};
using node = boost::make_recursive_variant<

View file

@ -8,6 +8,12 @@ include_directories(
set(SRC
state/in_section.cpp
state/outside_section.cpp
state/render_state.hpp
visitor/get_token.hpp
visitor/has_token.hpp
visitor/is_node_empty.hpp
visitor/render_node.hpp
visitor/render_section.hpp
mstch.cpp
render_context.cpp
template_type.cpp

View file

@ -11,8 +11,8 @@ std::string mstch::render(
const node& root,
const std::map<std::string,std::string>& partials)
{
std::map<std::string, template_type> partial_templts;
std::map<std::string, template_type> partial_templates;
for (auto& partial: partials)
partial_templts.insert({partial.first, {partial.second}});
return render_context(root, partial_templts).render(tmplt);
partial_templates.insert({partial.first, {partial.second}});
return render_context(root, partial_templates).render(tmplt);
}

View file

@ -5,7 +5,6 @@
#include "visitor/has_token.hpp"
using namespace mstch;
using namespace mstch::visitor;
const mstch::node render_context::null_node;
@ -13,8 +12,7 @@ render_context::push::push(render_context& context, const mstch::node& node):
context(context)
{
context.nodes.emplace_front(node);
context.state.push(std::unique_ptr<state::render_state>(
new state::outside_section));
context.state.push(std::unique_ptr<render_state>(new outside_section));
}
render_context::push::~push() {
@ -29,11 +27,9 @@ std::string render_context::push::render(const template_type& templt) {
render_context::render_context(
const mstch::node& node,
const std::map<std::string, template_type>& partials):
partials{partials},
nodes{node}
partials{partials}, nodes{node}
{
state.push(std::unique_ptr<state::render_state>(
new state::outside_section));
state.push(std::unique_ptr<render_state>(new outside_section));
}
const mstch::node& render_context::find_node(
@ -41,8 +37,7 @@ const mstch::node& render_context::find_node(
const std::deque<node>& current_nodes)
{
if (token != "." && token.find('.') != std::string::npos)
return find_node(
token.substr(token.rfind('.') + 1),
return find_node(token.substr(token.rfind('.') + 1),
{find_node(token.substr(0, token.rfind('.')), current_nodes)});
else
for (auto& node: current_nodes)

View file

@ -30,7 +30,7 @@ class render_context {
std::string render_partial(const std::string& partial_name);
template<class T, class... Args>
void set_state(Args&& ... args) {
state.top() = std::unique_ptr<state::render_state>(
state.top() = std::unique_ptr<render_state>(
new T(std::forward<Args>(args)...));
}
@ -41,7 +41,7 @@ class render_context {
const std::deque<node>& current_nodes);
const std::map<std::string, template_type>& partials;
std::deque<mstch::node> nodes;
std::stack<std::unique_ptr<state::render_state>> state;
std::stack<std::unique_ptr<render_state>> state;
};
}

View file

@ -5,14 +5,13 @@
#include "utils.hpp"
using namespace mstch;
using namespace mstch::visitor;
state::in_section::in_section(type type, const std::string& section_name):
in_section::in_section(type type, const std::string& section_name):
m_type(type), section_name(section_name), skipped_openings(0)
{
}
std::string state::in_section::render(render_context& ctx, const token& token) {
std::string in_section::render(render_context& ctx, const token& token) {
if (token.token_type() == token::type::section_close)
if (token.name() == section_name && skipped_openings == 0) {
auto& node = ctx.get_node(section_name);

View file

@ -7,7 +7,6 @@
#include "template_type.hpp"
namespace mstch {
namespace state {
class in_section: public render_state {
public:
@ -25,4 +24,3 @@ class in_section: public render_state {
};
}
}

View file

@ -6,9 +6,8 @@
#include "utils.hpp"
using namespace mstch;
using namespace mstch::visitor;
std::string state::outside_section::render(
std::string outside_section::render(
render_context& ctx, const token& token)
{
using flag = render_node::flag;

View file

@ -3,7 +3,6 @@
#include "render_state.hpp"
namespace mstch {
namespace state {
class outside_section: public render_state {
public:
@ -11,4 +10,3 @@ class outside_section: public render_state {
};
}
}

View file

@ -8,12 +8,9 @@ namespace mstch {
class render_context;
namespace state {
class render_state {
public:
virtual std::string render(render_context& context, const token& token) = 0;
};
}
}

View file

@ -13,7 +13,7 @@ citer first_not_ws(criter begin, criter end);
std::string html_escape(std::string str);
template<class... Args>
auto visit(Args&& ... args) -> decltype(boost::apply_visitor(
auto visit(Args&&... args) -> decltype(boost::apply_visitor(
std::forward<Args>(args)...))
{
return boost::apply_visitor(std::forward<Args>(args)...);

View file

@ -4,9 +4,9 @@
#include <boost/blank.hpp>
#include "mstch/mstch.hpp"
#include "has_token.hpp"
namespace mstch {
namespace visitor {
class get_token: public boost::static_visitor<const mstch::node&> {
public:
@ -38,4 +38,3 @@ inline const mstch::node& get_token::operator()<std::shared_ptr<object>>(
}
}
}

View file

@ -6,7 +6,6 @@
#include "mstch/mstch.hpp"
namespace mstch {
namespace visitor {
class has_token: public boost::static_visitor<bool> {
public:
@ -17,7 +16,8 @@ class has_token: public boost::static_visitor<bool> {
inline bool operator()(const T& t) const {
return token == ".";
}
private:
private:
const std::string& token;
};
@ -34,4 +34,3 @@ inline bool has_token::operator()<std::shared_ptr<object>>(
}
}
}

View file

@ -6,7 +6,6 @@
#include "mstch/mstch.hpp"
namespace mstch {
namespace visitor {
class is_node_empty: public boost::static_visitor<bool> {
public:
@ -24,20 +23,20 @@ inline bool is_node_empty::operator()<boost::blank>(
}
template<>
inline bool is_node_empty::operator()<int>(const int& val) const {
return val == 0;
inline bool is_node_empty::operator()<int>(const int& value) const {
return value == 0;
}
template<>
inline bool is_node_empty::operator()<bool>(const bool& val) const {
return !val;
inline bool is_node_empty::operator()<bool>(const bool& value) const {
return !value;
}
template<>
inline bool is_node_empty::operator()<std::string>(
const std::string& val) const
const std::string& value) const
{
return val == "";
return value == "";
}
template<>
@ -46,4 +45,3 @@ inline bool is_node_empty::operator()<array>(const array& array) const {
}
}
}

View file

@ -7,7 +7,6 @@
#include "utils.hpp"
namespace mstch {
namespace visitor {
class render_node: public boost::static_visitor<std::string> {
public:
@ -28,21 +27,25 @@ class render_node: public boost::static_visitor<std::string> {
};
template<>
inline std::string render_node::operator()<int>(const int& val) const {
return std::to_string(val);
inline std::string render_node::operator()<int>(const int& value) const {
return std::to_string(value);
}
template<> inline
std::string render_node::operator()<bool>(const bool& val) const {
return val?"true":"false";
template<>
inline std::string render_node::operator()<bool>(const bool& value) const {
return value?"true":"false";
}
template<>
inline std::string render_node::operator()<lambda>(const lambda& value) const {
return (m_flag == flag::escape_html)?html_escape(value()):value();
}
template<>
inline std::string render_node::operator()<std::string>(
const std::string& val) const
const std::string& value) const
{
return (m_flag == flag::escape_html)?html_escape(val):val;
return (m_flag == flag::escape_html)?html_escape(value):value;
}
}
}

View file

@ -8,7 +8,6 @@
#include "utils.hpp"
namespace mstch {
namespace visitor {
class render_section: public boost::static_visitor<std::string> {
public:
@ -26,7 +25,7 @@ class render_section: public boost::static_visitor<std::string> {
return render_context::push(ctx, t).render(section);
}
private:
private:
render_context& ctx;
const template_type& section;
flag m_flag;
@ -34,13 +33,12 @@ private:
template<>
inline std::string render_section::operator()<lambda>(const lambda& fun) const {
return "";
/*std::string section_str;
std::string section_str;
for(auto& token: section)
section_str += token.raw();
return lam(section_str, [this](const std::string& str) {
return ctx.render(template_type{str});
});*/
return fun(section_str, [this](const std::string& str) {
return render_context::push(ctx).render(template_type{str});
});
}
template<>
@ -55,4 +53,3 @@ inline std::string render_section::operator()<array>(const array& array) const {
}
}
}

View file

@ -12,8 +12,8 @@ int main() {
std::string comment_tmp{
"<div class=\"comments\"><h3>{{header}}</h3><ul>"
"{{#comments}}<li class=\"comment\"><h5>{{name}}</h5>"
"<p>{{body}}</p></li>{{/comments}}</ul></div>"
};
"<p>{{body}}</p></li>{{/comments}}</ul></div>"};
auto comment_view = mstch::map{
{"header", std::string{"My Post Comments"}},
{"comments", mstch::array{
@ -21,9 +21,7 @@ int main() {
mstch::map{{"name", std::string{"Sam"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::map{{"name", std::string{"Heather"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::map{{"name", std::string{"Kathy"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::map{{"name", std::string{"George"}}, {"body", std::string{"Thanks for this post!"}}}
}}
};
mstch::map{{"name", std::string{"George"}}, {"body", std::string{"Thanks for this post!"}}}}}};
std::vector<unsigned long> times;
for (int j = 0; j < 10; j++) {

View file

@ -1,3 +1,3 @@
const auto bug_11_eating_whitespace_data = mstch::map{
{"tag", std::string{"yo"}}
};
};

View file

@ -1,12 +1,3 @@
class comments: public mstch::object {
public:
comments() {
register_methods(this, {{"title", &comments::title}});
}
mstch::node title() {
return std::string{"A Comedy of Errors"};
}
};
const mstch::node comments_data = std::make_shared<comments>();
const mstch::node comments_data = mstch::map{
{"title", mstch::lambda{[](){return std::string{"A Comedy of Errors"};}}}
};

View file

@ -45,7 +45,8 @@ public:
{
register_methods(this, {
{"header", &complex::header}, {"item", &complex::item},
{"list", &complex::list}, {"empty", &complex::empty}});
{"list", &complex::list}, {"empty", &complex::empty}
});
}
mstch::node header() {

View file

@ -1,18 +1,4 @@
class escaped: public mstch::object {
public:
escaped() {
register_methods(this, {
{"title", &escaped::title}, {"entities", &escaped::entities}
});
}
mstch::node title() {
return std::string{"Bear > Shark"};
};
mstch::node entities() {
return std::string{"&quot; \"'<>/"};
}
};
const mstch::node escaped_data = std::make_shared<escaped>();
const mstch::node escaped_data = mstch::map{
{"title", mstch::lambda{[](){ return std::string{"Bear > Shark"}; }}},
{"entities", mstch::lambda{[](){ return std::string{"&quot; \"'<>/"}; }}}
};

View file

@ -3,6 +3,6 @@ const auto falsy_array_data = mstch::map{
mstch::array{std::string{""}, std::string{"emptyString"}},
mstch::array{mstch::array{}, std::string{"emptyArray"}},
mstch::array{0, std::string{"zero"}},
mstch::array{mstch::node{}, std::string{"null"}}
}}
mstch::array{mstch::node{}, std::string{"null"}}}
}
};

View file

@ -0,0 +1,28 @@
class higher_order_sections: public mstch::object {
private:
std::string m_helper;
public:
higher_order_sections(): m_helper{"To tinker?"} {
register_methods(this, {
{"name", &higher_order_sections::name},
{"helper", &higher_order_sections::helper},
{"bolder", &higher_order_sections::bolder}
});
}
mstch::node name() {
return std::string{"Tater"};
}
mstch::node helper() {
return m_helper;
}
mstch::node bolder() {
return mstch::lambda{[this](const std::string& text, mstch::renderer render) {
return text + " => <b>" + render(text) + "</b> " + m_helper;
}};
}
};
const mstch::node higher_order_sections_data = std::make_shared<higher_order_sections>();

View file

@ -1,7 +0,0 @@
({
number: function(text, render) {
return function(text, render) {
return +render(text);
}
}
})

View file

@ -1 +0,0 @@
<p>{{#number}}0{{/number}}</p>

View file

@ -1 +0,0 @@
<p>0</p>

View file

@ -1,9 +0,0 @@
({
name: "Tater",
helper: "To tinker?",
bolder: function () {
return function (text, render) {
return text + ' => <b>' + render(text) + '</b> ' + this.helper;
}
}
})

View file

@ -1,21 +1,6 @@
class nested_higher_order_sections: public mstch::object {
public:
nested_higher_order_sections() {
register_methods(this, {
{"bold", &nested_higher_order_sections::bold},
{"person", &nested_higher_order_sections::person}
});
}
mstch::node bold() {
return mstch::lambda{[](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
}};
};
mstch::node person() {
return mstch::map{{"name", std::string{"Jonas"}}};
}
};
const mstch::node nested_higher_order_sections_data = std::make_shared<nested_higher_order_sections>();
const mstch::node nested_higher_order_sections_data = mstch::map{
{"bold", mstch::lambda{[](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
}}},
{"person", mstch::map{{"name", std::string{"Jonas"}}}}
};

View file

@ -1,14 +1,14 @@
const auto null_lookup_object_data = mstch::map{
{"name", std::string{"David"}},
{"twitter", std::string{"@dasilvacontin"}},
{"fobject", mstch::array{
{"name", std::string{"David"}},
{"twitter", std::string{"@dasilvacontin"}},
{"fobject", mstch::array{
mstch::map{
{"name", std::string{"Flor"}},
{"twitter", std::string{"@florrts"}}
},
mstch::map{
{"name", std::string{"Miquel"}},
{"twitter", mstch::node{}}
{"name", std::string{"Flor"}},
{"twitter", std::string{"@florrts"}}
},
mstch::map{
{"name", std::string{"Miquel"}},
{"twitter", mstch::node{}}
}
}}
}}
};

View file

@ -1,18 +1,4 @@
class partial_template: public mstch::object {
public:
partial_template() {
register_methods(this, {
{"title", &partial_template::title},
{"again", &partial_template::again}});
}
mstch::node title() {
return std::string{"Welcome"};
}
mstch::node again() {
return std::string{"Goodbye"};
}
};
const auto partial_template_data = std::make_shared<partial_template>();
const mstch::node partial_template_data = mstch::map{
{"title", mstch::lambda{[](){ return std::string{"Welcome"}; }}},
{"again", mstch::lambda{[](){ return std::string{"Goodbye"}; }}},
};

View file

@ -9,7 +9,8 @@ public:
{"name", &partial_view::name},
{"value", &partial_view::value},
{"taxed_value", &partial_view::taxed_value},
{"in_ca", &partial_view::in_ca},});
{"in_ca", &partial_view::in_ca}
});
}
mstch::node greeting() {

View file

@ -9,7 +9,8 @@ public:
{"name", &partial_whitespace::name},
{"value", &partial_whitespace::value},
{"taxed_value", &partial_whitespace::taxed_value},
{"in_ca", &partial_whitespace::in_ca},});
{"in_ca", &partial_whitespace::in_ca}
});
}
mstch::node greeting() {

View file

@ -1,15 +1,5 @@
class section_functions_in_partials: public mstch::object {
public:
section_functions_in_partials() {
register_methods(this, {{"bold", &section_functions_in_partials::bold}});
}
mstch::node bold() {
return std::string{""};
/*return [](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
};*/
}
};
const auto section_functions_in_partials_data = std::make_shared<section_functions_in_partials>();
const mstch::node section_functions_in_partials_data = mstch::map{
{"bold", mstch::lambda{[](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
}}}
};

View file

@ -1,21 +1,19 @@
class simple: public mstch::object {
private:
std::string m_name;
int m_value;
bool m_in_ca;
public:
simple():
m_name{"Chris"},
m_value{10000},
m_in_ca{true}
m_value{10000}
{
register_methods(this, {
{"name", &simple::name}, {"value", &simple::value},
{"taxed_value", &simple::taxed_value}, {"in_ca", &simple::in_ca}});
{"name", &simple::name},
{"value", &simple::value},
{"taxed_value", &simple::taxed_value},
{"in_ca", &simple::in_ca}});
}
mstch::node name() {
return m_name;
return std::string{"Chris"};
}
mstch::node value() {
@ -27,8 +25,8 @@ public:
}
mstch::node in_ca() {
return m_in_ca;
return true;
}
};
const auto simple_data = std::make_shared<simple>();
const auto simple_data = std::make_shared<simple>();

View file

@ -1,12 +1,3 @@
class unescaped: public mstch::object {
public:
unescaped() {
register_methods(this, {{"title", &unescaped::title}});
}
mstch::node title() {
return std::string{"Bear > Shark"};
}
};
const auto unescaped_data = std::make_shared<unescaped>();
const mstch::node unescaped_data = mstch::map{
{"title", mstch::lambda{[](){ return std::string{"Bear > Shark"}; }}}
};

View file

@ -35,13 +35,14 @@ MSTCH_TEST(escaped)
MSTCH_TEST(falsy)
MSTCH_TEST(falsy_array)
MSTCH_TEST(grandparent_context)
MSTCH_TEST(higher_order_sections)
MSTCH_TEST(implicit_iterator)
MSTCH_TEST(included_tag)
MSTCH_TEST(inverted_section)
MSTCH_TEST(keys_with_questionmarks)
MSTCH_TEST(multiline_comment)
MSTCH_TEST(nested_dot)
//MSTCH_TEST(nested_higher_order_sections)
MSTCH_TEST(nested_higher_order_sections)
MSTCH_TEST(nested_iterating)
MSTCH_TEST(nesting)
MSTCH_TEST(nesting_same_name)
@ -59,7 +60,7 @@ MSTCH_PARTIAL_TEST(partial_whitespace)
MSTCH_TEST(recursion_with_same_names)
MSTCH_TEST(reuse_of_enumerables)
MSTCH_TEST(section_as_context)
//MSTCH_PARTIAL_TEST(section_functions_in_partials)
MSTCH_PARTIAL_TEST(section_functions_in_partials)
MSTCH_TEST(simple)
MSTCH_TEST(string_as_context)
MSTCH_TEST(two_in_a_row)