diff options
author | chriseth <chris@ethereum.org> | 2017-06-20 20:26:19 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2017-06-22 22:56:57 +0800 |
commit | cb7021881a3ccd97311a580b903dc82bebbc092d (patch) | |
tree | 12b94e40b585d863473ed232478a5f642cd85d30 /libdevcore | |
parent | f90a514f80b74518fbbdd7ef3a511df4f13abed2 (diff) | |
download | dexon-solidity-cb7021881a3ccd97311a580b903dc82bebbc092d.tar.gz dexon-solidity-cb7021881a3ccd97311a580b903dc82bebbc092d.tar.zst dexon-solidity-cb7021881a3ccd97311a580b903dc82bebbc092d.zip |
Whiskers template system
Diffstat (limited to 'libdevcore')
-rw-r--r-- | libdevcore/Whiskers.cpp | 127 | ||||
-rw-r--r-- | libdevcore/Whiskers.h | 87 |
2 files changed, 214 insertions, 0 deletions
diff --git a/libdevcore/Whiskers.cpp b/libdevcore/Whiskers.cpp new file mode 100644 index 00000000..4bad8476 --- /dev/null +++ b/libdevcore/Whiskers.cpp @@ -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; +} + diff --git a/libdevcore/Whiskers.h b/libdevcore/Whiskers.h new file mode 100644 index 00000000..21d46af4 --- /dev/null +++ b/libdevcore/Whiskers.h @@ -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; +}; + +} |