jamboree / bustache Goto Github PK
View Code? Open in Web Editor NEWC++20 implementation of {{ mustache }}
C++20 implementation of {{ mustache }}
The following commit adds line and column info to the format_error
class, which makes locating errors in templates much easier.
Using the additional info, one can generate a helpful error message from a format_error
as follows:
[[noreturn]] static void throwParseError(const std::filesystem::path& file, const bustache::format_error& error)
{
// we use 1-based indexing here
auto line = error.line() + 1,
column = error.column() + 1;
std::ostringstream sstr;
sstr << "while parsing file '" << minunicode::path_to_utf8(file) << "':\n";
auto indent = std::string_view{ " " };
auto curIndent = std::string(indent);
if (line > 0 && column > 0)
{
sstr << curIndent;
if (multiline)
sstr << "in line " << line << ", column ";
else
sstr << "in column ";
sstr << column << ":\n";
curIndent += std::string(indent);
}
sstr << curIndent << bustache::error_type_to_message(error.code());
std::throw_with_nested(std::runtime_error(sstr.str()));
}
The implementation approach is probably not ideal; I opted to be minimally invasive because I didn't want to change too many function signatures. Also, the error message returned by format_error::what()
currently remains unchanged, and I added a slightly redundant error_type_to_message()
function which omits the non-human-readable parts of the error message. A better approach might be to pass through the start of the range to all parsing functions and to generate a more helpful error message at the throw site rather than catching the plain error code and re-throwing another exception.
How would you like this to be implemented in order to be eligible for merging? Do you want format_error::what()
to remain unchanged, or would it be acceptable to have the error message include line and column info?
I currently use Bustache the normal way, I first load a json object with data that is mapped to replacement tags.
If no mapping is found, is it possible to execute a function when a certain replacement tag is encountered instead. This function would then provide the data to the replacement tag.
Let me explain why I ask. Assume that you have a replacement tag {{debugInformation}}
that is expensive to compute. This tag is only inserted arbitrarily by the user (when the template is developed or modified).
This is not an enhancement request, if this is not possible, I can use arguments configuration options to either compute or not compute this debug information. Thank you.
I downloaded Jamboree Bustache and I am getting compiler errors when trying to use Nlohmann Json with it.
The documentation states: "Most STL-compatible containers will work out-of-the-box" but I guess that Nlohmann Json does need an adapter to work with Bustache.
I see that Boost Json does have an adapter for it.
I looked at adapted/boost_json.hpp to see if I could do something for Nlohmann but this is way beyond my ability. Would someone who understands this kind of complexity please create one for Nlohmann since it is such a popular and easy to use Json library?
Not really an issue but I noticed that using nlohmann::ordered_json causes a compiler error (when rendering the template):
error C7608: atomic constraint should be a constant expression
I don't know if there are plans to allow bustache to work with ordered_json or not. Anyway, I looked at a very interesting post regarding ordered vs unordered maps: https://stackoverflow.com/questions/2196995/is-there-any-advantage-of-using-map-over-unordered-map-in-case-of-trivial-keys
Some users posted some test results for the containers. For the purpose of Bustache users, I personally do not see any benefit whatsoever of an ordered vs unordered container.
So the only applicable reason, that I could think of using an UNORDERED map would be if you wanted to save Json to a file while keeping the exact unordered or natural order as it was created. Using an ordered container means that key/value pairs will not be reordered in alphabetical order by 'key'.
Another possible benefit of orderd_json would be that someone may want to pretty print Json in its natural order for debugging purposes.
I'm still trying to find my way with the library, but when looking at examples of how to use it in the tests, I did some attempts and I got something very strange to me:
using namespace bustache;
context cont = {{"include", "{{$person}}customer{{/person}}"_fmt}};
auto x = "Greetings {{<include}} IGNORED {{$person}}Alice{{/person}}{{/include}}"_fmt(nullptr);
std::cout << "1 " << x.context(cont) << std::endl;
auto y = "Greetings {{<include}} IGNORED {{$person}}Alice{{/person}}{{/include}}"_fmt;
std::cout << "2 " << y(nullptr).context(cont) << std::endl;
I get:
1
2 Greetings Alice
And I doing something wrong? I don't see why one usage should be different from the other, though I'm not familiar with the types returned in each case.
Thank you.
I've been using Bustache templates with great success. Now, I would also like to use Bustache Object as a container for storing and searching for data but I am having problems finding the second value as you can see here:
// find a key in the Bustache container
auto result = bustObj.find("1IX99OAVFXOA");
// display the first value
std::cout << result->first << std::endl; // 1IX99OAVFXOA
// display the second value
//std::cout << result->second << std::endl; // compiler error
bustache::value x = result->second;
I cannot figure out how to obtain the second value, please help me.
Thank you
First of all thank you for providing a C++ mustache implementation, that is fast, works with any data types and supports template inheritance. I do have 2 questions/wishlist/documentation items. I am going to use handlebars.js as a reference here to help explain nice to haves but am not recommending its exact choice to address the issues.
mustache related: Do you have any way to control the whitespace? This is a deficiency of the mustache specification that many would like fixed in mustache 2 if it ever gets created.
https://dev.to/cocoroutine/truth-about-template-engines-part-2-nf6
https://handlebarsjs.com/guide/expressions.html#whitespace-control
https://dev.to/cocoroutine/truth-about-template-engines-3a7
The goal is to have templates that look good but also can created results that look good also. This means allowing template writer to manually control indentation to the right and left of per line output and getting rid of empty line.
This is less important than 2) but is mentioned first due to its brevity.
Everything thing else is "Trait-based user-defined model" related. Your documentation says is for a type that be both a atom, object and list but the actual example presented was for a variant which is more a exclusive or type. Ultimately what is be asked for is for all list and objects to have additional runtime properties without any customization.
https://handlebarsjs.com/api-reference/data-variables.html#root
This is purely a data model issue and does not go beyond the current mustache specification.
handlebars has @root, @FIRST, @Index, @key, @last, this, ., ..
A) The first 2 that I would be looking for on list is @empty and @notempty
You have these now in the list model just not exposed to the mustache template via the following
static bool empty(T const& self);
use case is as follows
{{#some_list.@isnotempty}}
HTML table element start tag
{{/some_list.@isnotempty}}
{{#some_list}}
HTML rows
{{/some_list}}
{{#some_list.@isnotempty}}
HTML table element end tag
{{/some_list.@isnotempty}}
B) @root, this, ., ..
would be good to reference relative data from current or root
C) @isfirst, @Islast
is good for in between rows as in separators by remove either first or last since mustache spec does NOT provide separator support
D) @iseven, @isodd
is good for alternating styling
E) @key and other handlebars voodoo is about pivoting data ... a @pivot property for the bustache object model may be better
so objects can be viewed as an object with members, accessed by name, which is already standard in mustache, which is good with static typing but not dynamic typing because objects can also be viewed as maps, instead of classes, so a list of key value pairs. @pivot would then be a dynamic object property that returns a list view of the map. As a consequence A) through D) would then be available.
While I wouldn't mind doing it myself via your "Trait-based user-defined model" functionality if it could handle it. It would be much better if these data model functionality was provided globally.
Is there any reason why Boost's unordered_map<>
implementation is used instead of the standard one which is available since C++11?
Hi, would be great if you could give some instructions on compiling the example.
I've tried following the example at https://wandbox.org/permlink/Vxmrb2GgcLKicC7N and I'm running
g++ example/main.cpp -Wall -Wextra -std=c++11 "-I/usr/include" "-I./include"
but I'm getting masses of undefined reference to bustache::*
and undefined reference to boost::*
cmake .; make; sudo make install
all work fine. I'm on ubuntu 17.04.
Hey there,
i just wanted to let you know, that there is a new kid on the block.
Since i had the need for a small, fast and memory efficient template engine for a micro controller (e.g. ESP8266), i wrote one:
https://github.com/mincequi/tinja
Also did some performance checks with bustache. But please, check yourself.
Hopefully, you find this interesting.
I failed to compile the code under MacOS with the following configuration:
cmake version: 3.11.0,
clang --version:
Apple LLVM version 9.1.0 (clang-902.0.39.1)
Target: x86_64-apple-darwin17.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
boost version: 1.66
Building Output:
`[ 66%] Building CXX object CMakeFiles/bustache.dir/src/format.cpp.o
[ 66%] Building CXX object CMakeFiles/bustache.dir/src/generate.cpp.o
In file included from /Users/build/bustache-master/src/generate.cpp:8:
In file included from /Users/build/bustache-master/include/bustache/generate.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/model.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/format.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/ast.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/detail/variant.hpp:12:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:198:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__tuple:16:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:4323:23: error: calling 'operator()' with incomplete return type 'bustache::value'
_LIBCPP_INVOKE_RETURN(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__config:441:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_NAMESPACE
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:4220:23: note: expanded from macro '_LIBCPP_INVOKE_RETURN'
noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) \
^~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:4340:9: note: in instantiation of exception specification for '__invoke<std::__1::function<bustache::value ()> &>' requested here
_VSTD::__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...));
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__config:441:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_NAMESPACE
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1601:33: note: in instantiation of template class 'std::__1::__invokable_r<void, std::__1::function<bustache::value ()> &>' requested here
__invokable<_Fp&, _ArgTypes...>::value>
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1626:9: note: in instantiation of default argument for '__callable<std::__1::function<bustache::value ()> >' required here
__callable<_Fp>::value && !is_same<_Fp, function>::value
^~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1628:5: note: in instantiation of default argument for 'function<std::__1::function<bustache::value ()> >' required here
function(_Fp);
^~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1588:28: note: while substituting deduced template arguments into function template 'function' [with _Fp = std::__1::function<bustache::value ()>, $1 = (no value)]
class _LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)>
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1680:9: note: 'operator()' declared here
_Rp operator()(_ArgTypes...) const;
^
/Users/build/bustache-master/include/bustache/model.hpp:56:11: note: definition of 'bustache::value' is not complete until the closing '}'
class value : public variant_base<value>
^
In file included from /Users/build/bustache-master/src/generate.cpp:8:
In file included from /Users/build/bustache-master/include/bustache/generate.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/model.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/format.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/ast.hpp:10:
In file included from /Users/build/bustache-master/include/bustache/detail/variant.hpp:12:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:198:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__tuple:16:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:4323:23: error: calling 'operator()' with incomplete return type 'bustache::value'
_LIBCPP_INVOKE_RETURN(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))
~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__config:441:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_NAMESPACE
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:4220:23: note: expanded from macro '_LIBCPP_INVOKE_RETURN'
noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) \
^~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:4340:9: note: in instantiation of exception specification for '__invoke<std::__1::function<bustache::value (const std::__1::vector<bustache::ast::content, std::__1::allocator<bustache::ast::content> > &)> &, const std::__1::vector<bustache::ast::content, std::__1::allocator<bustache::ast::content> > &>' requested here
_VSTD::__invoke(_VSTD::declval<_Fp>(), _VSTD::declval<_Args>()...));
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/__config:441:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_NAMESPACE
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1601:33: note: in instantiation of template class 'std::__1::__invokable_r<void, std::__1::function<bustache::value (const std::__1::vector<bustache::ast::content, std::__1::allocator<bustache::ast::content> > &)> &, const std::__1::vector<bustache::ast::content, std::__1::allocator<bustache::ast::content> > &>' requested here
__invokable<_Fp&, _ArgTypes...>::value>
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1626:9: note: in instantiation of default argument for '__callable<std::__1::function<bustache::value (const std::__1::vector<bustache::ast::content, std::__1::allocator<bustache::ast::content> > &)> >' required here
__callable<_Fp>::value && !is_same<_Fp, function>::value
^~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1628:5: note: in instantiation of default argument for 'function<std::__1::function<bustache::value (const std::__1::vector<bustache::ast::content, std::__1::allocator<bustache::ast::content> > &)> >' required here
function(_Fp);
^~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1588:28: note: while substituting deduced template arguments into function template 'function' [with _Fp = std::__1::function<bustache::value (const std::__1::vector<bustache::ast::content, std::__1::allocator<bustache::ast::content> > &)>, $1 = (no value)]
class _LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)>
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1680:9: note: 'operator()' declared here
_Rp operator()(_ArgTypes...) const;
^
/Users/build/bustache-master/include/bustache/model.hpp:56:11: note: definition of 'bustache::value' is not complete until the closing '}'
class value : public variant_base<value>
^
2 errors generated.
make[3]: *** [CMakeFiles/bustache.dir/src/generate.cpp.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [CMakeFiles/bustache.dir/all] Error 2
make[1]: *** [CMakeFiles/bustache.dir/rule] Error 2
make: *** [bustache] Error 2`
Hey there,
i stumbled across your lib when i was searching for a performant template engine.
Compiling with GCC12 is just fine. However, it fails with clang 14 on linux.
/home/minski/bustache/src/format.cpp:60: error: call to consteval function 'bustache::parser::(anonymous namespace)::constv<unsigned long>' is not a constant expression
/home/minski/bustache/src/format.cpp:60:45: error: call to consteval function 'bustache::parser::(anonymous namespace)::constv<unsigned long>' is not a constant expression
const auto match = (... & ((ascii ^ constv(broadcast(c))) + mask)) | word;
^
/home/minski/bustache/src/format.cpp:60:62: note: subexpression not valid in a constant expression
const auto match = (... & ((ascii ^ constv(broadcast(c))) + mask)) | word;
^
Next thing to tackle is macOS compatiblity. clang14 from macOS does not support std::ranges
.
Might there be a workaround for this? In other cases, macOS users would be locked out from your lib.
Thanks and best regards
The following example fails to compile if C++17 is active and its std::variant
is included.
This issue is that the visit call inside bustache are resolved to std::visit
instead of bustache::visit
.
$ cat main.cpp
#include <bustache/generate/string.hpp>
#include <unordered_map>
#include <variant>
int main()
{
std::string out;
bustache::generate_string(out, bustache::format{}, bustache::object{}, std::unordered_map<std::string, bustache::format>{}, bustache::normal);
}
$ clang++ main.cpp -lbustache -std=c++17
In file included from main.cpp:1:
In file included from /usr/include/bustache/generate/string.hpp:12:
In file included from /usr/include/bustache/generate.hpp:10:
In file included from /usr/include/bustache/model.hpp:10:
In file included from /usr/include/bustache/format.hpp:10:
In file included from /usr/include/bustache/ast.hpp:12:
In file included from /usr/include/boost/unordered_map.hpp:17:
In file included from /usr/include/boost/unordered/unordered_map.hpp:18:
In file included from /usr/include/boost/functional/hash.hpp:6:
In file included from /usr/include/boost/container_hash/hash.hpp:114:
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/variant:1386:23: error: no member named 'valueless_by_exception' in 'bustache::ast::content'
if ((__variants.valueless_by_exception() || ...))
~~~~~~~~~~ ^
/usr/include/bustache/generate.hpp:567:13: note: in instantiation of function template specialization
'std::visit<bustache::detail::content_visitor<bustache::detail::string_sink<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >,
std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bustache::format, std::hash<std::__cxx11::string>,
std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >, bustache::format> > >, bustache::default_unresolved_handler> &, const bustache::ast::content &>' requested here
visit(visitor, content);
^
/usr/include/bustache/generate/string.hpp:96:9: note: in instantiation of function template specialization 'bustache::generate<bustache::detail::string_sink<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> > >, std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bustache::format,
std::hash<std::__cxx11::string>, std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bustache::format> > >, bustache::default_unresolved_handler>' requested here
generate(sink, fmt, data, context, flag, std::forward<UnresolvedHandler>(f));
^
main.cpp:9:13: note: in instantiation of function template specialization 'bustache::generate_string<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >,
std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bustache::format, std::hash<std::__cxx11::string>,
std::equal_to<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<const std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >, bustache::format> > >, bustache::default_unresolved_handler>' requested here
bustache::generate_string(out, bustache::format("{{foo}}"), bustache::object{}, context, bustache::normal);
^
Sorry to bother you ,I tried to compile on Msys2(Mingw64) , but failed.
Cmake:
-- Building for: Ninja
-- The CXX compiler identification is GNU 13.2.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: E:/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Started CMake for bustache v0.1.0...
-- Configuring done (2.9s)
-- Build files have been written to: E:/msys64/home/test/bustache-master/build
Error:
FAILED: CMakeFiles/bustache.dir/src/render.cpp.obj
E:\msys64\mingw64\bin\c++.exe -IE:/msys64/home/Qrm/test/bustache-master/include -IE:/msys64/home/Qrm/test/bustache-master/src -std=gnu++20 -MD -MT CMakeFiles/bustache.dir/src/render.cpp.obj -MF CMakeFiles\bustache.dir\src\render.cpp.obj.d -o CMakeFiles/bustache.dir/src/render.cpp.obj -c E:/msys64/home/Qrm/test/bustache-master/src/render.cpp
In file included from E:/msys64/home/Qrm/test/bustache-master/include/bustache/render.hpp:10,
from E:/msys64/home/Qrm/test/bustache-master/src/render.cpp:8:
E:/msys64/home/Qrm/test/bustache-master/include/bustache/model.hpp: In instantiation of 'void bustache::detail::print_fmt(const T&, bustache::output_handler, const char*) [with T = std::basic_string_view<char>; bustache::output_handler = bustache::fn_ref<void(const char*, long long unsigned int)>]':
E:/msys64/home/Qrm/test/bustache-master/src/render.cpp:503:30: required from here
E:/msys64/home/Qrm/test/bustache-master/include/bustache/model.hpp:355:16: error: no matching function for call to 'std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char>::basic_format_context(<brace-enclosed initializer list>)'
355 | FmtCtx ctx{OutIter(buf), fmt::make_format_args<FmtCtx>()};
| ^~~
In file included from E:/msys64/home/Qrm/test/bustache-master/include/bustache/model.hpp:20:
E:/msys64/mingw64/include/c++/13.2.0/format:3373:7: note: candidate: 'std::basic_format_context<_Out, _CharT>::basic_format_context(std::basic_format_args<std::basic_format_context<_Out, _CharT> >, _Out, const std::locale&) [with _Out = std::back_insert_iterator<bustache::detail::output_buffer>; _CharT = char]'
3373 | basic_format_context(basic_format_args<basic_format_context> __args,
| ^~~~~~~~~~~~~~~~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3373:7: note: candidate expects 3 arguments, 2 provided
E:/msys64/mingw64/include/c++/13.2.0/format:3368:7: note: candidate: 'std::basic_format_context<_Out, _CharT>::basic_format_context(std::basic_format_args<std::basic_format_context<_Out, _CharT> >, _Out) [with _Out = std::back_insert_iterator<bustache::detail::output_buffer>; _CharT = char]'
3368 | basic_format_context(basic_format_args<basic_format_context> __args,
| ^~~~~~~~~~~~~~~~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3368:68: note: no known conversion for argument 1 from 'OutIter' {aka 'std::back_insert_iterator<bustache::detail::output_buffer>'} to 'std::basic_format_args<std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char> >'
3368 | basic_format_context(basic_format_args<basic_format_context> __args,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3360:11: note: candidate: 'std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char>::basic_format_context(const std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char>&)'
3360 | class basic_format_context
| ^~~~~~~~~~~~~~~~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3360:11: note: candidate expects 1 argument, 2 provided
E:/msys64/home/Qrm/test/bustache-master/include/bustache/model.hpp: In instantiation of 'void bustache::detail::print_fmt(const T&, bustache::output_handler, const char*) [with T = bool; bustache::output_handler = bustache::fn_ref<void(const char*, long long unsigned int)>]':
E:/msys64/home/Qrm/test/bustache-master/src/render.cpp:511:30: required from here
E:/msys64/home/Qrm/test/bustache-master/include/bustache/model.hpp:355:16: error: no matching function for call to 'std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char>::basic_format_context(<brace-enclosed initializer list>)'
355 | FmtCtx ctx{OutIter(buf), fmt::make_format_args<FmtCtx>()};
| ^~~
E:/msys64/mingw64/include/c++/13.2.0/format:3373:7: note: candidate: 'std::basic_format_context<_Out, _CharT>::basic_format_context(std::basic_format_args<std::basic_format_context<_Out, _CharT> >, _Out, const std::locale&) [with _Out = std::back_insert_iterator<bustache::detail::output_buffer>; _CharT = char]'
3373 | basic_format_context(basic_format_args<basic_format_context> __args,
| ^~~~~~~~~~~~~~~~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3373:7: note: candidate expects 3 arguments, 2 provided
E:/msys64/mingw64/include/c++/13.2.0/format:3368:7: note: candidate: 'std::basic_format_context<_Out, _CharT>::basic_format_context(std::basic_format_args<std::basic_format_context<_Out, _CharT> >, _Out) [with _Out = std::back_insert_iterator<bustache::detail::output_buffer>; _CharT = char]'
3368 | basic_format_context(basic_format_args<basic_format_context> __args,
| ^~~~~~~~~~~~~~~~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3368:68: note: no known conversion for argument 1 from 'OutIter' {aka 'std::back_insert_iterator<bustache::detail::output_buffer>'} to 'std::basic_format_args<std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char> >'
3368 | basic_format_context(basic_format_args<basic_format_context> __args,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3360:11: note: candidate: 'std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char>::basic_format_context(const std::basic_format_context<std::back_insert_iterator<bustache::detail::output_buffer>, char>&)'
3360 | class basic_format_context
| ^~~~~~~~~~~~~~~~~~~~
E:/msys64/mingw64/include/c++/13.2.0/format:3360:11: note: candidate expects 1 argument, 2 provided
ninja: build stopped: subcommand failed.
Jamboree, I thought that the following modification would not be difficult but I cannot figure out how to make the Printer object return values, for example:
std::cout << bustache::visit(Printer{}, result->second) << '\n';
I tried to modify the operator so that a value is returned.
#include <iostream>
#include <string>
#include <bustache/model.hpp>
struct Printer
{
int operator()(int val) { return val; }
double operator()(double val) { return val; }
std::string operator()(std::string const& val) { return val; }
template<class T>
void operator()(T const&) { std::cout << "(something else)" << '\n'; }
};
int main()
{
bustache::object bustObj
{
{"1IX99OAVFXOA", 123}
};
// find a key in the Bustache container
auto result = bustObj.find("1IX99OAVFXOA");
if (result != bustObj.end())
{
// display the first value
std::cout << result->first << '\n'; // 1IX99OAVFXOA
// display the second value
// bustache::visit(Printer{}, result->second);
std::cout << bustache::visit(Printer{}, result->second) << '\n';
}
}
Of course, I was unable to figure out how to get values returned.
As per mustache(5), it is suggested that variable misses default to empty value, but also that this behavior be configurable in the library. This is not the case for bustache.
I'm willing to contribute such an improvement if you consider it acceptable. However, I have a few questions:
html_escape
behavior is provided. I think the best way would be to convert option_type
to a proper option struct
with multiple configuration switches. Wha't your policy regarding breaking changes? Is there another way to do that?Thanks.
In file included from .../bustache/include/bustache/generate.hpp:10:0,
from .../bustache/src/generate.cpp:8:
.../bustache/include/bustache/model.hpp:165:23: error: member ‘_vptr’ conflicts with virtual function table field name
vtable const* _vptr;
^~~~~
Compiled fine fine when renamed the _vptr
. However, clang finished well without renaming.
I just found your benchmark program, which is great! I'd like to improve my implementation's performance and am trying to compile your program. I can compile the library but once I try enabling tests I get some errors.
Here are my steps:
mkdir build && cd build
cmake -DCATCH_INCLUDE_DIR=/path/to/Mustache -DBUSTACHE_ENABLE_TESTING=ON ..
cmake --build .
The first error:
/test/specs.cpp:655:46: error: no matching constructor for initialization of 'object' (aka
'unordered_map<basic_string<char, char_traits, allocator >, bustache::value>')
CHECK(to_string("Hello, {{lambda}}!"_fmt(object{{"lambda", [] { return "world"; }}})) == "Hello, world!");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note that I installed Boost via Homebrew, so it's using version 1.63.0. Also since I'm using my project's include directory which includes the latest catch.hpp maybe that's an issue as well.
Also, maybe the benchmark program should verify the rendered value matches an expected value, otherwise it's not clear whether an implementation is even functioning properly.
In my fork I made some changes to improve the CMake package integration:
The package now has an option EXPORT_BUILD_DIR
which exports the build directory to the CMake package registry. This means that find_package()
calls in consuming projects can find the package in its build directory. It is useful when working on both the library and consuming projects at the same time as it obviates the need to run make install
after every change to the library.
bustache depends on Boost in public header files. CMake target dependencies are transitive, so a target linking to "bustache" inherits the Boost dependency; however, CMake package dependencies are not automatically transitive. The "bustache-config.cmake" previously generated by install()
defines an imported target "bustache" and links it to the target "Boost", but it does not call find_package(Boost REQUIRED)
. This forces consumers of bustache to put this find_package(Boost REQUIRED)
call in their own projects before finding bustache, which is obviously undesirable. To avoid this, the package now installs the export (= set of targets) to "bustache-targets.cmake" and generates a separate "bustache-config.cmake" file from the template "bustache-config.cmake.in" which first calls find_dependency(Boost REQUIRED)
and then includes "bustache-targets.cmake". This is the recommended approach for handling transitive package dependencies.
The package no also generates and installs a "bustache-config-version.cmake" file which enforces semantic versioning (SameMajorVersion
) during package lookup. This has the advantage that it allows installed packages and exported build directories to coexist. Example:
EXPORT_BUILD_DIR
set to ON
. However, because find_package()
looks for installed packages first, the exported build directory is not found by consuming projects.find_package(bustache 4.3 REQUIRED)
. Because of the versioning logic in "bustache-config-version.cmake", CMake will skip the installed version of bustache and find the exported build directory.Would you be interested in merging these changes into your repository?
I understand you are targetting v1.1.3 of the mustache spec. However, template inheritance is turning into a defacto standard. It is supported by numerous mustache implementations, javascript, Java and others. For instance, it is supported by 3 of the 4 most popular Java implementations. Its support in javascript implementations mean that it can be used client and server side.
Consider Trimou as a documentation example
http://trimou.org/
^^^^^^^^^^^^
Template inheritance
This useful feature is not supported in the spec. Trimou basically follows the way mustache.java implements the template inheritance.
In the extended template (parent), the sections to extend are defined - use $ to identify such sections.
A section identified with < includes the extended template
In the extending template (child), the extending sections are defined - again, use $ to identify such sections. Sections to extend may define the default content.
The following template with name "super":
{{$header}}
The default header
{{/header}}
In between...
{{$content}}
The default content
{{/content}}
Can be extended in this way:
Hello world!
{{<super}}
{{$header}}
My own header
{{/header}}
Only extending sections are considered...
{{/super}}
Lalala...
And the result is:
Hello world!
My own header
In between...
The default content
Lalala...
I am a Mustache for Javascript user and downloaded Bustache (C++20). I wanted to use the variant data type for Json values and had trouble.
After looking at issues, I noticed messages for Bustache (C++11) so I downloaded and easily used variant for Json values.
Ok, interface for C++11's bustache::object and bustache::array seem much easier to use than the example given for C++20.
My next step was to give Bustache C++20 another shot and included "../test/model.hpp", replaced namespace to test::object and test::array. I was so happy to see everything compile but then when I went to build, I got a cryptic "error LNK2005" about something already being defined.
My guess is that the test/model.hpp has not been finalized and that struct value; is currently a global causing the link error.
I don't have C++ knowledge to work around this linker error, does anyone have a revision available to test/model.hpp so that I can use variant value type?
Hello and thank you for such a nice library. Is there some way to include (or embed) one template into another template? For example:
{{header}}
{{EMBEDDED_TEMPLATE}}
{{footer}}
data.emplace("header", "Hello World!");
data.emplace("EMBEDDED_TEMPLATE", "{{header}} - {{footer}}");
data.emplace("footer", "Goodbye World!");
Hello World!
{{EMBEDDED_TEMPLATE}}
Goodbye World!
Hello World!
Hello World! - Goodbye World!
Goodbye World!
Is it safe to assume that Bustache objects are returned via RVO just like other STD container are?
bustache::array getData()
{
bustache::array array;
...
return array;
}
Thank you in advance!
I have no problem building Bustache on GCC 13 or CLANG 17. Previously, I have built and used older versions of Bustache with GCC 7.4.
I do not believe that GCC 7.4 has support for C++20 and that this may be why I can't get it to compile. I did build the FMT library to see if that would help but CMake complained about lack of C++20 support.
I am hoping to get this working on Ubuntu 18.04 but I don't want to waste more time unless it is possible to get the latest version working without C++20 support. Thank you.
It is confusing to see that object
and array
are present in examples.
I am using Bustache heavily in a multi-threaded application using the adapter for Nlohmann Json found here: [https://github.com/jamboree/bustache/blob/master/example/nlohmann.cpp]
Bustache works perfectly well with this adapter, except that I cannot get partials to work with it.
Here is a minimalist example:
void test() {
std::unordered_map<std::string, bustache::format> context
{
{"EMBEDDED_TEMPLATE", ", goodbye {{goodbyeTag}}"_fmt}
};
nlohmann::json data;
data["helloTag"] = "Bustache";
data["goodbyeTag"] = "Mustache";
bustache::format format("Hello {{helloTag}}{{>EMBEDDED_TEMPLATE}} templating system.\n");
// Prints: Hello Bustache templating system.
std::cout << format(data) << "\n";
// Should print: Hello Bustache, goodbye Mustache templating system.
auto str = format(data).context(context);
std::cout << str << '\n'; // 'render_ostream': no matching overloaded function
}
Bustache works so nicely with Nlohmann, and my hope is that the Jamboree or some other knowledgeable person can adjust the code for partials for this adapter. Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.