Skip to content

Commit 83cba28

Browse files
authored
'extends' statement basic support
* Implement basic filesystem handlers * Fix build * Fix build (2) * Fix travis build * Base implementation of 'extends' functionality * Fix build * Fix build
1 parent 84af922 commit 83cba28

25 files changed

+961
-57
lines changed

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ matrix:
4444
apt:
4545
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
4646
packages: ['cmake', 'clang-6.0', 'g++-6']
47-
47+
4848
before_install:
4949
- date -u
5050
- uname -a
5151
- sudo add-apt-repository -y ppa:samuel-bachmann/boost
5252
- sudo apt-get update -qq
53-
53+
5454
install:
55-
- sudo apt-get install libboost1.60-dev
55+
- sudo apt-get install libboost1.60-all-dev
5656

5757
script:
5858
- if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi

CMakeLists.txt

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@ if (NOT DEFINED WITH_TESTS)
1717
endif ()
1818

1919
set (EXTRA_TEST_LIBS "")
20+
set (CMAKE_CXX_STANDARD 14)
21+
set (CMAKE_CXX_STANDARD_REQUIRED ON)
2022
if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang" OR ${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
21-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
22-
2323
if (NOT UNIX)
2424
set (EXTRA_TEST_LIBS "stdc++")
2525
else ()
2626
include(CMakeFindDependencyMacro)
2727
find_dependency(Threads)
28-
set (EXTRA_TEST_LIBS "Threads::Threads")
28+
set (EXTRA_TEST_LIBS Threads::Threads)
2929
endif ()
3030
else ()
3131
# MSVC
32+
if (NOT DEFINED Boost_USE_STATIC_LIBS)
33+
set (Boost_USE_STATIC_LIBS ON)
34+
endif ()
3235
if (NOT DEFINED MSVC_RUNTIME_TYPE)
3336
set (MSVC_RUNTIME_TYPE "/MD")
3437
endif ()
@@ -82,7 +85,11 @@ if(NOT "${GTEST_ROOT}" STREQUAL "" AND WITH_TESTS)
8285
endif ()
8386
endif()
8487

85-
find_package(Boost)
88+
if (WITH_TESTS)
89+
find_package(Boost COMPONENTS system filesystem REQUIRED)
90+
else ()
91+
find_package(Boost)
92+
endif ()
8693

8794
include(collect_sources)
8895

@@ -101,15 +108,26 @@ add_library(${LIB_TARGET_NAME} STATIC
101108
${Sources}
102109
${Headers}
103110
${PublicHeaders}
104-
)
111+
)
105112

