Skip to content

Add support for partials #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.53 COMPONENTS unit_test_framework system filesystem)

add_definitions( -DBOOST_SPIRIT_USE_PHOENIX_V3=1 )
add_definitions( -DBOOST_SPIRIT_USE_PHOENIX_V3=1 -DBOOST_TEST_ALTERNATIVE_INIT_API )
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
add_definitions( -std=c++0x -ftemplate-depth=512 -Wno-unused-local-typedefs -Wno-deprecated-declarations )
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
Expand Down
2 changes: 1 addition & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ foreach( EXAMPLE example1 example2 example3 )
add_executable( ${EXAMPLE} ${EXAMPLE}.cpp )
endforeach()


configure_file(${CMAKE_CURRENT_SOURCE_DIR}/footer.mst ${CMAKE_CURRENT_BINARY_DIR}/footer.mst COPYONLY)
3 changes: 2 additions & 1 deletion examples/example1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define BOOST_SPIRIT_NO_PREDEFINED_TERMINALS

#include <boost/boostache/boostache.hpp>
#include <boost/boostache/frontend/file_mapper.hpp>
#include <boost/boostache/frontend/stache/grammar_def.hpp> // need to work out header only syntax
#include <boost/boostache/stache.hpp>
#include <boost/boostache/model/helper.hpp>
Expand Down Expand Up @@ -45,7 +46,7 @@ int main()
using boostache::load_template;

auto iter = input.begin();
auto templ = load_template<boostache::format::stache>(iter, input.end());
auto templ = load_template<boostache::format::stache>(iter, input.end(), boostache::frontend::file_mapper<char>());
// ------------------------------------------------------------------

