Whiskers template system

This commit is contained in:
chriseth
2017-06-22 16:56:57 +02:00
parent f90a514f80
commit cb7021881a
4 changed files with 342 additions and 0 deletions
+127
View File
@@ -0,0 +1,127 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Whiskers.cpp
* @author Chris <chis@ethereum.org>
* @date 2017
*
* Moustache-like templates.
*/
#include <libdevcore/Whiskers.h>
#include <libdevcore/Assertions.h>
#include <boost/regex.hpp>
using namespace std;
using namespace dev;
Whiskers::Whiskers(string const& _template):
m_template(_template)
{
}
Whiskers& Whiskers::operator ()(string const& _parameter, string const& _value)
{
assertThrow(
m_parameters.count(_parameter) == 0,
WhiskersError,
_parameter + " already set."
);
assertThrow(
m_listParameters.count(_parameter) == 0,
WhiskersError,
_parameter + " already set as list parameter."
);
m_parameters[_parameter] = _value;
return *this;
}
Whiskers& Whiskers::operator ()(
string const& _listParameter,
vector<map<string, string>> const& _values
)
{
assertThrow(
m_listParameters.count(_listParameter) == 0,
WhiskersError,
_listParameter + " already set."
);
assertThrow(
m_parameters.count(_listParameter) == 0,
WhiskersError,
_listParameter + " already set as value parameter."
);
m_listParameters[_listParameter] = _values;
return *this;
}
string Whiskers::render() const
{
return replace(m_template, m_parameters, m_listParameters);
}
string Whiskers::replace(
string const& _template,
StringMap const& _parameters,
map<string, vector<StringMap>> const& _listParameters
)
{
using namespace boost;
static regex listOrTag("<([^#/>]+)>|<#([^>]+)>(.*?)</\\2>");
return regex_replace(_template, listOrTag, [&](match_results<string::const_iterator> _match) -> string
{
string tagName(_match[1]);
if (!tagName.empty())
{
assertThrow(_parameters.count(tagName), WhiskersError, "Tag " + tagName + " not found.");
return _parameters.at(tagName);
}
else
{
string listName(_match[2]);
string templ(_match[3]);
assertThrow(!listName.empty(), WhiskersError, "");
assertThrow(
_listParameters.count(listName),
WhiskersError, "List parameter " + listName + " not set."
);
string replacement;
for (auto const& parameters: _listParameters.at(listName))
replacement += replace(templ, joinMaps(_parameters, parameters));
return replacement;
}
});
}
Whiskers::StringMap Whiskers::joinMaps(
Whiskers::StringMap const& _a,
Whiskers::StringMap const& _b
)
{
Whiskers::StringMap ret = _a;
for (auto const& x: _b)
assertThrow(
ret.insert(x).second,
WhiskersError,
"Parameter collision"
);
return ret;
}
+87
View File
@@ -0,0 +1,87 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Whiskers.h
* @author Chris <chis@ethereum.org>
* @date 2017
*
* Moustache-like templates.
*/
#pragma once
#include <libdevcore/Exceptions.h>
#include <string>
#include <map>
#include <vector>
namespace dev
{
DEV_SIMPLE_EXCEPTION(WhiskersError);
///
/// Moustache-like templates.
///
/// Usage:
/// std::vector<std::map<std::string, std::string>> listValues(2);
/// listValues[0]["k"] = "key1";
/// listValues[0]["v"] = "value1";
/// listValues[1]["k"] = "key2";
/// listValues[1]["v"] = "value2";
/// auto s = Whiskers("<p1>\n<#list><k> -> <v>\n</list>")
/// ("p1", "HEAD")
/// ("list", listValues)
/// .render();
///
/// results in s == "HEAD\nkey1 -> value1\nkey2 -> value2\n"
///
/// Note that lists cannot themselves contain lists - this would be a future feature.
class Whiskers
{
public:
using StringMap = std::map<std::string, std::string>;
using StringListMap = std::map<std::string, std::vector<StringMap>>;
explicit Whiskers(std::string const& _template);
/// Sets a single parameter, <paramName>.
Whiskers& operator()(std::string const& _parameter, std::string const& _value);
/// Sets a list parameter, <#listName> </listName>.
Whiskers& operator()(
std::string const& _listParameter,
std::vector<StringMap> const& _values
);
std::string render() const;
private:
static std::string replace(
std::string const& _template,
StringMap const& _parameters,
StringListMap const& _listParameters = StringListMap()
);
/// Joins the two maps throwing an exception if two keys are equal.
static StringMap joinMaps(StringMap const& _a, StringMap const& _b);
std::string m_template;
StringMap m_parameters;
StringListMap m_listParameters;
};
}