From cb7021881a3ccd97311a580b903dc82bebbc092d Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 20 Jun 2017 14:26:19 +0200 Subject: Whiskers template system --- libdevcore/Whiskers.cpp | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ libdevcore/Whiskers.h | 87 +++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 libdevcore/Whiskers.cpp create mode 100644 libdevcore/Whiskers.h (limited to 'libdevcore') 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 . +*/ +/** @file Whiskers.cpp + * @author Chris + * @date 2017 + * + * Moustache-like templates. + */ + +#include + +#include + +#include + +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> 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> const& _listParameters +) +{ + using namespace boost; + static regex listOrTag("<([^#/>]+)>|<#([^>]+)>(.*?)"); + return regex_replace(_template, listOrTag, [&](match_results _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 . +*/ +/** @file Whiskers.h + * @author Chris + * @date 2017 + * + * Moustache-like templates. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace dev +{ + +DEV_SIMPLE_EXCEPTION(WhiskersError); + +/// +/// Moustache-like templates. +/// +/// Usage: +/// std::vector> listValues(2); +/// listValues[0]["k"] = "key1"; +/// listValues[0]["v"] = "value1"; +/// listValues[1]["k"] = "key2"; +/// listValues[1]["v"] = "value2"; +/// auto s = Whiskers("\n<#list> -> \n") +/// ("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; + using StringListMap = std::map>; + + explicit Whiskers(std::string const& _template); + + /// Sets a single parameter, . + Whiskers& operator()(std::string const& _parameter, std::string const& _value); + /// Sets a list parameter, <#listName> . + Whiskers& operator()( + std::string const& _listParameter, + std::vector 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; +}; + +} -- cgit