C++11 implementation of {{ mustache }}, compliant with spec v1.1.3.
unordered_map
, etc{{ mustache }} is a template language for text-replacing. When it comes to formatting, there are 2 essential things -- Format and Data. {{ mustache }} also allows an extra lookup-context for Partials. In {{ bustache }}, we represent the Format as a bustache::format
object, and bustache::object
for Data, and anything that provides interface that is compatible with Map<std::string, bustache::format>
can be used for Partials. The Format is orthogonal to the Data, so techincally you can use your custom Data type with bustache::format
, but then you have to write the formatting logic yourself.
bustache::format format{"{{mustache}} templating"}; bustache::object data{{"mustache", "bustache"}}; std::cout << format(data); // should print "bustache templating"
It's basically the JSON Data Model represented in C++, with some extensions.
#include <bustache/model.hpp>
using array = std::vector<value>; using object = boost::unordered_map<std::string, value>; using lambda0v = std::function<value()>; using lambda0f = std::function<format()>; using lambda1v = std::function<value(ast::content_list const&)>; using lambda1f = std::function<format(ast::content_list const&)>; class value = variant < std::nullptr_t , bool , int , double , std::string , array , lambda0v , lambda0f , lambda1v , lambda1f , object >;
bustache::format
parses in-memory string into AST.
#include <bustache/format.hpp>
Constructors
format(char const* begin, char const* end); // [1] template<std::size_t N> explicit format(char const (&source)[N]); // [2] template<class Source> explicit format(Source const& source); // [3] template <typename Source> explicit format(Source const&& source); // [4] explicit format(ast::content_list contents, bool copytext = true); // [5]
Source
is an object that represents continous memory, like std::string
, std::vector<char>
or boost::iostreams::mapped_file_source
that provides access to raw memory through source.data()
and source.size()
.ast::content_list
, if copytext == true
the text will be copied into the internal buffer.Manipulator
template <typename T> manipulator<T, no_context> operator()(T const& data, option_type flag = normal) const; template <typename T, typename Context> manipulator<T, Context> operator()(T const& data, Context const& context, option_type flag = normal) const;
Context
is any associative container Map<std::string, bustache::format>
, which is referenced by Partials.option_type
provides 2 options: normal
and escape_html
, if normal
is chosen, there‘s no difference between {{Tag}}
and {{{Tag}}}
, the text won’t be escaped in both cases.Output directly to the std::basic_ostream
.
// in <bustache/model.hpp> template<class CharT, class Traits, class T, class Context, std::enable_if_t<std::is_constructible<value::view, T>::value, bool> = true> inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& out, manipulator<T, Context> const& manip)
// open the template file boost::iostreams::mapped_file_source file(...); // create format from source bustache::format format(file); // create the data we want to output bustache::object data{...}; // create the context for Partials std::unordered_map<std::string, bustache::format> context{...}; // output the result std::cout << format(data, context, bustache::escape_html);
Note that you can output anything that constitutes bustache::value
, not just bustache::object
.
Generate a std::string
from a manipulator
.
// in <bustache/model.hpp> template<class T, class Context, std::enable_if_t<std::is_constructible<value::view, T>::value, bool> = true> inline std::string to_string(manipulator<T, Context> const& manip)
bustache::format format(...); std::string txt = to_string(format(data, context, bustache::escape_html));
generate
can be used for customized output.
#include <bustache/generate.hpp>
template<class Sink> inline void generate ( Sink& sink, format const& fmt, value::view const& data, option_type flag = normal ); template<class Sink, class Context> void generate ( Sink& sink, format const& fmt, value::view const& data, Context const& context, option_type flag = normal );
Sink
is a polymorphic functor that handles:
void operator()(char const* it, char const* end); void operator()(bool data); void operator()(int data); void operator()(double data);
You don‘t have to deal with HTML-escaping yourself, it’s handled within generate
depending on the option.
These are predefined output built on generate
.
#include <bustache/generate/ostream.hpp>
#include <bustache/generate/string.hpp>
template<class CharT, class Traits, class Context> void generate_ostream ( std::basic_ostream<CharT, Traits>& out, format const& fmt, value::view const& data, Context const& context, option_type flag ); template<class String, class Context> void generate_string ( String& out, format const& fmt, value::view const& data, Context const& context, option_type flag );
The stream-based output and string output are built on these functions, but <bustache/model.hpp>
doesn't include these headers and only supports char
output, if you need other char-type support for stream/string output, you have to include these headers as well.
The lambdas in {{ bustache }} have 4 variants - they're production of 2 param-set x 2 return-type. One param-set accepts no params, the other accepts a bustache::ast::content_list const&
. One return-type is bustache::value
, the other is bustache::format
.
Note that unlike other implementations, we pass a bustache::ast::content_list
instead of a raw string. A content_list
is a parsed list of AST nodes, you can make a new content_list
out of the old one and give it to a bustache::format
.
The constructor of bustache::format
may throw bustache::format_error
if the parsing fails.
class format_error : public std::runtime_error { public: explicit format_error(error_type err); error_type code() const; };
error_type
has these values:
You can also use what()
for a descriptive text.
Compare with 2 other libs - mstch and Kainjow.Mustache. See benchmark.cpp.
Sample run (VS2015 Update 3, boost 1.60.0, 64-bit release build):
Benchmark Time CPU Iterations ----------------------------------------------------- bustache_usage 6325 ns 6397 ns 112179 mstch_usage 140822 ns 140795 ns 4986 kainjow_usage 47354 ns 47420 ns 14475
Lower is better.
Copyright (c) 2014-2017 Jamboree Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)