// ------------------------------------------------------------------
Expand Down
11 changes: 6 additions & 5 deletions examples/example2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <boost/boostache/boostache.hpp>
#include <boost/boostache/frontend/stache/grammar_def.hpp> // need to work out header only syntax
#include <boost/boostache/stache.hpp>
#include <boost/boostache/frontend/file_mapper.hpp>
#include <boost/boostache/model/helper.hpp>
#include <iostream>
#include <sstream>
Expand All @@ -24,7 +25,7 @@ namespace boostache = boost::boostache;
// -------------------------------------------------------
// The data will be an invoice this time. The invoice
// consists of a list of line items. Each line item
// can be describes as map of string to strings.
// can be described as map of string to strings.
//
using item_t = std::map<std::string, std::string>;
using item_list_t = std::vector<item_t>;
Expand All @@ -36,7 +37,7 @@ int main()
{
// ------------------------------------------------------------------
// The template describing an invoice.
std::string input(
std::string input(
"Invoice"
"\n"
"{{#lines}}"
Expand All @@ -49,13 +50,13 @@ int main()
// ------------------------------------------------------------------
// The data description. invoice_items is a list of maps that
// describe each item.
item_list_t invoice_items = {
item_list_t invoice_items = {
{ {"item_code" , "1234"},
{"description" , "teddy bear"},
{"amount" , "$23"} },
{ {"item_code" , "1235"},
{"description" , "computer"},
{"amount" , "$9"} }
{"amount" , "$9"} }
};

// we need to put the list into a map so that tag 'lines' can
Expand All @@ -70,7 +71,7 @@ int main()
using boostache::load_template;

auto iter = input.begin();
auto templ = load_template<boostache::format::stache>(iter, input.end());
auto templ = load_template<boostache::format::stache>(iter, input.end(), boostache::frontend::file_mapper<char>());
// ------------------------------------------------------------------

// ------------------------------------------------------------------
Expand Down
25 changes: 19 additions & 6 deletions examples/example3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <boost/boostache/boostache.hpp>
#include <boost/boostache/frontend/stache/grammar_def.hpp> // need to work out header only syntax
#include <boost/boostache/stache.hpp>
#include <boost/boostache/frontend/file_mapper.hpp>
#include <boost/boostache/model/helper.hpp>
#include <boost/spirit/include/support_extended_variant.hpp>
#include <string>
Expand All @@ -36,6 +37,8 @@ namespace boostache = boost::boostache;
// This is fairly simple to do with a variant. We are going
// to use the spirit version of it because it makes
// recursive structures easier to describe.
// We also add a partial at the end. Note that the partial
// itself can contain more boostache (see footer.mst).
//

struct value_t;
Expand All @@ -60,8 +63,8 @@ int main()
{
// ------------------------------------------------------------------
// The template describing an invoice.
std::string input(
"Invoice {{invoice_number}}"
std::string input(
"Invoice {{invoice_number}}\n"
"\n"
"{{# company}}"
"Company: {{name}}\n"
Expand All @@ -71,15 +74,16 @@ int main()
"------------------------------------------------\n"
"{{#lines}}"
" {{item_code}} {{description}} {{amount}}\n"
"{{/lines}}"
"{{/lines}}\n"
"- {{>footer}} -"
);
// ------------------------------------------------------------------


// ------------------------------------------------------------------
// The data description.

object_t invoice =
object_t invoice =
{{"invoice_number", "1234"},
{"company" , object_t{{"name" , "FizSoft"},
{"street" , "42 Level St."},
Expand All @@ -93,17 +97,26 @@ int main()
{"description" , "Computer"},
{"amount" , "$9"}} }}
};

// ------------------------------------------------------------------

// ------------------------------------------------------------------
// Load the template
// This parses the input and compiles the result. The return is the
// compiled data structure
using boostache::load_template;
using boostache::frontend::file_mapper;

//The file mapper coming with boostache will try to read from a file
//called <work_dir>/<partial_name>.<ext>
//By default work_dir is the empty string (current directory), and ext
//is ".mustache". In this example we change it to ".mst".
//You can customize how partials are resolved by providing your own
//mapper.
boostache::frontend::file_mapper<char> fmapper(".mst");

auto iter = input.begin();
auto templ = load_template<boostache::format::stache>(iter, input.end());
auto templ = load_template<boostache::format::stache>(iter, input.end(), fmapper);
// ------------------------------------------------------------------

// ------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions examples/footer.mst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
End of invoice {{invoice_number}}
17 changes: 11 additions & 6 deletions include/boost/boostache/backend/detail/stache_compiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* \file detail/stache_compiler.hpp
*
* Copyright 2014, 2015 Michael Caisse : ciere.com
* Copyright 2015 Michele Santullo
*
* 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)
Expand All @@ -28,7 +29,7 @@ namespace boost { namespace boostache { namespace backend { namespace stache_com
return( s.find_first_not_of(std::string{" \t\r\n"})
== std::string::npos );
}

class stache_visit
{
public:
Expand Down Expand Up @@ -103,13 +104,17 @@ namespace boost { namespace boostache { namespace backend { namespace stache_com
vm::ast::node operator()(fe::stache::ast::comment const & v) const
{
return vm::ast::nop{};
}
}

vm::ast::node operator()(fe::stache::ast::partial const & v) const
vm::ast::node operator()(fe::stache::ast::partial const & p) const
{
// TODO: need to implement partials
return vm::ast::nop{};
}
vm::ast::node_list node_list;
for (auto const & node : p.nodes)
{
node_list.nodes.push_back(boost::apply_visitor(*this, node));
}
return node_list;
}

vm::ast::node operator()(fe::stache::ast::node_list const & nodes) const
{
Expand Down
13 changes: 7 additions & 6 deletions include/boost/boostache/boostache.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@
#include <boost/boostache/backend/stache_compiler.hpp>
#include <boost/boostache/vm/generate.hpp>
#include <istream>
#include <utility>


namespace boost { namespace boostache
{
template <typename Format, typename Iterator>
inline vm::ast::node load_template(Iterator & begin, Iterator const & end)
template <typename Format, typename Iterator, typename PartialFunctor>
inline vm::ast::node load_template(Iterator & begin, Iterator const & end, PartialFunctor mapper_type)
{
return backend::compile(frontend::parse<Format>(begin,end));
return backend::compile(frontend::parse<Format>(begin,end, std::move(mapper_type)));
}

template <typename Format>
inline vm::ast::node load_template(std::istream & input)
template <typename Format, typename PartialFunctor>
inline vm::ast::node load_template(std::istream & input, PartialFunctor mapper_type)
{
return backend::compile(frontend::parse<Format>(input));
return backend::compile(frontend::parse<Format>(input, std::move(mapper_type)));
}

template <typename Stream, typename Context>
Expand Down
67 changes: 67 additions & 0 deletions include/boost/boostache/frontend/file_mapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* \file file_mapper.hpp
*
* Copyright 2015 Michele Santullo
*
* Utility class that maps a partial name to a file on the filesystem.
*
* 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)
*/

#ifndef BOOST_BOOSTACHE_FILE_MAPPER_HPP
#define BOOST_BOOSTACHE_FILE_MAPPER_HPP

#include <string>
#include <utility>
#include <fstream>

namespace boost { namespace boostache { namespace frontend
{
template <typename CharType>
class file_mapper
{
public:
using string_type = std::basic_string<CharType>;

file_mapper (file_mapper&&) = default;
file_mapper (const file_mapper&) = default;
explicit file_mapper (string_type&& ext=".mustache", string_type&& base_path="") :
extension(std::move(ext)),
base_path(std::move(base_path))
{
}

void set_extension (string_type&& ext)
{
extension = std::move(ext);
}
void set_base_path (string_type&& bpath)
{
base_path = std::move(bpath);
if (!base_path.empty() && base_path.back() != static_cast<CharType>('/') && base_path.back() != static_cast<CharType>('\\'))
base_path += '/';
}

string_type operator() (const string_type& tag) const
{
//TODO: don't open the file every time, add some sort of buffering instead
string_type path(base_path + tag + extension);
std::basic_ifstream<CharType> ifs(path);
ifs.seekg(0, std::ios_base::end);
const auto ssize = ifs.tellg();
ifs.seekg(0, std::ios_base::beg);

string_type retval;
retval.resize(ssize, ' ');
ifs.read(&*retval.begin(), ssize);
ifs.close();
return retval;
}

private:
string_type extension;
string_type base_path;
};
}}}
#endif
16 changes: 9 additions & 7 deletions include/boost/boostache/frontend/parse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <iostream>
#include <utility>

namespace boost { namespace boostache { namespace frontend
{
template <typename Format, typename Iterator>
typename Format::ast_t parse(Iterator & begin, Iterator const & end)
template <typename Format, typename Iterator, typename PartialFunctor>
typename Format::ast_t parse(Iterator & begin, Iterator const & end, PartialFunctor mapper_type)
{
typename Format::ast_t ast;
typename Format::template grammar_t<Iterator> grammar;
typename Format::template grammar_t<Iterator, PartialFunctor> grammar(std::move(mapper_type));

// TODO mjc : should throw with parse error location
if(!boost::spirit::qi::phrase_parse( begin, end
, grammar
Expand All @@ -38,14 +39,15 @@ namespace boost { namespace boostache { namespace frontend
}


template <typename Format>
typename Format::ast_t parse(std::istream& input)
template <typename Format, typename PartialFunctor>
typename Format::ast_t parse(std::istream& input, PartialFunctor mapper_type)
{
// TODO mjc : store/restore ios state?
input.unsetf(std::ios::skipws);
boost::spirit::istream_iterator iter{input};
return parse<Format>( iter
, boost::spirit::istream_iterator{} );
, boost::spirit::istream_iterator{}
, std::move(mapper_type) );
}
}}}

Expand Down
13 changes: 9 additions & 4 deletions include/boost/boostache/frontend/stache/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* Copyright 2014 Michael Caisse : ciere.com
* Copyright 2014 Jeroen Habraken
* Copyright 2015 Michele Santullo
*
* 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)
Expand Down Expand Up @@ -34,9 +35,7 @@ namespace boost { namespace boostache { namespace frontend { namespace stache {
identifier value;
};

struct partial : identifier
{};

struct partial;
struct section;

struct node : boost::spirit::extended_variant<
Expand All @@ -45,7 +44,7 @@ namespace boost { namespace boostache { namespace frontend { namespace stache {
, literal_text
, variable
, boost::recursive_wrapper<section>
, partial
, boost::recursive_wrapper<partial>
>
{
node() : base_type() {}
Expand All @@ -65,6 +64,12 @@ namespace boost { namespace boostache { namespace frontend { namespace stache {
node_list nodes;
};

struct partial
{
identifier name;
node_list nodes;
};

struct root : node_list {};

}}}}}
Expand Down
Loading