106113
target_include_directories(${LIB_TARGET_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
107114

108115
if (WITH_TESTS)
109116
enable_testing()
110117
CollectSources(TestSources TestHeaders ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/test)
111118
add_executable(jinja2cpp_tests ${TestSources} ${TestHeaders})
112-
target_link_libraries(jinja2cpp_tests ${GTEST_BOTH_LIBRARIES} ${LIB_TARGET_NAME} ${EXTRA_TEST_LIBS})
119+
target_link_libraries(jinja2cpp_tests ${GTEST_BOTH_LIBRARIES} ${LIB_TARGET_NAME} ${EXTRA_TEST_LIBS} Boost::system Boost::filesystem)
120+
121+
add_custom_command(
122+
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_data/simple_template1.j2tpl
123+
COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/test/test_data ${CMAKE_CURRENT_BINARY_DIR}/test_data
124+
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/test/test_data/simple_template1.j2tpl
125+
COMMENT "Copy test data to the destination dir"
126+
)
127+
128+
add_custom_target(CopyTestData ALL
129+
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/test_data/simple_template1.j2tpl
130+
)
113131
endif ()
114132

115133
install(TARGETS ${LIB_TARGET_NAME}

include/jinja2cpp/error_handler.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#ifndef JINJA2CPP_DIAGNOSTIC_CONSUMER_H
2-
#define JINJA2CPP_DIAGNOSTIC_CONSUMER_H
1+
#ifndef JINJA2CPP_ERROR_HANDLER_H
2+
#define JINJA2CPP_ERROR_HANDLER_H
33

44
#include "template.h"
55

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#ifndef JINJA2CPP_FILESYSTEM_HANDLER_H
2+
#define JINJA2CPP_FILESYSTEM_HANDLER_H
3+
4+
#include <boost/variant.hpp>
5+
6+
#include <iostream>
7+
#include <memory>
8+
#include <string>
9+
#include <unordered_map>
10+
11+
namespace jinja2
12+
{
13+
14+
template<typename CharT>
15+
using FileStreamPtr = std::unique_ptr<std::basic_istream<CharT>, void (*)(std::basic_istream<CharT>*)>;
16+
using CharFileStreamPtr = FileStreamPtr<char>;
17+
using WCharFileStreamPtr = FileStreamPtr<wchar_t>;
18+
19+
class IFilesystemHandler
20+
{
21+
public:
22+
virtual ~IFilesystemHandler() = default;
23+
24+
virtual CharFileStreamPtr OpenStream(const std::string& name) const = 0;
25+
virtual WCharFileStreamPtr OpenWStream(const std::string& name) const = 0;
26+
};
27+
28+
using FilesystemHandlerPtr = std::shared_ptr<IFilesystemHandler>;
29+
30+
class MemoryFileSystem : public IFilesystemHandler
31+
{
32+
public:
33+
void AddFile(std::string fileName, std::string fileContent);
34+
void AddFile(std::string fileName, std::wstring fileContent);
35+
36+
CharFileStreamPtr OpenStream(const std::string& name) const override;
37+
WCharFileStreamPtr OpenWStream(const std::string& name) const override;
38+
39+
private:
40+
using FileContent = boost::variant<std::string, std::wstring>;
41+
std::unordered_map<std::string, FileContent> m_filesMap;
42+
};
43+
44+
class RealFileSystem : public IFilesystemHandler
45+
{
46+
public:
47+
RealFileSystem(std::string rootFolder = ".");
48+
49+
void SetRootFolder(std::string newRoot)
50+
{
51+
m_rootFolder = newRoot;
52+
}
53+
54+
CharFileStreamPtr OpenStream(const std::string& name) const override;
55+
WCharFileStreamPtr OpenWStream(const std::string& name) const override;
56+
57+
private:
58+
std::string m_rootFolder;
59+
};
60+
} // jinja2
61+
62+
#endif // FILESYSTEM_HANDLER_H

include/jinja2cpp/template.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
namespace jinja2
1111
{
1212
class ITemplateImpl;
13+
class TemplateEnv;
14+
template<typename CharT> class TemplateImpl;
1315

1416
class Template
1517
{
1618
public:
17-
Template();
19+
Template(TemplateEnv* env = nullptr);
1820
~Template();
1921

2022
bool Load(const char* tpl);
@@ -27,13 +29,14 @@ class Template
2729

2830
private:
2931
std::shared_ptr<ITemplateImpl> m_impl;
32+
friend class TemplateImpl<char>;
3033
};
3134

3235

3336
class TemplateW
3437
{
3538
public:
36-
TemplateW();
39+
TemplateW(TemplateEnv* env = nullptr);
3740
~TemplateW();
3841

3942
bool Load(const wchar_t* tpl);
@@ -46,6 +49,7 @@ class TemplateW
4649

4750
private:
4851
std::shared_ptr<ITemplateImpl> m_impl;
52+
friend class TemplateImpl<wchar_t>;
4953
};
5054
} // jinja2
5155

include/jinja2cpp/template_env.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef JINJA2CPP_TEMPLATE_ENV_H
2+
#define JINJA2CPP_TEMPLATE_ENV_H
3+
4+
#include "template.h"
5+
#include "filesystem_handler.h"
6+
7+
#include <unordered_map>
8+
9+
namespace jinja2
10+
{
11+
12+
class IErrorHandler;
13+
class IFilesystemHandler;
14+
15+
class TemplateEnv
16+
{
17+
public:
18+
void SetErrorHandler(IErrorHandler* h)
19+
{
20+
m_errorHandler = h;
21+
}
22+
auto GetErrorHandler() const
23+
{
24+
return m_errorHandler;
25+
}
26+
void AddFilesystemHandler(std::string prefix, FilesystemHandlerPtr h)
27+
{
28+
m_filesystemHandlers.push_back(FsHandler{std::move(prefix), h});
29+
}
30+
Template LoadTemplate(std::string fileName);
31+
TemplateW LoadTemplateW(std::string fileName);
32+
33+
private:
34+
IErrorHandler* m_errorHandler;
35+
struct FsHandler
36+
{
37+
std::string prefix;
38+
FilesystemHandlerPtr handler;
39+
};
40+
std::vector<FsHandler> m_filesystemHandlers;
41+
};
42+
43+
} // jinja2
44+
45+
#endif // JINJA2CPP_TEMPLATE_ENV_H

include/jinja2cpp/template_env.h.h

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/filesystem_handler.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#include <jinja2cpp/filesystem_handler.h>
2+
3+
#include <boost/filesystem/path.hpp>
4+
5+
#include <sstream>
6+
#include <fstream>
7+
8+
namespace jinja2
9+
{
10+
11+
using TargetFileStream = boost::variant<CharFileStreamPtr*, WCharFileStreamPtr*>;
12+
13+
struct FileContentConverter : public boost::static_visitor<void>
14+
{
15+
void operator() (const std::string& content, CharFileStreamPtr* sPtr) const
16+
{
17+
sPtr->reset(new std::istringstream(content));
18+
}
19+
20+
void operator() (const std::wstring& content, WCharFileStreamPtr* sPtr) const
21+
{
22+
sPtr->reset(new std::wistringstream(content));
23+
}
24+
void operator() (const std::wstring& content, CharFileStreamPtr* sPtr) const
25+
{
26+
// CharFileStreamPtr stream(new std::istringstream(content), [](std::istream* s) {delete static_cast<std::istringstream>(s);});
27+
// std::swap(*sPtr, stream);
28+
}
29+
30+
void operator() (const std::string& content, WCharFileStreamPtr* sPtr) const
31+
{
32+
// WCharFileStreamPtr stream(new std::wistringstream(content), [](std::wistream* s) {delete static_cast<std::wistringstream>(s);});
33+
// std::swap(*sPtr, stream);
34+
}
35+
};
36+
37+
void MemoryFileSystem::AddFile(std::string fileName, std::string fileContent)
38+
{
39+
m_filesMap[std::move(fileName)] = FileContent(std::move(fileContent));
40+
}
41+
42+
void MemoryFileSystem::AddFile(std::string fileName, std::wstring fileContent)
43+
{
44+
m_filesMap[std::move(fileName)] = FileContent(std::move(fileContent));
45+
}
46+
47+
CharFileStreamPtr MemoryFileSystem::OpenStream(const std::string& name) const
48+
{
49+
CharFileStreamPtr result(nullptr, [](std::istream* s) {delete static_cast<std::istringstream*>(s);});
50+
auto p = m_filesMap.find(name);
51+
if (p == m_filesMap.end())
52+
return result;
53+
54+
TargetFileStream targetStream(&result);
55+
boost::apply_visitor(FileContentConverter(), p->second, targetStream);
56+
57+
return result;
58+
}
59+
60+
WCharFileStreamPtr MemoryFileSystem::OpenWStream(const std::string& name) const
61+
{
62+
WCharFileStreamPtr result(nullptr, [](std::wistream* s) {delete static_cast<std::wistringstream*>(s);});
63+
auto p = m_filesMap.find(name);
64+
if (p == m_filesMap.end())
65+
return result;
66+
67+
TargetFileStream targetStream(&result);
68+
boost::apply_visitor(FileContentConverter(), p->second, targetStream);
69+
70+
return result;
71+
}
72+
73+
RealFileSystem::RealFileSystem(std::string rootFolder)
74+
: m_rootFolder(rootFolder)
75+
{
76+
77+
}
78+
79+
CharFileStreamPtr RealFileSystem::OpenStream(const std::string& name) const
80+
{
81+
boost::filesystem::path root(m_rootFolder);
82+
root /= name;
83+
const auto& filePath = root.native();
84+
85+
CharFileStreamPtr result(new std::ifstream(filePath), [](std::istream* s) {delete static_cast<std::ifstream*>(s);});
86+
if (result->good())
87+
return result;
88+
89+
return CharFileStreamPtr(nullptr, [](std::istream* s){});
90+
}
91+
92+
WCharFileStreamPtr RealFileSystem::OpenWStream(const std::string& name) const
93+
{
94+
boost::filesystem::path root(m_rootFolder);
95+
root /= name;
96+
const auto& filePath = root.native();
97+
98+
WCharFileStreamPtr result(new std::wifstream(filePath), [](std::wistream* s) {delete static_cast<std::wifstream*>(s);});
99+
if (result->good())
100+
return result;
101+
102+
return WCharFileStreamPtr(nullptr, [](std::wistream* s){;});
103+
}
104+
105+
} // jinja2

0 commit comments

Comments
 (0)