synth
A Powerful C++ Templating Framework with command-line and Python bindings, written by Alvaro J. Genial.
Synopsis
Synth is a template framework—a set of components that can be mixed and matched to build the right functionality; furthermore, components are loosely-coupled, designed to be both extensible and replaceable.
Status
Beta, approaching a first full release.
Motivation
Synth blurs the line between compile-time and runtime, and it does so by blending three worlds: (a) the static C++ type system; (b) the dynamic values that need to be manipulated and formatted, including those from other languages; and (c) the templates to do so. The name is an allusion to this synthesis process, which combines values to generate new ones (streams, files, strings, numbers, etc.)
Examples
Command-line
echo '{"user": "Dolph Lundgren"}' > 'ctx.json'
echo 'Howdy, {{ user }}!' > 'tpl.txt'
cat tpl.txt | synth -e django -c ctx.jsonPython
import synth
def simple_tmpl_example():
tpl = synth.Template('Howdy, <TMPL_VAR user>!', 'tmpl')
ctx = {'user': 'Dolph Lundgren'}
tpl.render_to_file("greeting.txt", ctx)
# or, e.g.:
return tpl.render_to_string(ctx)C++
#include <map>
#include <string>
#include <iostream>
#include <ajg/synth.hpp>
std::string simple_ssi_example() {
using namespace ajg::synth;
typedef string_template<char, ssi::engine<> > template_type;
template_type const tpl("Howdy, <!--#echo var=\"user\" -->!");
template_type::context_type ctx;
ctx["user"] = "Dolph Lundgren";
tpl.render(std::cout);
// or, e.g.:
tpl.render_to_file("greeting.txt", ctx);
// or, e.g.:
return tpl.render_to_string(ctx);
}Reference
Command-line
synth [FLAGS...]
-h [ --help ] print help message
-v [ --version ] print library version
-c [ --context ] file the data: *.{ini,json,xml}
-e [ --engine ] name template engine: {django,ssi,tmpl}
-a [ --autoescape ] bool automatically escape values (default: 'true')
-d [ --directories ] path template lookup directories (default: '.')
-r [ --replacement ] text replaces missing values (default: '')Dependencies
Building synth from source requires:
Synth is known to compile with:
g++versions4.2.1and4.6.3clang++version3.3, including Apple'sLLVM version 5.0boostversions1.46and1.55
Installing Boost
On OS X, using Homebrew:
brew install boost --build-from-sourceUsing Apt, typically on Debian or Ubuntu:
sudo apt-get install libboost-all-devUsing Yum, typically on Fedora or RHEL (untested):
sudo yum install boost-develOn Windows, download a suitable version from here:
http://sourceforge.net/projects/boost/files/boost-binaries/
Installation
From source:
Install the dependencies.
Get the source:
git clone --recursive https://github.com/ajg/synth.git && cd synthOptional Build the command-line program:
scons synth # Add debug=1 to generate debugging symbols & disable optimizations.Optional Build (and install) the Python module:
python setup.py install
(Pre-built binaries are in the works.)
Using Pip:
Install Boost, then:
pip install synthUsing Easy Install:
Install Boost, then:
easy_install synthComponents
Engines
django: An implementation of Django Templates.ssi: An implementation of Server Side Includes.tmpl: An implementation of Perl's HTML::Template.
Bindings
command_linepython
Templates
file_templatemulti_templatestream_templatestring_template
Adapters
array[N](Native static array.)[](Native dynamic array.)boost::array
boolbool
complexstd::complex
containerstd::dequestd::listmapstd::mapstd::multimap
setstd::setstd::multiset
std::stackstd::vector
memorystd::auto_ptr
numericcharchar signedchar unsignedshortshort unsignedintint unsignedlonglong unsignedwchar_t(When available.)long long(When available.)long long unsigned(When available.)__int64(MSVC-only.)__int64 unsigned(MSVC-only.)floatdoublelong double
optionalboost::optional
ptimeboost::posix_time::ptime
ptreeboost::property_tree::ptree
pointer*(Native pointer.)
refboost::reference_wrapper
smart_ptrboost::scoped_arrayboost::scoped_ptrboost::shared_arrayboost::shared_ptr
stringstd::basic_string
utilitystd::pair
variantboost::variant
Formats
inijsonxml
Bases
base_templateabstract_adapter
Django Engine
Tags
django::autoescape_tagdjango::block_tagdjango::comment_tagdjango::csrf_token_tagdjango::cycle_tagdjango::debug_tagdjango::extends_tagdjango::filter_tagdjango::firstof_tagdjango::for_tagdjango::for_empty_tagdjango::if_tagdjango::ifchanged_tagdjango::ifequal_tagdjango::ifnotequal_tagdjango::include_tagdjango::load_tagdjango::load_from_tagdjango::now_tagdjango::regroup_tagdjango::spaceless_tagdjango::ssi_tagdjango::templatetag_tagdjango::url_tagdjango::url_as_tagdjango::variable_tagdjango::verbatim_tagdjango::widthratio_tagdjango::with_tagdjango::library_tag
Filters
django::add_filterdjango::addslashes_filterdjango::capfirst_filterdjango::center_filterdjango::cut_filterdjango::date_filterdjango::default_filterdjango::default_if_none_filterdjango::dictsort_filterdjango::dictsortreversed_filterdjango::divisibleby_filterdjango::escape_filterdjango::escapejs_filterdjango::filesizeformat_filterdjango::first_filterdjango::fix_ampersands_filterdjango::floatformat_filterdjango::force_escape_filterdjango::get_digit_filterdjango::iriencode_filterdjango::join_filterdjango::last_filterdjango::length_filterdjango::length_is_filterdjango::linebreaks_filterdjango::linebreaksbr_filterdjango::linenumbers_filterdjango::ljust_filterdjango::lower_filterdjango::make_list_filterdjango::phone2numeric_filterdjango::pluralize_filterdjango::pprint_filterdjango::random_filterdjango::removetags_filterdjango::rjust_filterdjango::safe_filterdjango::safeseq_filterdjango::slice_filterdjango::slugify_filterdjango::stringformat_filterdjango::striptags_filterdjango::time_filterdjango::timesince_filterdjango::timeuntil_filterdjango::title_filterdjango::truncatechars_filterdjango::truncatechars_html_filterdjango::truncatewords_filterdjango::truncatewords_html_filterdjango::unordered_list_filterdjango::upper_filterdjango::urlencode_filterdjango::urlize_filterdjango::urlizetrunc_filterdjango::wordcount_filterdjango::wordwrap_filterdjango::yesno_filter
Options
django::options::autoescapedjango::options::nonbreaking_spacedjango::options::default_value(forTEMPLATE_STRING_IF_INVALID)django::options::formats(forTIME_FORMAT,DATE_FORMAT, etc.)django::options::debug(forTEMPLATE_DEBUG)django::options::directories(forTEMPLATE_DIRS)django::options::libraries(for external tags & filters)django::options::loaders(for dynamically loading libraries)
SSI Engine
Directives
ssi::config_directivessi::echo_directivessi::exec_directivessi::fsize_directivessi::flastmod_directivessi::if_directivessi::include_directivessi::printenv_directivessi::set_directive
Options
ssi::options::echo_messagessi::options::directoriesssi::options::size_formatssi::options::time_formatssi::options::error_message
TMPL Engine
Tags
tmpl::comment_tag(Technically, part ofctpp)tmpl::if_tagtmpl::include_tagtmpl::loop_tagtmpl::unless_tagtmpl::variable_tag
Future Work
- Build:
- Create Visual Studio 2013 solution & project ~ Pass /W3 cleanly ~ Pass /W4 cleanly ~ Pass /Wall cleanly
- Create Visual Studio 2012 solution & project
- Distribution:
- Pre-built OS X binaries
- Pre-built Windows binaries
- Homebrew formula
- Bindings:
- Engines:
- v1+
cheetahengine ctppenginemulti_engine
- v1+
- Traits:
- Add dedicated
none_typedefaulted toboost::none_t~ Propagate this type in lieu ofboolean_typewhere appropriate
- Add dedicated
- Adapters:
- Templates:
descriptor_template- Clean up and make
multi_templatepublic
- Django:
- Named arguments (e.g. for tags and filters)
- Option to pre-load libraries, tags and filters
- Implement missing date/time format specifiers
- Make markers dynamically configurable
- SSI:
- Implement additional directives from Jigsaw
- Command-line:
- Python:
- Turn optional arguments to synth.Template into kwargs
- Full support for
unicodetype
- Documentation:
- Produce Boost-compatible documentation
- Create
conf.py(et al.) to enable ReadTheDocs
- Testing:
- Rewrite the majority of unit tests as a set of .in/.out files
- Add unit tests from Cjango
- Add way to specify expected failures; re-enable commented out tests
- Optimization:
- Compare benefit/cost of
-O,-O2,-O3and-Ofast - Investigate
-fvisibility-inlines-hidden - Replace
ostream << string(a, b)constructs withstd::ostream_iterator+std::copy
- Compare benefit/cost of
- Refactoring:
- Replace all
`foo'messages with`foo` - Move
*_templates to own namespace - Move
engines to own namespace - Replace all remaining get_nested uses with s1, s2, ... or named patterns
- v2 Create
c++11/c++14branch- Translate macros to variadic templates
- Replace
BOOST_FOREACHwith newforloop - Replace
boost::assignuse with aggregate initializers - Remove needlessly configurable (especially defaulted)
templateparameters - Remove complex redundant
typedefs in favor ofauto
- v1+ Sort
#includes alphabetically - v1+ Run entire C++ codebase through clang-format
- Change
classin template signatures totypename - Rename
Array/array_typetoSequence/sequence_type - Introduce
Mapping/mapping_typeto replace hard-codedstd::maps - v2 Test or drop support for non-
chartypes (e.g.wchar_t) - v1 Hygienicize and prefix all macros (and #undef private ones after use)
- v1 Rename
this_typetoself_typeunless it's actually a pointer - v1 Reformat all operator ()'s to operator()
- v2+ Factor out values & adapters into separate library for generic language interop
- Replace all
Frequently Asked Questions (FAQs)
Q: Why does installation fail with the following error?
#include <boost/python.hpp> ^ 1 error generated. error: command 'cc' failed with exit status 1A: You need to install Boost.Python first.
License
This library is distributed under the Boost LICENSE.

