74ed09fda0
CMake allows projects to build dependencies as subdirectories using the add_subdirectory command. CMAKE_SOURCE_DIR refers to the top-level project directory which may very well *not* be the mstch root directory if mstch is "embedded" in another project. This patch offers to use PROJECT_SOURCE_DIR instead which accurately refers to the "source directory of the most recent `project()` command", in this case, the mstch root directory. |
||
---|---|---|
benchmark | ||
cmake | ||
include/mstch | ||
src | ||
test | ||
vendor | ||
.gitignore | ||
.gitmodules | ||
.travis.yml | ||
appveyor.yml | ||
CMakeLists.txt | ||
LICENSE | ||
README.md |
mstch - {{mustache}} templates in C++11
mstch is a complete implementation of {{mustache}} templates using modern C++. It's compliant with specifications v1.1.2, including the lambda module.
It works great with json.hpp.
Supported features
mstch supports the complete feature set described in the mustache(5)
manpage:
- JSON-like data structure using Boost.Variant
- variables, sections, inverted sections
- partials
- changing the delimiter
- C++11 lambdas
- C++ objects as view models
Basic usage
#include <iostream>
#include <mstch/mstch.hpp>
int main() {
std::string view{"{{#names}}Hi {{name}}!\n{{/names}}"};
mstch::map context{
{"names", mstch::array{
mstch::map{{"name", std::string{"Chris"}}},
mstch::map{{"name", std::string{"Mark"}}},
mstch::map{{"name", std::string{"Scott"}}},
}}
};
std::cout << mstch::render(view, context) << std::endl;
return 0;
}
The output of this example will be:
Hi Chris!
Hi Mark!
Hi Scott!
Data structure
The types in the example above, mstch::array
and mstch::map
are actually
aliases for standard types:
using map = std::map<const std::string, node>;
using array = std::vector<node>;
mstch::node
is a boost::variant
that can hold a std::string
, int
,
double
, bool
, mstch::lambda
or a std::shared_ptr<mstch::object>
(see below), also a map or an array recursively. Essentially it works just like
a JSON object.
Note that when using a std::string
as value you must explicitly specify the
type, since a const char*
literal like "foobar"
would be implicitly
converted to bool
. Alternatively you can use C++14 string_literals
if your compiler supports it.
Advanced usage
Partials
Partials can be passed in a std::map
as the third parameter of the
mstch::render
function:
std::string view{"{{#names}}{{> user}}{{/names}}"};
std::string user_view{"<strong>{{name}}\n</strong>"};
mstch::map context{
{"names", mstch::array{
mstch::map{{"name", std::string{"Chris"}}},
mstch::map{{"name", std::string{"Mark"}}},
mstch::map{{"name", std::string{"Scott"}}},
}}
};
std::cout << mstch::render(view, context, {{"user", user_view}}) << std::endl;
Output:
<strong>Chris</strong>
<strong>Mark</strong>
<strong>Scott</strong>
Lambdas
C++11 lambda expressions can be used to add logic to your templates. Like a
const char*
literal, lambdas can be implicitly converted to bool
, so they
must be wrapped in a mstch::lambda
object when used in a mstch::node
. The
lambda expression passed to mstch::lambda
must itself return a mstch::node
.
The returned node will be rendered to a string, then it will be parsed as a
template.
The lambda expression accepts either no parameters:
std::string view{"Hello {{lambda}}!"};
mstch::map context{
{"lambda", mstch::lambda{[]() -> mstch::node {
return std::string{"World"};
}}}
};
std::cout << mstch::render(view, context) << std::endl;
Output:
Hello World!
Or it accepts a const std::string&
that gets the unrendered literal block:
std::string view{"{{#bold}}{{yay}} :){{/bold}}"};
mstch::map context{
{"yay", std::string{"Yay!"}},
{"bold", mstch::lambda{[](const std::string& text) -> mstch::node {
return "<b>" + text + "</b>";
}}}
};
std::cout << mstch::render(view, context) << std::endl;
Output:
<b>Yay! :)</b>
Objects
Custom objects can also be used as context for rendering templates. The class
must inherit from mstch::object
, and register it's exported methods with
register_methods
. Exported methods must have the return type of mstch::node
.
Objects must be created as a std::shared_ptr
.
class example: public mstch::object {
public:
example(): m_value(1) {
register_methods(this, {
{"count", &example::count},
{"names", &example::names}
});
}
mstch::node count() {
return m_value++;
}
mstch::node names() {
return mstch::array{
std::string{"Chris"}, std::string{"Mark"}, std::string{"Scott"}};
}
private:
int m_value;
};
std::string view{"{{#names}}<b>{{count}}</b>: {{.}}\n{{/names}}"};
const auto context = std::make_shared<example>();
std::cout << mstch::render(view, context) << std::endl;
Output:
<b>1</b>: Chris
<b>2</b>: Mark
<b>3</b>: Scott
Requirements
- A C++ compiler with decent C++11 support. Currently tested with:
- GCC 4.7, 4.8, 4.9
- clang 3.5, 3.6
- MSVC 2013, 2015
- Boost 1.54+ for Boost.Variant
- CMake 3.0+ for building
Installing
From the root of the source tree:
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install
Running the unit tests
Unit tests are using the Catch framework, included in the repository. Boost.Program_Options, Boost.Spirit, and The Boost Algorithm Library are also required to build them.
Don't forget to initialize submodules:
$ git submodule init
$ git submodule update
To build and run the unit tests:
$ mkdir build
$ cd build
$ cmake -DWITH_UNIT_TESTS=ON ..
$ make
$ make test
License
mstch is licensed under the MIT license.