half-complete refactor

This commit is contained in:
Daniel Sipka 2015-04-16 21:05:59 +02:00
parent 25bbbfdbcc
commit 8fbcd12284
100 changed files with 483 additions and 327 deletions

View File

@ -3,36 +3,45 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <string> #include <string>
#include <functional> #include <memory>
#include <boost/variant.hpp> #include <boost/variant.hpp>
namespace mstch { namespace mstch {
// booleans must be wrapped, because std::function is implicitly convertible namespace internal {
// to a bool. template<class N>
class boolean { class object_t {
private:
const bool state;
public: public:
boolean(bool b): state(b) {} N at(const std::string &name) const {
operator bool() const { return state; } return (methods.at(name))();
}; }
bool has(const std::string name) const {
return methods.count(name);
}
protected:
template<class S>
void register_methods(S* sub, std::map<std::string,N(S::*)()> methods) {
for(auto& m: methods)
this->methods.insert(m.first, std::bind(m.second, sub));
}
private:
const std::map<std::string, std::function<N()>> methods;
};
}
using renderer = std::function<std::string(const std::string&)>;
using string_lambda = std::function<std::string()>;
using renderer_lambda = std::function<
std::function<std::string(const std::string&,renderer)>()>;
using node = boost::make_recursive_variant< using node = boost::make_recursive_variant<
boost::blank, std::string, int, boolean, boost::blank, std::string, int, bool,
string_lambda, renderer_lambda, std::shared_ptr<internal::object_t<boost::recursive_variant_>>,
std::map<const std::string,boost::recursive_variant_>, std::map<const std::string,boost::recursive_variant_>,
std::vector<boost::recursive_variant_>>::type; std::vector<boost::recursive_variant_>>::type;
using object = std::map<const std::string,node>; using object = internal::object_t<node>;
using map = std::map<const std::string,node>;
using array = std::vector<node>; using array = std::vector<node>;
std::string render( std::string render(
const std::string& tmplt, const std::string& tmplt,
const object& root, const node& root,
const std::map<std::string,std::string>& partials = const std::map<std::string,std::string>& partials =
std::map<std::string,std::string>()); std::map<std::string,std::string>());
} }

View File

