mstch is a complete implementation of {{mustache}} templates using modern C++
Find a file
2015-09-24 11:43:27 +02:00
include/mstch MSVC support 2015-09-24 11:43:27 +02:00
src MSVC support 2015-09-24 11:43:27 +02:00
test MSVC support 2015-09-24 11:43:27 +02:00
vendor spec submodule 2015-05-05 08:58:07 +02:00
.gitignore ignore build directories 2015-05-04 16:36:24 +02:00
.gitmodules spec submodule 2015-05-05 08:58:07 +02:00
.travis.yml build with multiple gcc versions 2015-05-12 08:11:01 +02:00
CMakeLists.txt MSVC support 2015-09-24 11:43:27 +02:00
LICENSE Initial commit 2015-04-09 20:14:44 +02:00
README.md lambda type 2015-05-09 11:38:41 +02:00

mstch - {{mustache}} templates in C++11

mstch logo

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.

GitHub version Build Status

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.4.2, 3.5
  • Boost 1.54+ for Boost.Variant
  • CMake 2.8+ 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.