@ -9,6 +9,8 @@ set(SRC
state/in_inverted_section.cpp state/in_inverted_section.cpp
state/in_section.cpp state/in_section.cpp
state/outside_section.cpp state/outside_section.cpp
visitor/get_token.cpp
visitor/has_token.cpp
visitor/is_node_empty.cpp visitor/is_node_empty.cpp
visitor/render_node.cpp visitor/render_node.cpp
visitor/render_section.cpp visitor/render_section.cpp

View File

@ -8,7 +8,7 @@ using namespace mstch;
std::string mstch::render( std::string mstch::render(
const std::string& tmplt, const std::string& tmplt,
const object& root, const node& root,
const std::map<std::string,std::string>& partials) const std::map<std::string,std::string>& partials)
{ {
std::map<std::string,template_type> partial_templts; std::map<std::string,template_type> partial_templts;

View File

@ -1,21 +1,23 @@
#include "render_context.hpp" #include "render_context.hpp"
#include "utils.hpp" #include "utils.hpp"
#include "state/outside_section.hpp" #include "state/outside_section.hpp"
#include "visitor/has_token.hpp"
#include "visitor/get_token.hpp"
using namespace mstch; using namespace mstch;
const mstch::node render_context::null_node; const mstch::node render_context::null_node;
render_context::push::push(render_context& context, const mstch::object& obj): render_context::push::push(render_context& context, const mstch::node& node):
context(context) context(context)
{ {
context.objects.emplace_front(obj); context.nodes.emplace_front(node);
context.state.push(std::unique_ptr<state::render_state>( context.state.push(std::unique_ptr<state::render_state>(
new state::outside_section)); new state::outside_section));
} }
render_context::push::~push() { render_context::push::~push() {
context.objects.pop_front(); context.nodes.pop_front();
context.state.pop(); context.state.pop();
} }
@ -24,34 +26,32 @@ std::string render_context::push::render(const template_type& templt) {
} }
render_context::render_context( render_context::render_context(
const mstch::object& object, const mstch::node& node,
const std::map<std::string,template_type>& partials): const std::map<std::string,template_type>& partials):
partials{partials}, partials{partials},
objects{object} nodes{node}
{ {
state.push(std::unique_ptr<state::render_state>( state.push(std::unique_ptr<state::render_state>(
new state::outside_section)); new state::outside_section));
} }
const mstch::node& render_context::find_node( mstch::node render_context::find_node(
const std::string& token, const std::string& token,
const std::deque<object>& current_objects) const std::deque<node>& current_nodes)
{ {
if (token != "." && token.find('.') != std::string::npos) if (token != "." && token.find('.') != std::string::npos)
return find_node( return find_node(
token.substr(token.rfind('.') + 1), token.substr(token.rfind('.') + 1),
{boost::get<object>(find_node( {find_node(token.substr(0, token.rfind('.')), current_nodes)});
token.substr(0, token.rfind('.')),
current_objects))});
else else
for (auto& object: current_objects) for (auto& node: current_nodes)
if (object.count(token)) if (boost::apply_visitor(visitor::has_token(token), node))
return object.at(token); return boost::apply_visitor(visitor::get_token(token, node), node);
return null_node; return null_node;
} }
const mstch::node& render_context::get_node(const std::string& token) { mstch::node render_context::get_node(const std::string& token) {
return find_node(token, objects); return find_node(token, nodes);
} }
std::string render_context::render(const template_type& templt) { std::string render_context::render(const template_type& templt) {

View File

@ -14,7 +14,7 @@ namespace mstch {
public: public:
class push { class push {
public: public:
push(render_context& context, const mstch::object& obj = {}); push(render_context& context, const mstch::node& node = {});
~push(); ~push();
std::string render(const template_type& templt); std::string render(const template_type& templt);
private: private:
@ -22,9 +22,9 @@ namespace mstch {
}; };
render_context( render_context(
const mstch::object& object, const mstch::node& node,
const std::map<std::string,template_type>& partials); const std::map<std::string,template_type>& partials);
const mstch::node& get_node(const std::string& token); mstch::node get_node(const std::string& token);
std::string render(const template_type& templt); std::string render(const template_type& templt);
std::string render_partial(const std::string& partial_name); std::string render_partial(const std::string& partial_name);
template<class T, class... Args> template<class T, class... Args>
@ -34,11 +34,11 @@ namespace mstch {
} }
private: private:
static const mstch::node null_node; static const mstch::node null_node;
const mstch::node& find_node( mstch::node find_node(
const std::string& token, const std::string& token,
const std::deque<object>& current_objects); const std::deque<node>& current_nodes);
const std::map<std::string,template_type>& partials; const std::map<std::string,template_type>& partials;
std::deque<mstch::object> objects; std::deque<mstch::node> nodes;
std::stack<std::unique_ptr<state::render_state>> state; std::stack<std::unique_ptr<state::render_state>> state;
}; };
} }

View File

@ -18,7 +18,7 @@ std::string state::in_inverted_section::render(
case token::type::section_close: case token::type::section_close:
if(token.content() == section_name && skipped_openings == 0) { if(token.content() == section_name && skipped_openings == 0) {
std::string out; std::string out;
auto& section_node = ctx.get_node(section_name); auto section_node = ctx.get_node(section_name);
if(boost::apply_visitor(visitor::is_node_empty(), section_node)) if(boost::apply_visitor(visitor::is_node_empty(), section_node))
out = render_context::push(ctx).render(section); out = render_context::push(ctx).render(section);
ctx.set_state<outside_section>(); ctx.set_state<outside_section>();

View File

@ -14,7 +14,7 @@ std::string state::in_section::render(render_context& ctx, const token& token) {
switch(token.token_type()) { switch(token.token_type()) {
case token::type::section_close: case token::type::section_close:
if(token.content() == section_name && skipped_openings == 0) { if(token.content() == section_name && skipped_openings == 0) {
auto& section_node = ctx.get_node(section_name); auto section_node = ctx.get_node(section_name);
std::string out; std::string out;
if (!boost::apply_visitor(visitor::is_node_empty(), section_node)) if (!boost::apply_visitor(visitor::is_node_empty(), section_node))
out = boost::apply_visitor( out = boost::apply_visitor(

View File

@ -18,10 +18,11 @@ std::string state::outside_section::render(
ctx.set_state<in_inverted_section>(token.content()); ctx.set_state<in_inverted_section>(token.content());
break; break;
case token::type::variable: case token::type::variable:
case token::type::unescaped_variable: case token::type::unescaped_variable: {
return boost::apply_visitor(visitor::render_node((token.token_type() == return boost::apply_visitor(visitor::render_node((token.token_type() ==
token::type::variable)?flag::escape_html:flag::none), token::type::variable)?flag::escape_html:flag::none),
ctx.get_node(token.content())); ctx.get_node(token.content()));
}
case token::type::comment: break; case token::type::comment: break;
case token::type::text: case token::type::text:
return token.content(); return token.content();

37
src/visitor/get_token.cpp Normal file
View File

@ -0,0 +1,37 @@
#include "get_token.hpp"
using namespace mstch;
using namespace mstch::visitor;
get_token::get_token(const std::string& token, const mstch::node& node):
token(token), node(node)
{
}
mstch::node get_token::operator()(const boost::blank& blank) const {
return node;
}
mstch::node get_token::operator()(const int& i) const {
return node;
}
mstch::node get_token::operator()(const bool& b) const {
return node;
}
mstch::node get_token::operator()(const std::string& str) const {
return node;
}
mstch::node get_token::operator()(const array& arr) const {
return node;
}
mstch::node get_token::operator()(const map& map) const {
return map.at(token);
}
mstch::node get_token::operator()(const std::shared_ptr<object>& obj) const {
return obj->at(token);
}

24
src/visitor/get_token.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <boost/variant/static_visitor.hpp>
#include <boost/blank.hpp>
#include "mstch/mstch.hpp"
namespace mstch {
namespace visitor {
class get_token: public boost::static_visitor<node> {
public:
get_token(const std::string& token, const mstch::node& node);
mstch::node operator()(const boost::blank& blank) const;
mstch::node operator()(const int& i) const;
mstch::node operator()(const bool& b) const;
mstch::node operator()(const std::string& str) const;
mstch::node operator()(const array& arr) const;
mstch::node operator()(const map& map) const;
mstch::node operator()(const std::shared_ptr<object>& obj) const;
private:
const std::string& token;
mstch::node node;
};
}
}

35
src/visitor/has_token.cpp Normal file
View File

@ -0,0 +1,35 @@
#include "has_token.hpp"
using namespace mstch;
using namespace mstch::visitor;
has_token::has_token(const std::string& token): token(token) {
}
bool has_token::operator()(const boost::blank& blank) const {
return false;
}
bool has_token::operator()(const int& i) const {
return token == ".";
}
bool has_token::operator()(const bool& b) const {
return token == ".";
}
bool has_token::operator()(const std::string& str) const {
return token == ".";
}
bool has_token::operator()(const array& arr) const {
return token == ".";
}
bool has_token::operator()(const map& map) const {
return map.count(token) == 1;
}
bool has_token::operator()(const std::shared_ptr<object>& obj) const {
return obj->has(token);
}

23
src/visitor/has_token.hpp Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include <boost/variant/static_visitor.hpp>
#include <boost/blank.hpp>
#include "mstch/mstch.hpp"
namespace mstch {
namespace visitor {
class has_token: public boost::static_visitor<bool> {
public:
has_token(const std::string& token);
bool operator()(const boost::blank& blank) const;
bool operator()(const int& i) const;
bool operator()(const bool& b) const;
bool operator()(const std::string& str) const;
bool operator()(const array& arr) const;
bool operator()(const map& map) const;
bool operator()(const std::shared_ptr<object>& obj) const;
private:
const std::string& token;
};
}
}

View File

@ -1,35 +1,32 @@
#include "is_node_empty.hpp" #include "is_node_empty.hpp"
using namespace mstch; using namespace mstch;
using namespace mstch::visitor;
bool visitor::is_node_empty::operator()(const boost::blank& blank) const { bool is_node_empty::operator()(const boost::blank& blank) const {
return true; return true;
} }
bool visitor::is_node_empty::operator()(const int& i) const { bool is_node_empty::operator()(const int& i) const {
return i == 0; return i == 0;
} }
bool visitor::is_node_empty::operator()(const bool& b) const { bool is_node_empty::operator()(const bool& b) const {
return !b; return !b;
} }
bool visitor::is_node_empty::operator()(const std::string& str) const { bool is_node_empty::operator()(const std::string& str) const {
return str == ""; return str == "";
} }
bool visitor::is_node_empty::operator()(const array& arr) const { bool is_node_empty::operator()(const array& arr) const {
return arr.size() == 0; return arr.size() == 0;
} }
bool visitor::is_node_empty::operator()(const object& obj) const { bool is_node_empty::operator()(const map& map) const {
return false; return false;
} }
bool visitor::is_node_empty::operator()(const string_lambda& lambda) const { bool is_node_empty::operator()(const std::shared_ptr<object>& obj) const {
return false;
}
bool visitor::is_node_empty::operator()(const renderer_lambda& lambda) const {
return false; return false;
} }

View File

@ -2,7 +2,6 @@
#include <boost/variant/static_visitor.hpp> #include <boost/variant/static_visitor.hpp>
#include <boost/blank.hpp> #include <boost/blank.hpp>
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
namespace mstch { namespace mstch {
@ -14,9 +13,8 @@ namespace mstch {
bool operator()(const bool& b) const; bool operator()(const bool& b) const;
bool operator()(const std::string& str) const; bool operator()(const std::string& str) const;
bool operator()(const array& arr) const; bool operator()(const array& arr) const;
bool operator()(const object& obj) const; bool operator()(const map& map) const;
bool operator()(const string_lambda& lambda) const; bool operator()(const std::shared_ptr<object>& obj) const;
bool operator()(const renderer_lambda& lambda) const;
}; };
} }
} }

View File

@ -2,44 +2,35 @@
#include "render_node.hpp" #include "render_node.hpp"
using namespace mstch; using namespace mstch;
using namespace mstch::visitor;
visitor::render_node::render_node(flag p_flag): m_flag(p_flag) { render_node::render_node(flag p_flag): m_flag(p_flag) {
} }
std::string visitor::render_node::operator()(const boost::blank& blank) const { std::string render_node::operator()(const boost::blank& blank) const {
return ""; return "";
} }
std::string visitor::render_node::operator()(const int& i) const { std::string render_node::operator()(const int& i) const {
return std::to_string(i); return std::to_string(i);
} }
std::string visitor::render_node::operator()(const bool& b) const { std::string render_node::operator()(const bool& b) const {
return b?"true":"false"; return b?"true":"false";
} }
std::string visitor::render_node::operator()(const std::string& str) const { std::string render_node::operator()(const std::string& str) const {
return (m_flag == flag::escape_html)?html_escape(str):str; return (m_flag == flag::escape_html)?html_escape(str):str;
} }
std::string visitor::render_node::operator()(const array& arr) const { std::string render_node::operator()(const array& arr) const {
return ""; return "";
} }
std::string visitor::render_node::operator()(const object& obj) const { std::string render_node::operator()(const map& map) const {
return ""; return "";
} }
std::string visitor::render_node::operator()( std::string render_node::operator()(const std::shared_ptr<object>& obj) const {
const string_lambda& lambda) const return "";
{
return this->operator()(lambda());
}
std::string visitor::render_node::operator()(
const renderer_lambda& lambda) const
{
return this->operator()((lambda())("", [](const std::string& text) {
return std::string{""};
}));
} }

View File

@ -2,9 +2,7 @@
#include <boost/variant/static_visitor.hpp> #include <boost/variant/static_visitor.hpp>
#include <boost/blank.hpp> #include <boost/blank.hpp>
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
#include <set>
namespace mstch { namespace mstch {
namespace visitor { namespace visitor {
@ -17,9 +15,8 @@ namespace mstch {
std::string operator()(const bool& b) const; std::string operator()(const bool& b) const;
std::string operator()(const std::string& str) const; std::string operator()(const std::string& str) const;
std::string operator()(const array& arr) const; std::string operator()(const array& arr) const;
std::string operator()(const object& obj) const; std::string operator()(const map& map) const;
std::string operator()(const string_lambda& lambda) const; std::string operator()(const std::shared_ptr<object>& obj) const;
std::string operator()(const renderer_lambda& lambda) const;
private: private:
flag m_flag; flag m_flag;
}; };

View File

@ -1,39 +1,40 @@
#include "render_section.hpp" #include "render_section.hpp"
using namespace mstch; using namespace mstch;
using namespace mstch::visitor;
visitor::render_section::render_section( render_section::render_section(
render_context& ctx, const template_type& section, flag p_flag): render_context& ctx, const template_type& section, flag p_flag):
ctx(ctx), section(section), m_flag(p_flag) ctx(ctx), section(section), m_flag(p_flag)
{ {
} }
std::string visitor::render_section::operator()( std::string render_section::operator()(
const boost::blank& blank) const const boost::blank& blank) const
{ {
return render_context::push(ctx, {{".", {}}}).render(section); return render_context::push(ctx, mstch::node{}).render(section);
} }
std::string visitor::render_section::operator()(const int& i) const { std::string render_section::operator()(const int& i) const {
return render_context::push(ctx, {{".", i}}).render(section); return render_context::push(ctx, i).render(section);
} }
std::string visitor::render_section::operator()(const bool& b) const { std::string render_section::operator()(const bool& b) const {
return render_context::push(ctx, {{".", b}}).render(section); return render_context::push(ctx, b).render(section);
} }
std::string visitor::render_section::operator()(const std::string& str) const { std::string render_section::operator()(const std::string& str) const {
return render_context::push(ctx, {{".", str}}).render(section); return render_context::push(ctx, str).render(section);
} }
std::string visitor::render_section::operator()(const object& obj) const { std::string render_section::operator()(const map& map) const {
return render_context::push(ctx, obj).render(section); return render_context::push(ctx, map).render(section);
} }
std::string visitor::render_section::operator()(const array& a) const { std::string render_section::operator()(const array& a) const {
std::string out; std::string out;
if(m_flag == flag::keep_array) if(m_flag == flag::keep_array)
out += render_context::push(ctx, {{".", a}}).render(section); out += render_context::push(ctx, a).render(section);
else else
for (auto& item: a) for (auto& item: a)
out += boost::apply_visitor( out += boost::apply_visitor(
@ -41,17 +42,6 @@ std::string visitor::render_section::operator()(const array& a) const {
return out; return out;
} }
std::string visitor::render_section::operator()( std::string render_section::operator()(const std::shared_ptr<object>& obj) const {
const string_lambda& lambda) const return render_context::push(ctx, obj).render(section);
{
return lambda();
}
std::string visitor::render_section::operator()(
const renderer_lambda& lambda) const
{
return "";
/*return (lambda())(section, [&](const std::string& text) {
return render_context::push(ctx).render(text);
}); TODO ! */
} }

View File

@ -3,8 +3,6 @@
#include <boost/variant/static_visitor.hpp> #include <boost/variant/static_visitor.hpp>
#include <boost/blank.hpp> #include <boost/blank.hpp>
#include "render_context.hpp" #include "render_context.hpp"
#include <set>
#include "mstch/mstch.hpp" #include "mstch/mstch.hpp"
namespace mstch { namespace mstch {
@ -21,9 +19,8 @@ namespace mstch {
std::string operator()(const bool& b) const; std::string operator()(const bool& b) const;
std::string operator()(const std::string& str) const; std::string operator()(const std::string& str) const;
std::string operator()(const array& arr) const; std::string operator()(const array& arr) const;
std::string operator()(const object& obj) const; std::string operator()(const map& map) const;
std::string operator()(const string_lambda& lambda) const; std::string operator()(const std::shared_ptr<object>& obj) const;
std::string operator()(const renderer_lambda& lambda) const;
private: private:
render_context& ctx; render_context& ctx;
const template_type& section; const template_type& section;

View File

@ -15,11 +15,11 @@ set(filetoheader_exe ${CMAKE_CURRENT_BINARY_DIR}/filetoheader${CMAKE_EXECUTABLE_
file(GLOB data_files RELATIVE file(GLOB data_files RELATIVE
"${CMAKE_SOURCE_DIR}/test/data" "${CMAKE_SOURCE_DIR}/test/data"
"${CMAKE_SOURCE_DIR}/test/data/*.data") "${CMAKE_SOURCE_DIR}/test/data/*.hpp")
foreach(data_file ${data_files}) foreach(data_file ${data_files})
list(APPEND genargs "-D${data_file}") list(APPEND genargs "-C${data_file}")
string(REGEX REPLACE "\\.data" "" test_name "${data_file}") string(REGEX REPLACE "\\.hpp" "" test_name "${data_file}")
list(APPEND tests "${test_name}") list(APPEND tests "${test_name}")
endforeach(data_file) endforeach(data_file)

View File

@ -9,14 +9,14 @@ int main() {
"{{#comments}}<li class=\"comment\"><h5>{{name}}</h5>" "{{#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::object{ auto comment_view = mstch::map{
{"header", std::string{"My Post Comments"}}, {"header", std::string{"My Post Comments"}},
{"comments", mstch::array{ {"comments", mstch::array{
mstch::object{{"name", std::string{"Joe"}}, {"body", std::string{"Thanks for this post!"}}}, mstch::map{{"name", std::string{"Joe"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::object{{"name", std::string{"Sam"}}, {"body", std::string{"Thanks for this post!"}}}, mstch::map{{"name", std::string{"Sam"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::object{{"name", std::string{"Heather"}}, {"body", std::string{"Thanks for this post!"}}}, mstch::map{{"name", std::string{"Heather"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::object{{"name", std::string{"Kathy"}}, {"body", std::string{"Thanks for this post!"}}}, mstch::map{{"name", std::string{"Kathy"}}, {"body", std::string{"Thanks for this post!"}}},
mstch::object{{"name", std::string{"George"}}, {"body", std::string{"Thanks for this post!"}}} mstch::map{{"name", std::string{"George"}}, {"body", std::string{"Thanks for this post!"}}}
}} }}
}; };

View File

@ -1,3 +0,0 @@
mstch::object{
{"message", std::string{"Some <code>"}}
}

View File

@ -0,0 +1,3 @@
const auto ampersand_escape_data = mstch::map{
{"message", std::string{"Some <code>"}}
};

View File

@ -1,4 +1,4 @@
mstch::object{ const auto apostrophe_data = mstch::map{
{"apos", std::string{"'"}}, {"apos", std::string{"'"}},
{"control", std::string{"X"}} {"control", std::string{"X"}}
} };

View File

@ -1,3 +1,3 @@
mstch::object{ const auto array_of_strings_data = mstch::map{
{"array_of_strings", mstch::array{std::string{"hello"}, std::string{"world"}}} {"array_of_strings", mstch::array{std::string{"hello"}, std::string{"world"}}}
} };

View File

@ -1,3 +0,0 @@
mstch::object{
{"value", std::string{"\\abc"}}
}

View File

@ -0,0 +1,3 @@
const auto backslashes_data = mstch::map{
{"value", std::string{"\\abc"}}
};

View File

@ -1,3 +0,0 @@
mstch::object{
{"tag", std::string{"yo"}}
}

View File

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

View File

@ -1,3 +0,0 @@
mstch::object{
{"length", std::string{"hello"}}
}

View File

@ -0,0 +1,3 @@
const auto bug_length_property_data = mstch::map{
{"length", std::string{"hello"}}
};

View File

@ -1,5 +0,0 @@
mstch::object{
{"title", []() {
return std::string{"A Comedy of Errors"};
}}
};

12
test/data/comments.hpp Normal file
View File

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

View File

@ -1,8 +0,0 @@
mstch::object{
{"outer", mstch::object{
{"id", 1},
{"second", mstch::object{
{"nothing", 2}
}}
}}
}

View File

@ -0,0 +1,8 @@
const auto context_lookup_data = mstch::map{
{"outer", mstch::map{
{"id", 1},
{"second", mstch::map{
{"nothing", 2}
}}
}}
};

View File

@ -1,4 +0,0 @@
mstch::object{
{"bedrooms", true},
{"total", 1}
}

View File

@ -0,0 +1,4 @@
const auto disappearing_whitespace_data = mstch::map{
{"bedrooms", true},
{"total", 1}
};

View File

@ -1,5 +1,5 @@
mstch::object{ const auto double_render_data = mstch::map{
{"foo", true}, {"foo", true},
{"bar", std::string{"{{win}}"}}, {"bar", std::string{"{{win}}"}},
{"win", std::string{"FAIL"}} {"win", std::string{"FAIL"}}
} };

View File

@ -1,3 +0,0 @@
mstch::object{
{"jobs", mstch::array{}}
}

3
test/data/empty_list.hpp Normal file
View File

@ -0,0 +1,3 @@
const auto empty_list_data = mstch::map{
{"jobs", mstch::array{}}
};

View File

@ -1 +0,0 @@
mstch::object{}

View File

@ -0,0 +1 @@
const auto empty_sections_data = mstch::map{};

View File

@ -1,6 +1,6 @@
mstch::object{ const auto empty_sections_data = mstch::map{
{"description", std::string{"That is all!"}}, {"description", std::string{"That is all!"}},
{"child", mstch::object{ {"child", mstch::map{
{"description", std::string{""}} {"description", std::string{""}}
}} }}
} };

View File

@ -1 +0,0 @@
mstch::object{}

View File

@ -0,0 +1 @@
const auto empty_sections_data = mstch::map{};

View File

@ -1,3 +0,0 @@
mstch::object{
{"bar", 2}
}

View File

@ -0,0 +1,3 @@
const auto empty_sections_data = mstch::map{
{"bar", 2}
};

View File

@ -1,6 +0,0 @@
mstch::object{
{"title", []() {
return "Bear > Shark";
}},
{"entities", std::string{"&quot; \"'<>/"}}
}

16
test/data/escaped.hpp Normal file
View File

@ -0,0 +1,16 @@
class escaped: public mstch::object {
public:
escaped() {
register_methods(this, {{"title", &title}, {"entities", &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>();

View File

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

View File

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

View File

@ -1,19 +0,0 @@
mstch::object{
{"grand_parent_id", std::string{"grand_parent1"}},
{"parent_contexts", mstch::array{
mstch::object{
{"parent_id", std::string{"parent1"}},
{"child_contexts", mstch::array{
mstch::object{{"child_id", std::string{"parent1-child1"}}},
mstch::object{{"child_id", std::string{"parent1-child2"}}}
}}
},
mstch::object{
{"parent_id", std::string{"parent2"}},
{"child_contexts", mstch::array{
mstch::object{{"child_id", std::string{"parent2-child1"}}},
mstch::object{{"child_id", std::string{"parent2-child2"}}}
}}
}
}}
}

View File

@ -0,0 +1,19 @@
const auto grandparent_context_data = mstch::map{
{"grand_parent_id", std::string{"grand_parent1"}},
{"parent_contexts", mstch::array{
mstch::map{
{"parent_id", std::string{"parent1"}},
{"child_contexts", mstch::array{
mstch::map{{"child_id", std::string{"parent1-child1"}}},
mstch::map{{"child_id", std::string{"parent1-child2"}}}
}}
},
mstch::map{
{"parent_id", std::string{"parent2"}},
{"child_contexts", mstch::array{
mstch::map{{"child_id", std::string{"parent2-child1"}}},
mstch::map{{"child_id", std::string{"parent2-child2"}}}
}}
}
}}
};

View File

@ -1,8 +0,0 @@
mstch::object{
{"data", mstch::object{
{"author", mstch::object{
{"twitter_id", 819606},
{"name", std::string{"janl"}}
}}
}}
}

View File

@ -0,0 +1,8 @@
const auto implicit_iterator_data = mstch::map{
{"data", mstch::map{
{"author", mstch::map{
{"twitter_id", 819606},
{"name", std::string{"janl"}}
}}
}}
};

View File

@ -1,3 +1,3 @@
mstch::object{ const auto inlcuded_tag_data = mstch::map{
{"html", std::string{"I like {{mustache}}"}} {"html", std::string{"I like {{mustache}}"}}
} };

View File

@ -1,3 +0,0 @@
mstch::object{
{"repos", mstch::array{}}
}

View File

@ -0,0 +1,3 @@
const auto inverted_section_data = mstch::map{
{"repos", mstch::array{}}
};

View File

@ -1,5 +0,0 @@
mstch::object{
{"person?", mstch::object{
{"name", std::string{"Jon"}}
}}
}

View File

@ -0,0 +1,5 @@
const auto keys_with_questionmarks_data = mstch::map{
{"person?", mstch::map{
{"name", std::string{"Jon"}}
}}
};

View File

@ -1 +0,0 @@
mstch::object{}

View File

@ -0,0 +1 @@
const auto multiline_comment_data = mstch::map{};

View File

@ -1 +0,0 @@
mstch::object{{"name", std::string{"Bruno"}}}

1
test/data/nested_dot.hpp Normal file
View File

@ -0,0 +1 @@
const auto nested_dot_data = mstch::map{{"name", std::string{"Bruno"}}};

View File

@ -1,8 +0,0 @@
mstch::object{
{"bold", []() {
return [](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
};
}},
{"person", mstch::object{{"name", std::string{"Jonas"}}}}
}

View File

@ -0,0 +1,21 @@
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 std::string{""};
/*return [](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>();

View File

@ -1,8 +0,0 @@
mstch::object{
{"inner", mstch::array{mstch::object{
{"foo", std::string{"foo"}},
{"inner", mstch::array{mstch::object{
{"bar", std::string{"bar"}}
}}}
}}}
}

View File

@ -0,0 +1,8 @@
const auto nested_iterating_data = mstch::map{
{"inner", mstch::array{mstch::map{
{"foo", std::string{"foo"}},
{"inner", mstch::array{mstch::map{
{"bar", std::string{"bar"}}
}}}
}}}
};

View File

@ -1,7 +0,0 @@
mstch::object{
{"foo", mstch::array{
mstch::object{{"a", mstch::object{{"b", 1}}}},
mstch::object{{"a", mstch::object{{"b", 2}}}},
mstch::object{{"a", mstch::object{{"b", 3}}}}
}}
}

7
test/data/nesting.hpp Normal file
View File

@ -0,0 +1,7 @@
const auto nesting_data = mstch::map{
{"foo", mstch::array{
mstch::map{{"a", mstch::map{{"b", 1}}}},
mstch::map{{"a", mstch::map{{"b", 2}}}},
mstch::map{{"a", mstch::map{{"b", 3}}}}
}}
};

View File

@ -1,8 +1,8 @@
mstch::object{ const auto nesting_same_name_data = mstch::map{
{"items", mstch::array{ {"items", mstch::array{
mstch::object{ mstch::map{
{"name", std::string{"name"}}, {"name", std::string{"name"}},
{"items", mstch::array{1, 2, 3, 4}} {"items", mstch::array{1, 2, 3, 4}}
} }
}} }}
} };

View File

@ -1,8 +1,8 @@
mstch::object{ const auto null_lookup_array_data = mstch::map{
{"name", std::string{"David"}}, {"name", std::string{"David"}},
{"twitter", std::string{"@dasilvacontin"}}, {"twitter", std::string{"@dasilvacontin"}},
{"farray", mstch::array{ {"farray", mstch::array{
mstch::array{std::string{"Flor"}, std::string{"@florrts"}}, mstch::array{std::string{"Flor"}, std::string{"@florrts"}},
mstch::array{std::string{"Miquel"}, mstch::node{}}, mstch::array{std::string{"Miquel"}, mstch::node{}},
}} }}
} };

View File

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

View File

@ -1,4 +1,4 @@
mstch::object{ const auto null_view_data = mstch::map{
{"name", std::string{"Joe"}}, {"name", std::string{"Joe"}},
{"friends", mstch::node{}} {"friends", mstch::node{}}
} };

View File

@ -1,3 +1,3 @@
mstch::object{ const auto partial_array_data = mstch::map{
{"array", mstch::array{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}} {"array", mstch::array{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}}
} };

View File

@ -1,8 +0,0 @@
mstch::object{
{"numbers", mstch::array{
mstch::object{{"i", std::string{"1"}}},
mstch::object{{"i", std::string{"2"}}},
mstch::object{{"i", std::string{"3"}}},
mstch::object{{"i", std::string{"4"}}}
}}
}

View File

@ -0,0 +1,8 @@
const auto partial_array_of_partials_data = mstch::map{
{"numbers", mstch::array{
mstch::map{{"i", std::string{"1"}}},
mstch::map{{"i", std::string{"2"}}},
mstch::map{{"i", std::string{"3"}}},
mstch::map{{"i", std::string{"4"}}}
}}
};

View File

@ -1,3 +1,3 @@
mstch::object{ const auto partial_array_of_partials_implicit_data = mstch::map{
{"numbers", mstch::array{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}} {"numbers", mstch::array{std::string{"1"}, std::string{"2"}, std::string{"3"}, std::string{"4"}}}
} };

View File

@ -1,3 +0,0 @@
mstch::object{
{"foo", 1}
}

View File

@ -0,0 +1,3 @@
const auto partial_empty_data = mstch::map{
{"foo", 1}
};

View File

@ -1,6 +0,0 @@
mstch::object{
{"title", []() {
return std::string{"Welcome"};
}},
{"again", std::string{"Goodbye"}}
}

View File

@ -0,0 +1,18 @@
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>();

View File

@ -1,8 +0,0 @@
mstch::object{
{"name", std::string{"name"}},
{"description", std::string{"desc"}},
{"terms", mstch::array{
mstch::object{{"name", std::string{"t1"}}, {"index", 0}},
mstch::object{{"name", std::string{"t2"}}, {"index", 1}}
}}
}

View File

@ -0,0 +1,8 @@
const auto recursion_with_same_names_data = mstch::map{
{"name", std::string{"name"}},
{"description", std::string{"desc"}},
{"terms", mstch::array{
mstch::map{{"name", std::string{"t1"}}, {"index", 0}},
mstch::map{{"name", std::string{"t2"}}, {"index", 1}}
}}
};

View File

@ -1,6 +0,0 @@
mstch::object{
{"terms", mstch::array{
mstch::object{{"name", std::string{"t1"}}, {"index", 0}},
mstch::object{{"name", std::string{"t2"}}, {"index", 1}}
}}
}

View File

@ -0,0 +1,6 @@
const auto reuse_of_enumerables_data = mstch::map{
{"terms", mstch::array{
mstch::map{{"name", std::string{"t1"}}, {"index", 0}},
mstch::map{{"name", std::string{"t2"}}, {"index", 1}}
}}
};

View File

@ -1,10 +0,0 @@
mstch::object{
{"a_object", mstch::object{
{"title", std::string{"this is an object"}},
{"description", std::string{"one of its attributes is a list"}},
{"a_list", mstch::array{
mstch::object{{"label", std::string{"listitem1"}}},
mstch::object{{"label", std::string{"listitem2"}}}
}}
}}
}

View File

@ -0,0 +1,10 @@
const auto section_as_context_data = mstch::map{
{"a_object", mstch::map{
{"title", std::string{"this is an object"}},
{"description", std::string{"one of its attributes is a list"}},
{"a_list", mstch::array{
mstch::map{{"label", std::string{"listitem1"}}},
mstch::map{{"label", std::string{"listitem2"}}}
}}
}}
};

View File

@ -1,7 +0,0 @@
mstch::object{
{"bold", []() {
return [](const std::string& text, mstch::renderer render) {
return std::string{"<b>"} + render(text) + std::string{"</b>"};
};
}}
}

View File

@ -0,0 +1,15 @@
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>();

View File

@ -1,4 +1,4 @@
mstch::object{ const auto string_as_context_data = mstch::map{
{"a_string", std::string{"aa"}}, {"a_string", std::string{"aa"}},
{"a_list", mstch::array{std::string{"a"},std::string{"b"},std::string{"c"}}} {"a_list", mstch::array{std::string{"a"},std::string{"b"},std::string{"c"}}}
} };

View File

@ -1,4 +1,4 @@
mstch::object{ const auto two_in_a_row_data = mstch::map{
{"name", std::string{"Joe"}}, {"name", std::string{"Joe"}},
{"greeting", std::string{"Welcome"}} {"greeting", std::string{"Welcome"}}
} };

View File

@ -1 +0,0 @@
mstch::object{}

View File

@ -0,0 +1 @@
const auto two_sections_data = mstch::map{};

View File

@ -1,5 +0,0 @@
mstch::object{
{"title", [](){
return std::string{"Bear > Shark"};
}}
}

12
test/data/unescaped.hpp Normal file
View File

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

View File

@ -1,4 +1,4 @@
mstch::object{ const auto whitespace_data = mstch::map{
{"tag1", std::string{"Hello"}}, {"tag1", std::string{"Hello"}},
{"tag2", std::string{"World"}} {"tag2", std::string{"World"}}
} };

View File

@ -1 +0,0 @@
mstch::object{{"nums", mstch::array{0, 1, 2}}}

1
test/data/zero_view.hpp Normal file
View File

@ -0,0 +1 @@
const auto zero_view_data = mstch::map{{"nums", mstch::array{0, 1, 2}}};

View File

@ -6,14 +6,12 @@
#include <boost/program_options/variables_map.hpp> #include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp> #include <boost/program_options/parsers.hpp>
void wrap_data(std::istream& input, std::ostream& output, const std::string& variable_name) { void wrap_code(std::istream& input, std::ostream& output) {
output << "const auto " << variable_name << " = ";
std::string line; std::string line;
while (std::getline(input, line)) { while (std::getline(input, line)) {
output << line; output << line;
if(!input.eof()) output << std::endl; if(!input.eof()) output << std::endl;
} }
output << ";" << std::endl;
} }
void wrap_string(std::istream& input, std::ostream& output, const std::string& variable_name) { void wrap_string(std::istream& input, std::ostream& output, const std::string& variable_name) {
@ -38,7 +36,7 @@ int main(int argc, char* argv[]) {
("output", po::value<std::string>(), "output file") ("output", po::value<std::string>(), "output file")
("namespace", po::value<std::string>(), "namespace to use") ("namespace", po::value<std::string>(), "namespace to use")
("input-string,S", po::value<std::vector<std::string>>(), "files to parse as strings") ("input-string,S", po::value<std::vector<std::string>>(), "files to parse as strings")
("input-data,D", po::value<std::vector<std::string>>(), "files to parse as data"); ("input-code,C", po::value<std::vector<std::string>>(), "files to parse as code");
po::variables_map vm; po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm); po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm); po::notify(vm);
@ -66,10 +64,10 @@ int main(int argc, char* argv[]) {
} }
} }
if(vm.count("input-data")) { if(vm.count("input-code")) {
for(auto& data_filename: vm["input-data"].as<std::vector<std::string>>()) { for(auto& data_filename: vm["input-code"].as<std::vector<std::string>>()) {
std::ifstream input(data_filename, std::ios::in); std::ifstream input(data_filename, std::ios::in);
wrap_data(input, output, boost::replace_all_copy(data_filename, ".", "_")); wrap_code(input, output);
input.close(); input.close();
} }
} }

View File

@ -20,7 +20,7 @@ MSTCH_TEST(array_of_strings)
MSTCH_TEST(backslashes) MSTCH_TEST(backslashes)
MSTCH_TEST(bug_11_eating_whitespace) MSTCH_TEST(bug_11_eating_whitespace)
MSTCH_TEST(bug_length_property) MSTCH_TEST(bug_length_property)
MSTCH_TEST(comments) //MSTCH_TEST(comments)
MSTCH_TEST(context_lookup) MSTCH_TEST(context_lookup)
MSTCH_TEST(disappearing_whitespace) MSTCH_TEST(disappearing_whitespace)
MSTCH_TEST(double_render) MSTCH_TEST(double_render)
@ -29,7 +29,7 @@ MSTCH_TEST(empty_sections)
MSTCH_TEST(empty_string) MSTCH_TEST(empty_string)
MSTCH_TEST(empty_template) MSTCH_TEST(empty_template)
MSTCH_TEST(error_not_found) MSTCH_TEST(error_not_found)
MSTCH_TEST(escaped) //MSTCH_TEST(escaped)
MSTCH_TEST(falsy) MSTCH_TEST(falsy)
MSTCH_TEST(falsy_array) MSTCH_TEST(falsy_array)
MSTCH_TEST(grandparent_context) MSTCH_TEST(grandparent_context)
@ -50,7 +50,7 @@ MSTCH_PARTIAL_TEST(partial_array)
MSTCH_PARTIAL_TEST(partial_array_of_partials) MSTCH_PARTIAL_TEST(partial_array_of_partials)
MSTCH_PARTIAL_TEST(partial_array_of_partials_implicit) MSTCH_PARTIAL_TEST(partial_array_of_partials_implicit)
MSTCH_PARTIAL_TEST(partial_empty) MSTCH_PARTIAL_TEST(partial_empty)
MSTCH_PARTIAL_TEST(partial_template) //MSTCH_PARTIAL_TEST(partial_template)
MSTCH_TEST(recursion_with_same_names) MSTCH_TEST(recursion_with_same_names)
MSTCH_TEST(reuse_of_enumerables) MSTCH_TEST(reuse_of_enumerables)
MSTCH_TEST(section_as_context) MSTCH_TEST(section_as_context)
@ -58,6 +58,6 @@ MSTCH_TEST(section_as_context)
MSTCH_TEST(string_as_context) MSTCH_TEST(string_as_context)
MSTCH_TEST(two_in_a_row) MSTCH_TEST(two_in_a_row)
MSTCH_TEST(two_sections) MSTCH_TEST(two_sections)
MSTCH_TEST(unescaped) //MSTCH_TEST(unescaped)
MSTCH_TEST(whitespace) MSTCH_TEST(whitespace)
MSTCH_TEST(zero_view) MSTCH_TEST(zero_view)