diff --git a/.travis.yml b/.travis.yml index fa85df5..cbfe279 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,33 @@ +sudo: false language: cpp -script: autoreconf -i && ./configure && make check && ./test-program +compiler: + - gcc + - clang +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.9 + - g++-4.9 + - clang +before_install: + - if [ "$CXX" = "g++" ]; then + export CXX="g++-4.9" CC="gcc-4.9"; + export CXXFLAGS="-std=c++11"; + elif [ "$CXX" = "clang++" ]; then + export CXXFLAGS="-std=c++11 -stdlib=libc++ -DGTEST_USE_OWN_TR1_TUPLE=1"; + fi +install: + - if [ "$CXX" == "clang++" ]; then + svn co --quiet http://llvm.org/svn/llvm-project/libcxx/trunk libcxx; + cd libcxx/lib && bash buildit; + ln -sf libc++.so.1.0 libc++.so.1; + cd "$TRAVIS_BUILD_DIR"; + export CXXFLAGS="$CXXFLAGS -L`pwd`/libcxx/lib -I`pwd`/libcxx/include"; + export LD_LIBRARY_PATH="`pwd`/libcxx/lib:$LD_LIBRARY_PATH"; + fi before_script: - - sudo apt-get install libgtest-dev libboost-regex-dev build-essential - ./utils/build_gtest.sh - + - autoreconf -i && ./configure && make check +script: ./test-program diff --git a/Makefile.am b/Makefile.am index 27615a1..37c2132 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -LDFLAGS=-lboost_regex-mt pkginclude_HEADERS = include/plustache/template.hpp include/plustache/context.hpp include/plustache/plustache_types.hpp check_PROGRAMS = test-program test_program_CPPFLAGS=-Ivendor/gtest-1.6.0/include -I$(top_srcdir)/include -test_program_LDFLAGS=-Lvendor/gtest-1.6.0/lib/.libs -lgtest -lboost_regex-mt +test_program_LDFLAGS=-Lvendor/gtest-1.6.0/lib/.libs -lgtest test_program_SOURCES = tests/test_change_delimiter.cpp tests/test_collections_plustache.cpp tests/test_html_escape_plustache.cpp tests/test_inverted_sections.cpp tests/test_multiple_plustache.cpp tests/test_nested_sections_plustache.cpp tests/test_partials_plustache.cpp tests/test_sections_plustache.cpp tests/test_simple_plustache.cpp tests/tests.cpp test_program_LDADD = .libs/libplustache.a diff --git a/README.md b/README.md index 87aef66..3f9573f 100644 --- a/README.md +++ b/README.md @@ -152,5 +152,5 @@ If you get the tr1/tuple error, do: * plustache executable ## Dependencies -* boost for regex and some other things +* compiler support for C++11's regex implementation (Clang or GCC 4.9+) * google test for unit testing (included) diff --git a/configure.ac b/configure.ac index af39180..38c76b8 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,6 @@ AC_PROG_CC AC_PROG_INSTALL # Checks for libraries. -AC_CHECK_LIB([boost_regex], [main]) AC_CHECK_LIB([gtest], [main]) # Checks for header files. diff --git a/include/plustache/template.hpp b/include/plustache/template.hpp index 81ba3ed..f3667c5 100644 --- a/include/plustache/template.hpp +++ b/include/plustache/template.hpp @@ -8,8 +8,7 @@ #include #include #include -#include -#include +#include #include #include @@ -31,9 +30,9 @@ namespace Plustache { std::string otag; std::string ctag; /* regex */ - boost::regex tag; - boost::regex section; - boost::regex escape_chars; + std::regex tag; + std::regex section; + std::regex escape_chars; /* lut for HTML escape chars */ std::map escape_lut; /* render and helper methods */ @@ -47,6 +46,7 @@ namespace Plustache { const std::string& closetag); void compile_data(); std::string get_template(const std::string& tmpl); + void update_tags(); }; } // namespace Plustache #endif diff --git a/platforms/xcode/.gitignore b/platforms/xcode/.gitignore new file mode 100644 index 0000000..81bf6c8 --- /dev/null +++ b/platforms/xcode/.gitignore @@ -0,0 +1,18 @@ +# Created by https://www.gitignore.io + +### Xcode ### +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.xcuserstate + diff --git a/platforms/xcode/GoogleTests.mm b/platforms/xcode/GoogleTests.mm new file mode 100755 index 0000000..9b252ed --- /dev/null +++ b/platforms/xcode/GoogleTests.mm @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2013 Matthew Stevens + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// Downloaded from https://github.com/mattstevens/xcode-googletest on 21 Apr 2015 - kah + +#import +#import +#import + +using testing::TestCase; +using testing::TestInfo; +using testing::TestPartResult; +using testing::UnitTest; + +static NSString * const GoogleTestDisabledPrefix = @"DISABLED_"; + +/** + * A Google Test listener that reports failures to XCTest. + */ +class XCTestListener : public testing::EmptyTestEventListener { +public: + XCTestListener(XCTestCase *testCase) : + _testCase(testCase) {} + + void OnTestPartResult(const TestPartResult& test_part_result) { + if (test_part_result.passed()) + return; + + int lineNumber = test_part_result.line_number(); + const char *fileName = test_part_result.file_name(); + NSString *path = fileName ? [@(fileName) stringByStandardizingPath] : nil; + NSString *description = @(test_part_result.message()); + [_testCase recordFailureWithDescription:description + inFile:path + atLine:(lineNumber >= 0 ? (NSUInteger)lineNumber : 0) + expected:YES]; + } + +private: + XCTestCase *_testCase; +}; + +/** + * Test suite used to run Google Test cases. + * + * This test suite skips its own run and instead runs each of its sub-tests. This results + * in the Google Test cases being reported at the same level as other XCTest cases. + * + * Additionally, if a test case has been completely filtered out it is not run at all. + * This eliminates noise from the test report when running only a subset of tests. + */ +@interface GoogleTestSuite : XCTestSuite +@end + +@implementation GoogleTestSuite + +- (void)performTest:(XCTestSuiteRun *)testRun { + for (XCTest *test in self.tests) { + if (test.testCaseCount > 0) { + [testRun addTestRun:[test run]]; + } + } +} + +@end + +/** + * A test case that executes Google Test, reporting test results to XCTest. + * + * XCTest loads tests by looking for all classes derived from XCTestCase and calling + * +defaultTestSuite on each of them. Normally this method returns an XCTestSuite + * containing an XCTestCase for each method of the receiver whose name begins with "test". + * Instead this class returns a custom test suite that runs an XCTestSuite for each Google + * Test case. + */ +@interface GoogleTests : XCTestCase +@end + +@implementation GoogleTests { + NSString *_name; + NSString *_className; + NSString *_methodName; + NSString *_googleTestFilter; +} + +- (id)initWithClassName:(NSString *)className methodName:(NSString *)methodName testFilter:(NSString *)filter { + self = [super initWithSelector:@selector(runTest)]; + if (self) { + _className = [className copy]; + _methodName = [methodName copy]; + _name = [NSString stringWithFormat:@"-[%@ %@]", _className, _methodName]; + _googleTestFilter = [filter copy]; + } + return self; +} + +- (NSString *)name { + return _name; +} + +/** + * Returns the test name logged to the console for this test. + */ +- (NSString *)nameForLegacyLogging { + return _name; +} + +/** + * Returns the class name reported to Xcode for this test. + */ +- (NSString *)testClassName { + return _className; +} + +/** + * Returns the method name reported to Xcode for this test. + */ +- (NSString *)testMethodName { + return _methodName; +} + ++ (id)defaultTestSuite { + // Pass the command-line arguments to Google Test to support the --gtest options + NSArray *arguments = [[NSProcessInfo processInfo] arguments]; + + int i = 0; + int argc = (int)[arguments count]; + const char **argv = (const char **)calloc((unsigned int)argc + 1, sizeof(const char *)); + for (NSString *arg in arguments) { + argv[i++] = [arg UTF8String]; + } + + testing::InitGoogleTest(&argc, (char **)argv); + UnitTest *googleTest = UnitTest::GetInstance(); + testing::TestEventListeners& listeners = googleTest->listeners(); + delete listeners.Release(listeners.default_result_printer()); + free(argv); + + BOOL runDisabledTests = testing::GTEST_FLAG(also_run_disabled_tests); + NSCharacterSet *decimalDigitCharacterSet = [NSCharacterSet decimalDigitCharacterSet]; + + XCTestSuite *testSuite = [GoogleTestSuite testSuiteWithName:NSStringFromClass([self class])]; + + for (int testCaseIndex = 0; testCaseIndex < googleTest->total_test_case_count(); testCaseIndex++) { + const TestCase *testCase = googleTest->GetTestCase(testCaseIndex); + NSString *testCaseName = @(testCase->name()); + + // For typed tests '/' is used to separate the parts of the test case name. + NSArray *testCaseNameComponents = [testCaseName componentsSeparatedByString:@"/"]; + + if (runDisabledTests == NO) { + BOOL testCaseDisabled = NO; + + for (NSString *component in testCaseNameComponents) { + if ([component hasPrefix:GoogleTestDisabledPrefix]) { + testCaseDisabled = YES; + break; + } + } + + if (testCaseDisabled) { + continue; + } + } + + // Xcode's parsing expects that the test's class and method names are valid + // Objective-C names. If they are not the tests will not be displayed properly in + // the UI. Join the test case name components with '_' rather than '/' to address + // this. + NSString *className = [testCaseNameComponents componentsJoinedByString:@"_"]; + + XCTestSuite *testCaseSuite = [XCTestSuite testSuiteWithName:className]; + + for (int testIndex = 0; testIndex < testCase->total_test_count(); testIndex++) { + const TestInfo *testInfo = testCase->GetTestInfo(testIndex); + NSString *testName = @(testInfo->name()); + if (runDisabledTests == NO && [testName hasPrefix:GoogleTestDisabledPrefix]) { + continue; + } + + // Google Test allows test names starting with a digit, prefix these with an + // underscore to create a valid method name. + NSString *methodName = testName; + if ([methodName length] > 0 && [decimalDigitCharacterSet characterIsMember:[methodName characterAtIndex:0]]) { + methodName = [@"_" stringByAppendingString:methodName]; + } + + NSString *testFilter = [NSString stringWithFormat:@"%@.%@", testCaseName, testName]; + + [testCaseSuite addTest:[[self alloc] initWithClassName:className + methodName:methodName + testFilter:testFilter]]; + } + + [testSuite addTest:testCaseSuite]; + } + + return testSuite; +} + +/** + * Runs a single test. + */ +- (void)runTest { + XCTestListener *listener = new XCTestListener(self); + UnitTest *googleTest = UnitTest::GetInstance(); + googleTest->listeners().Append(listener); + + testing::GTEST_FLAG(filter) = [_googleTestFilter UTF8String]; + + (void)RUN_ALL_TESTS(); + + delete googleTest->listeners().Release(listener); + + int totalTestsRun = googleTest->successful_test_count() + googleTest->failed_test_count(); + XCTAssertEqual(totalTestsRun, 1, @"Expected to run a single test for filter \"%@\"", _googleTestFilter); +} + +@end diff --git a/platforms/xcode/plustache.xcodeproj/project.pbxproj b/platforms/xcode/plustache.xcodeproj/project.pbxproj new file mode 100644 index 0000000..906ef26 --- /dev/null +++ b/platforms/xcode/plustache.xcodeproj/project.pbxproj @@ -0,0 +1,960 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXAggregateTarget section */ + 2F9708E31AF998CB00D82006 /* plustache-automake */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 2F9708E41AF998CB00D82006 /* Build configuration list for PBXAggregateTarget "plustache-automake" */; + buildPhases = ( + 2F9708FF1AF99A2300D82006 /* ShellScript */, + ); + dependencies = ( + ); + name = "plustache-automake"; + productName = plustache; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 2F9709151AF9A6D600D82006 /* libplustache.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F9709061AF9A6A900D82006 /* libplustache.a */; }; + 2F97091B1AF9A73900D82006 /* context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708ED1AF9992D00D82006 /* context.cpp */; }; + 2F97091D1AF9A73900D82006 /* template.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708EF1AF9992D00D82006 /* template.cpp */; }; + 2F97091E1AF9A73E00D82006 /* test_change_delimiter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F01AF9993B00D82006 /* test_change_delimiter.cpp */; }; + 2F97091F1AF9A73E00D82006 /* test_collections_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F11AF9993B00D82006 /* test_collections_plustache.cpp */; }; + 2F9709201AF9A73E00D82006 /* test_html_escape_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F21AF9993B00D82006 /* test_html_escape_plustache.cpp */; }; + 2F9709211AF9A73E00D82006 /* test_inverted_sections.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F31AF9993B00D82006 /* test_inverted_sections.cpp */; }; + 2F9709221AF9A73E00D82006 /* test_multiple_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F41AF9993B00D82006 /* test_multiple_plustache.cpp */; }; + 2F9709231AF9A73E00D82006 /* test_nested_sections_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F51AF9993B00D82006 /* test_nested_sections_plustache.cpp */; }; + 2F9709241AF9A73E00D82006 /* test_partials_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F61AF9993B00D82006 /* test_partials_plustache.cpp */; }; + 2F9709251AF9A73E00D82006 /* test_sections_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F71AF9993B00D82006 /* test_sections_plustache.cpp */; }; + 2F9709261AF9A73E00D82006 /* test_simple_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F81AF9993B00D82006 /* test_simple_plustache.cpp */; }; + 2F9709381AF9A8C700D82006 /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2F9709331AF9A86D00D82006 /* gtest-all.cc */; }; + 2F97093B1AF9A8D600D82006 /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F97092F1AF9A7F200D82006 /* libgtest.a */; }; + 2F97093C1AF9AAC100D82006 /* GoogleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2F9709011AF9A63800D82006 /* GoogleTests.mm */; }; + 2F9BE7CA1B3B5A510098800C /* tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9BE7C81B3B5A3D0098800C /* tests.cpp */; }; + 2F9BE7D61B3B5BCF0098800C /* tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9BE7C81B3B5A3D0098800C /* tests.cpp */; }; + 2F9BE7D71B3B5BE30098800C /* test_change_delimiter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F01AF9993B00D82006 /* test_change_delimiter.cpp */; }; + 2F9BE7D81B3B5BE30098800C /* test_collections_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F11AF9993B00D82006 /* test_collections_plustache.cpp */; }; + 2F9BE7D91B3B5BE30098800C /* test_html_escape_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F21AF9993B00D82006 /* test_html_escape_plustache.cpp */; }; + 2F9BE7DA1B3B5BE30098800C /* test_inverted_sections.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F31AF9993B00D82006 /* test_inverted_sections.cpp */; }; + 2F9BE7DB1B3B5BE30098800C /* test_multiple_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F41AF9993B00D82006 /* test_multiple_plustache.cpp */; }; + 2F9BE7DC1B3B5BE30098800C /* test_nested_sections_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F51AF9993B00D82006 /* test_nested_sections_plustache.cpp */; }; + 2F9BE7DD1B3B5BE30098800C /* test_partials_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F61AF9993B00D82006 /* test_partials_plustache.cpp */; }; + 2F9BE7DE1B3B5BE30098800C /* test_sections_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F71AF9993B00D82006 /* test_sections_plustache.cpp */; }; + 2F9BE7DF1B3B5BE30098800C /* test_simple_plustache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F9708F81AF9993B00D82006 /* test_simple_plustache.cpp */; }; + 2F9BE7E41B3B5C4C0098800C /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F97092F1AF9A7F200D82006 /* libgtest.a */; }; + 2F9BE7E51B3B5C4F0098800C /* libplustache.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F9709061AF9A6A900D82006 /* libplustache.a */; }; + 2FEF3FFC1B21EC3F00A1FFD7 /* context.hpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 2F9708FB1AF999B700D82006 /* context.hpp */; }; + 2FEF3FFD1B21EC3F00A1FFD7 /* plustache_types.hpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 2F9708FC1AF999B700D82006 /* plustache_types.hpp */; }; + 2FEF3FFE1B21EC3F00A1FFD7 /* template.hpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 2F9708FD1AF999B700D82006 /* template.hpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 2F9709161AF9A6D600D82006 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2F9708DD1AF9988D00D82006 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2F9709051AF9A6A900D82006; + remoteInfo = plustache; + }; + 2F9709391AF9A8CE00D82006 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2F9708DD1AF9988D00D82006 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2F97092E1AF9A7F200D82006; + remoteInfo = gtest; + }; + 2F9BE7E01B3B5C450098800C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2F9708DD1AF9988D00D82006 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2F97092E1AF9A7F200D82006; + remoteInfo = gtest; + }; + 2F9BE7E21B3B5C480098800C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2F9708DD1AF9988D00D82006 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2F9709051AF9A6A900D82006; + remoteInfo = plustache; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 2F9BE7CD1B3B5B9C0098800C /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 2FEF3FFB1B21EC3800A1FFD7 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + 2FEF3FFC1B21EC3F00A1FFD7 /* context.hpp in CopyFiles */, + 2FEF3FFD1B21EC3F00A1FFD7 /* plustache_types.hpp in CopyFiles */, + 2FEF3FFE1B21EC3F00A1FFD7 /* template.hpp in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 2F9708ED1AF9992D00D82006 /* context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = context.cpp; sourceTree = ""; }; + 2F9708EF1AF9992D00D82006 /* template.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = template.cpp; sourceTree = ""; }; + 2F9708F01AF9993B00D82006 /* test_change_delimiter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_change_delimiter.cpp; sourceTree = ""; }; + 2F9708F11AF9993B00D82006 /* test_collections_plustache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_collections_plustache.cpp; sourceTree = ""; }; + 2F9708F21AF9993B00D82006 /* test_html_escape_plustache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_html_escape_plustache.cpp; sourceTree = ""; }; + 2F9708F31AF9993B00D82006 /* test_inverted_sections.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_inverted_sections.cpp; sourceTree = ""; }; + 2F9708F41AF9993B00D82006 /* test_multiple_plustache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_multiple_plustache.cpp; sourceTree = ""; }; + 2F9708F51AF9993B00D82006 /* test_nested_sections_plustache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_nested_sections_plustache.cpp; sourceTree = ""; }; + 2F9708F61AF9993B00D82006 /* test_partials_plustache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_partials_plustache.cpp; sourceTree = ""; }; + 2F9708F71AF9993B00D82006 /* test_sections_plustache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_sections_plustache.cpp; sourceTree = ""; }; + 2F9708F81AF9993B00D82006 /* test_simple_plustache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_simple_plustache.cpp; sourceTree = ""; }; + 2F9708FB1AF999B700D82006 /* context.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = context.hpp; sourceTree = ""; }; + 2F9708FC1AF999B700D82006 /* plustache_types.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = plustache_types.hpp; sourceTree = ""; }; + 2F9708FD1AF999B700D82006 /* template.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = template.hpp; sourceTree = ""; }; + 2F9709011AF9A63800D82006 /* GoogleTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = GoogleTests.mm; sourceTree = SOURCE_ROOT; }; + 2F9709061AF9A6A900D82006 /* libplustache.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libplustache.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 2F97090F1AF9A6D600D82006 /* tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 2F97092F1AF9A7F200D82006 /* libgtest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 2F9709331AF9A86D00D82006 /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "gtest-all.cc"; sourceTree = ""; }; + 2F9BE7C81B3B5A3D0098800C /* tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tests.cpp; path = ../../tests/tests.cpp; sourceTree = SOURCE_ROOT; }; + 2F9BE7CF1B3B5B9C0098800C /* tests-manual */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "tests-manual"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2F9709031AF9A6A900D82006 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2F97090C1AF9A6D600D82006 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F9709151AF9A6D600D82006 /* libplustache.a in Frameworks */, + 2F97093B1AF9A8D600D82006 /* libgtest.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2F97092C1AF9A7F200D82006 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2F9BE7CC1B3B5B9C0098800C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F9BE7E51B3B5C4F0098800C /* libplustache.a in Frameworks */, + 2F9BE7E41B3B5C4C0098800C /* libgtest.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2F9708DC1AF9988D00D82006 = { + isa = PBXGroup; + children = ( + 2F9708FA1AF9996000D82006 /* include */, + 2F9708EB1AF998E400D82006 /* src */, + 2F9708EC1AF9990500D82006 /* tests */, + 2F9BE7D01B3B5B9C0098800C /* tests-manual */, + 2F9709361AF9A87F00D82006 /* vendor */, + 2F9709071AF9A6A900D82006 /* Products */, + ); + sourceTree = ""; + }; + 2F9708EB1AF998E400D82006 /* src */ = { + isa = PBXGroup; + children = ( + 2F9708ED1AF9992D00D82006 /* context.cpp */, + 2F9708EF1AF9992D00D82006 /* template.cpp */, + ); + name = src; + path = ../../src; + sourceTree = ""; + }; + 2F9708EC1AF9990500D82006 /* tests */ = { + isa = PBXGroup; + children = ( + 2F9708F01AF9993B00D82006 /* test_change_delimiter.cpp */, + 2F9708F11AF9993B00D82006 /* test_collections_plustache.cpp */, + 2F9708F21AF9993B00D82006 /* test_html_escape_plustache.cpp */, + 2F9708F31AF9993B00D82006 /* test_inverted_sections.cpp */, + 2F9708F41AF9993B00D82006 /* test_multiple_plustache.cpp */, + 2F9708F51AF9993B00D82006 /* test_nested_sections_plustache.cpp */, + 2F9708F61AF9993B00D82006 /* test_partials_plustache.cpp */, + 2F9708F71AF9993B00D82006 /* test_sections_plustache.cpp */, + 2F9708F81AF9993B00D82006 /* test_simple_plustache.cpp */, + ); + name = tests; + path = ../../tests; + sourceTree = ""; + }; + 2F9708FA1AF9996000D82006 /* include */ = { + isa = PBXGroup; + children = ( + 2F9708FE1AF999CE00D82006 /* plustache */, + ); + name = include; + path = ../../include; + sourceTree = ""; + }; + 2F9708FE1AF999CE00D82006 /* plustache */ = { + isa = PBXGroup; + children = ( + 2F9708FB1AF999B700D82006 /* context.hpp */, + 2F9708FC1AF999B700D82006 /* plustache_types.hpp */, + 2F9708FD1AF999B700D82006 /* template.hpp */, + ); + path = plustache; + sourceTree = ""; + }; + 2F9709071AF9A6A900D82006 /* Products */ = { + isa = PBXGroup; + children = ( + 2F9709061AF9A6A900D82006 /* libplustache.a */, + 2F97090F1AF9A6D600D82006 /* tests.xctest */, + 2F97092F1AF9A7F200D82006 /* libgtest.a */, + 2F9BE7CF1B3B5B9C0098800C /* tests-manual */, + ); + name = Products; + sourceTree = ""; + }; + 2F9709361AF9A87F00D82006 /* vendor */ = { + isa = PBXGroup; + children = ( + 2F9709371AF9A89A00D82006 /* gtest */, + ); + name = vendor; + path = ../../vendor; + sourceTree = ""; + }; + 2F9709371AF9A89A00D82006 /* gtest */ = { + isa = PBXGroup; + children = ( + 2F9709011AF9A63800D82006 /* GoogleTests.mm */, + 2F9709331AF9A86D00D82006 /* gtest-all.cc */, + ); + name = gtest; + path = "gtest-1.6.0/src"; + sourceTree = ""; + }; + 2F9BE7D01B3B5B9C0098800C /* tests-manual */ = { + isa = PBXGroup; + children = ( + 2F9BE7C81B3B5A3D0098800C /* tests.cpp */, + ); + path = "tests-manual"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 2F97092D1AF9A7F200D82006 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 2F9709051AF9A6A900D82006 /* plustache */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2F9709081AF9A6A900D82006 /* Build configuration list for PBXNativeTarget "plustache" */; + buildPhases = ( + 2FEF3FFB1B21EC3800A1FFD7 /* CopyFiles */, + 2F9709021AF9A6A900D82006 /* Sources */, + 2F9709031AF9A6A900D82006 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = plustache; + productName = plustache; + productReference = 2F9709061AF9A6A900D82006 /* libplustache.a */; + productType = "com.apple.product-type.library.static"; + }; + 2F97090E1AF9A6D600D82006 /* tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2F9709181AF9A6D600D82006 /* Build configuration list for PBXNativeTarget "tests" */; + buildPhases = ( + 2F97090B1AF9A6D600D82006 /* Sources */, + 2F97090C1AF9A6D600D82006 /* Frameworks */, + 2F97090D1AF9A6D600D82006 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 2F9709171AF9A6D600D82006 /* PBXTargetDependency */, + 2F97093A1AF9A8CE00D82006 /* PBXTargetDependency */, + ); + name = tests; + productName = tests; + productReference = 2F97090F1AF9A6D600D82006 /* tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 2F97092E1AF9A7F200D82006 /* gtest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2F9709301AF9A7F200D82006 /* Build configuration list for PBXNativeTarget "gtest" */; + buildPhases = ( + 2F97092B1AF9A7F200D82006 /* Sources */, + 2F97092C1AF9A7F200D82006 /* Frameworks */, + 2F97092D1AF9A7F200D82006 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = gtest; + productName = gtest; + productReference = 2F97092F1AF9A7F200D82006 /* libgtest.a */; + productType = "com.apple.product-type.library.static"; + }; + 2F9BE7CE1B3B5B9C0098800C /* tests-manual */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2F9BE7D31B3B5B9C0098800C /* Build configuration list for PBXNativeTarget "tests-manual" */; + buildPhases = ( + 2F9BE7CB1B3B5B9C0098800C /* Sources */, + 2F9BE7CC1B3B5B9C0098800C /* Frameworks */, + 2F9BE7CD1B3B5B9C0098800C /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 2F9BE7E31B3B5C480098800C /* PBXTargetDependency */, + 2F9BE7E11B3B5C450098800C /* PBXTargetDependency */, + ); + name = "tests-manual"; + productName = "tests-manual"; + productReference = 2F9BE7CF1B3B5B9C0098800C /* tests-manual */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2F9708DD1AF9988D00D82006 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0640; + TargetAttributes = { + 2F9708E31AF998CB00D82006 = { + CreatedOnToolsVersion = 6.3.1; + }; + 2F9709051AF9A6A900D82006 = { + CreatedOnToolsVersion = 6.3.1; + }; + 2F97090E1AF9A6D600D82006 = { + CreatedOnToolsVersion = 6.3.1; + }; + 2F97092E1AF9A7F200D82006 = { + CreatedOnToolsVersion = 6.3.1; + }; + 2F9BE7CE1B3B5B9C0098800C = { + CreatedOnToolsVersion = 6.3.2; + }; + }; + }; + buildConfigurationList = 2F9708E01AF9988D00D82006 /* Build configuration list for PBXProject "plustache" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 2F9708DC1AF9988D00D82006; + productRefGroup = 2F9709071AF9A6A900D82006 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2F9709051AF9A6A900D82006 /* plustache */, + 2F97090E1AF9A6D600D82006 /* tests */, + 2F9BE7CE1B3B5B9C0098800C /* tests-manual */, + 2F9708E31AF998CB00D82006 /* plustache-automake */, + 2F97092E1AF9A7F200D82006 /* gtest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2F97090D1AF9A6D600D82006 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2F9708FF1AF99A2300D82006 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cwd=$(pwd)\nset -e\nexport PATH=\"/usr/local/bin:$PATH\"\n\nsrc_root=\"$cwd/../..\"\ninstall_root=\"$BUILT_PRODUCTS_DIR\"\nbuild_root=\"$PROJECT_TEMP_ROOT/plustache.build/src\"\n\nif [ ! -d \"$build_root\" ]; then\n mkdir -p \"$build_root\"\nfi\n\ncp -af \"$src_root/\" \"$build_root\"\ncd \"$build_root\"\n\nif [ ! -f \"configure\" ]; then\n autoreconf -i\nfi\n\nif [ ! -f Makefile ]; then\n ./configure --prefix=\"$install_root\"\nfi\n\nmake\nmake install\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2F9709021AF9A6A900D82006 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F97091B1AF9A73900D82006 /* context.cpp in Sources */, + 2F97091D1AF9A73900D82006 /* template.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2F97090B1AF9A6D600D82006 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F97091F1AF9A73E00D82006 /* test_collections_plustache.cpp in Sources */, + 2F9709221AF9A73E00D82006 /* test_multiple_plustache.cpp in Sources */, + 2F9709211AF9A73E00D82006 /* test_inverted_sections.cpp in Sources */, + 2F9709251AF9A73E00D82006 /* test_sections_plustache.cpp in Sources */, + 2F9709241AF9A73E00D82006 /* test_partials_plustache.cpp in Sources */, + 2F9709261AF9A73E00D82006 /* test_simple_plustache.cpp in Sources */, + 2F9709231AF9A73E00D82006 /* test_nested_sections_plustache.cpp in Sources */, + 2F97091E1AF9A73E00D82006 /* test_change_delimiter.cpp in Sources */, + 2F97093C1AF9AAC100D82006 /* GoogleTests.mm in Sources */, + 2F9BE7CA1B3B5A510098800C /* tests.cpp in Sources */, + 2F9709201AF9A73E00D82006 /* test_html_escape_plustache.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2F97092B1AF9A7F200D82006 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F9709381AF9A8C700D82006 /* gtest-all.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2F9BE7CB1B3B5B9C0098800C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2F9BE7D61B3B5BCF0098800C /* tests.cpp in Sources */, + 2F9BE7D71B3B5BE30098800C /* test_change_delimiter.cpp in Sources */, + 2F9BE7D81B3B5BE30098800C /* test_collections_plustache.cpp in Sources */, + 2F9BE7D91B3B5BE30098800C /* test_html_escape_plustache.cpp in Sources */, + 2F9BE7DA1B3B5BE30098800C /* test_inverted_sections.cpp in Sources */, + 2F9BE7DB1B3B5BE30098800C /* test_multiple_plustache.cpp in Sources */, + 2F9BE7DC1B3B5BE30098800C /* test_nested_sections_plustache.cpp in Sources */, + 2F9BE7DD1B3B5BE30098800C /* test_partials_plustache.cpp in Sources */, + 2F9BE7DE1B3B5BE30098800C /* test_sections_plustache.cpp in Sources */, + 2F9BE7DF1B3B5BE30098800C /* test_simple_plustache.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 2F9709171AF9A6D600D82006 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2F9709051AF9A6A900D82006 /* plustache */; + targetProxy = 2F9709161AF9A6D600D82006 /* PBXContainerItemProxy */; + }; + 2F97093A1AF9A8CE00D82006 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2F97092E1AF9A7F200D82006 /* gtest */; + targetProxy = 2F9709391AF9A8CE00D82006 /* PBXContainerItemProxy */; + }; + 2F9BE7E11B3B5C450098800C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2F97092E1AF9A7F200D82006 /* gtest */; + targetProxy = 2F9BE7E01B3B5C450098800C /* PBXContainerItemProxy */; + }; + 2F9BE7E31B3B5C480098800C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2F9709051AF9A6A900D82006 /* plustache */; + targetProxy = 2F9BE7E21B3B5C480098800C /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 2F9708E11AF9988D00D82006 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "compiler-default"; + GCC_VERSION = ""; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DGTEST_USE_OWN_TR1_TUPLE=1", + "-std=c++11", + ); + }; + name = Debug; + }; + 2F9708E21AF9988D00D82006 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + CLANG_CXX_LIBRARY = "compiler-default"; + GCC_VERSION = ""; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DGTEST_USE_OWN_TR1_TUPLE=1", + "-std=c++11", + ); + }; + name = Release; + }; + 2F9708E51AF998CB00D82006 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 2F9708E61AF998CB00D82006 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 2F9709091AF9A6A900D82006 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 2F97090A1AF9A6A900D82006 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; + 2F9709191AF9A6D600D82006 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/include", + ); + INFOPLIST_FILE = ""; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 2F97091A1AF9A6D600D82006 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", + ); + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/include", + ); + INFOPLIST_FILE = ""; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; + 2F9709311AF9A7F200D82006 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/include", + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 2F9709321AF9A7F200D82006 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/include", + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; + 2F9BE7D41B3B5B9C0098800C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/include", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 2F9BE7D51B3B5B9C0098800C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SOURCE_ROOT)/../../vendor/gtest-1.6.0/include", + ); + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2F9708E01AF9988D00D82006 /* Build configuration list for PBXProject "plustache" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2F9708E11AF9988D00D82006 /* Debug */, + 2F9708E21AF9988D00D82006 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2F9708E41AF998CB00D82006 /* Build configuration list for PBXAggregateTarget "plustache-automake" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2F9708E51AF998CB00D82006 /* Debug */, + 2F9708E61AF998CB00D82006 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2F9709081AF9A6A900D82006 /* Build configuration list for PBXNativeTarget "plustache" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2F9709091AF9A6A900D82006 /* Debug */, + 2F97090A1AF9A6A900D82006 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2F9709181AF9A6D600D82006 /* Build configuration list for PBXNativeTarget "tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2F9709191AF9A6D600D82006 /* Debug */, + 2F97091A1AF9A6D600D82006 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2F9709301AF9A7F200D82006 /* Build configuration list for PBXNativeTarget "gtest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2F9709311AF9A7F200D82006 /* Debug */, + 2F9709321AF9A7F200D82006 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2F9BE7D31B3B5B9C0098800C /* Build configuration list for PBXNativeTarget "tests-manual" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2F9BE7D41B3B5B9C0098800C /* Debug */, + 2F9BE7D51B3B5B9C0098800C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 2F9708DD1AF9988D00D82006 /* Project object */; +} diff --git a/platforms/xcode/plustache.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platforms/xcode/plustache.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/platforms/xcode/plustache.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/platforms/xcode/plustache.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/platforms/xcode/plustache.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..08de0be --- /dev/null +++ b/platforms/xcode/plustache.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/platforms/xcode/plustache.xcodeproj/xcshareddata/xcschemes/plustache.xcscheme b/platforms/xcode/plustache.xcodeproj/xcshareddata/xcschemes/plustache.xcscheme new file mode 100644 index 0000000..c7e4ff8 --- /dev/null +++ b/platforms/xcode/plustache.xcodeproj/xcshareddata/xcschemes/plustache.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/template.cpp b/src/template.cpp index b2f93d0..7c43d03 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -7,14 +7,55 @@ #include #include -#include -#include +#include +#include #include #include using namespace Plustache; + +/** + * @brief trim whitespace from the start of a string + * + * @param s the string to trim + * + * @return s, trimmed + */ +static inline std::string <rim(std::string &s) +{ + s.erase(s.begin(), std::find_if(s.begin(), s.end(), + std::not1(std::ptr_fun(std::isspace)))); + return s; +} + +/** + * @brief trim whitespace from the end of a string + * + * @param s the string to trim + * + * @return s, trimmed + */ +static inline std::string &rtrim(std::string &s) +{ + s.erase(std::find_if(s.rbegin(), s.rend(), + std::not1(std::ptr_fun(std::isspace))).base(), s.end()); + return s; +} + +/** + * @brief trim whitespace from both ends of a string + * + * @param s the string to trim + * + * @return s, trimmed + */ +static inline std::string &trim(std::string &s) +{ + return ltrim(rtrim(s)); +} + /** * @brief constructor taking no arguments */ @@ -47,14 +88,26 @@ void template_t::compile_data() escape_lut[">"] = ">"; escape_lut["\\"] = "\"; escape_lut["\""] = """; + // regex for what to escape in a html std::string escape_chars.assign("(<|>|\"|\\\\|&)"); + + // tag delimiters otag = "\\{\\{"; ctag = "\\}\\}"; + update_tags(); +} +/** + * @brief applies the current ctag/otag settings to the tag & section + * regex patterns + */ +void template_t::update_tags() { // tag and section regex tag.assign(otag + "(#|=|&|!|>|\\{)?(.+?)(\\})?" + ctag); - section.assign(otag + "(\\^|\\#)([^\\}]*)" + ctag + "\\s*(.+?)\\s*" - + otag + "/\\2"+ctag); + section.assign(otag + "(\\^|\\#)([^\\}]*)" + ctag + + "(?:[ \\t]*\\n)?" + // ignore leading whitespace + "((?:.|\\s)+?)" + // section content + otag + "\\/\\2" + ctag); } /** @@ -80,23 +133,25 @@ std::string template_t::render_tags(const std::string& tmplate, std::string ret = ""; std::string rest = ""; std::string::const_iterator start, end; - boost::match_results matches; + std::match_results matches; start = tmplate.begin(); end = tmplate.end(); // return whole std::string when no tags are found if (!regex_search(start, end, matches, tag, - boost::match_default | boost::format_all)) + std::regex_constants::match_default | + std::regex_constants::format_default)) { ret = tmplate; } // loop through tags and replace while (regex_search(start, end, matches, tag, - boost::match_default | boost::format_all)) + std::regex_constants::match_default | + std::regex_constants::format_default)) { std::string modifier(matches[1].first, matches[1].second); std::string key(matches[2].first, matches[2].second); - boost::algorithm::trim(key); - boost::algorithm::trim(modifier); + trim(key); + trim(modifier); std::string text(start, matches[0].second); std::string repl; // don't html escape this @@ -111,7 +166,7 @@ std::string template_t::render_tags(const std::string& tmplate, size_t found = s.find(f); while(found != std::string::npos) { - s.replace(found,f.length(),"\\\\"); + s.replace(found,f.length(),"\\"); found = s.find(f, found+2); } repl.assign(s); @@ -141,17 +196,19 @@ std::string template_t::render_tags(const std::string& tmplate, // replace ret += regex_replace(text, tag, repl, - boost::match_default | boost::format_all); + std::regex_constants::match_default | + std::regex_constants::format_default); // change delimiter after was removed if (modifier == "=") { // regex for finding delimiters - boost::regex delim("(.+?) (.+?)="); + std::regex delim("(.+?) (.+?)="); // match object - boost::match_results delim_m; + std::match_results delim_m; // search for the delimiters - boost::regex_search(matches[2].first, matches[2].second, delim_m, delim, - boost::match_default | boost::format_all); + std::regex_search(matches[2].first, matches[2].second, delim_m, delim, + std::regex_constants::match_default | + std::regex_constants::format_default); // set new otag and ctag std::string new_otag = delim_m[1]; std::string new_ctag = delim_m[2]; @@ -161,6 +218,9 @@ std::string template_t::render_tags(const std::string& tmplate, // set start for next tag and rest of std::string rest.assign(matches[0].second, end); start = matches[0].second; + + // Reset for next round (required for libstdc++ implementation) + matches = std::match_results(); } // append and return ret += rest; @@ -182,30 +242,34 @@ std::string template_t::render_sections(const std::string& tmplate, std::string ret = ""; std::string rest = ""; std::string::const_iterator start, end; - boost::match_results matches; + std::match_results matches; start = tmplate.begin(); end = tmplate.end(); // return the whole template if no sections are found - if (!boost::regex_search(start, end, matches, section, - boost::match_default | boost::format_all)) + if (!std::regex_search(start, end, matches, section, + std::regex_constants::match_default | + std::regex_constants::format_default)) { ret = tmplate; } // loop through sections and render - while (boost::regex_search(start, end, matches, section, - boost::match_default | boost::format_all)) + while (std::regex_search(start, end, matches, section, + std::regex_constants::match_default | + std::regex_constants::format_default)) { // std::string assignments std::string text(start, matches[0].second); std::string key(matches[2].first, matches[2].second); std::string modifier(matches[1]); + // trimming - boost::algorithm::trim(key); - boost::algorithm::trim(modifier); + trim(key); + trim(modifier); std::string repl = ""; std::string show = "false"; CollectionType values; values = ctx.get(key); + if (values.size() == 1) { // if we don't have a collection, we find the key and an @@ -225,37 +289,59 @@ std::string template_t::render_sections(const std::string& tmplate, { show = "true"; } + // inverted section? if (modifier == "^" && show == "false") show = "true"; else if (modifier == "^" && show == "true") show = "false"; - // assign replacement content + + // Generate content if (show == "true") { - if (boost::regex_search(matches[3].first, matches[3].second, section, - boost::match_default | boost::format_all)) + for(CollectionType::iterator it = values.begin(); + it != values.end(); ++it) { - repl.assign(template_t::render_sections(matches[3], ctx)); - } - else - { - for(CollectionType::iterator it = values.begin(); - it != values.end(); ++it) + std::string content = matches[3]; + Context small_ctx; + small_ctx = ctx; + small_ctx.add(*it); + + if (std::regex_search(content, section, + std::regex_constants::match_default | + std::regex_constants::format_default)) { - Context small_ctx; - small_ctx = ctx; - small_ctx.add(*it); - repl += template_t::render_tags(matches[3], small_ctx); + content.assign(template_t::render_sections( + content, small_ctx)); } + + repl += template_t::render_tags(content, small_ctx); } } - else repl.assign(""); - ret += boost::regex_replace(text, section, repl, - boost::match_default | boost::format_all); - rest.assign(matches[0].second, end); - start = matches[0].second; + // Hide section with empty content + else { + repl.assign(""); + } + + // Replace matched section with generated text + ret += std::regex_replace(text, section, repl, + std::regex_constants::match_default | + std::regex_constants::format_default); + + // Check on end-of-section newlines + bool shouldSkipNextNewline = + // If the section ended in a newline, or was empty... + ((repl[repl.length() - 1] == '\n') || show == "false") && + // ...and the section is also followed by a newline, skip it. + (std::string(matches[0].second, matches[0].second + 1) == "\n"); + + // Store the rest of the template for the next pass + auto next = matches[0].second + (shouldSkipNextNewline ? 1 : 0); + rest.assign(next, end); + start = next; } + // append and return ret += rest; + return ret; } @@ -316,26 +402,29 @@ std::string template_t::html_escape(const std::string& s) std::string ret = ""; std::string rest = ""; std::string::const_iterator start, end; - boost::match_results matches; + std::match_results matches; start = s.begin(); end = s.end(); // return original std::string if nothing is found - if (!boost::regex_search(start, end, matches, escape_chars, - boost::match_default | boost::format_all)) + if (!std::regex_search(start, end, matches, escape_chars, + std::regex_constants::match_default | + std::regex_constants::format_default)) { ret = s; } // search for html chars - while (boost::regex_search(start, end, matches, escape_chars, - boost::match_default | boost::format_all)) + while (std::regex_search(start, end, matches, escape_chars, + std::regex_constants::match_default | + std::regex_constants::format_default)) { std::string key(matches[0].first, matches[0].second); std::string text(start, matches[0].second); - boost::algorithm::trim(key); + trim(key); std::string repl; repl = escape_lut[key]; - ret += boost::regex_replace(text, escape_chars, repl, - boost::match_default | boost::format_all); + ret += std::regex_replace(text, escape_chars, repl, + std::regex_constants::match_default | + std::regex_constants::format_default); rest.assign(matches[0].second, end); start = matches[0].second; } @@ -391,10 +480,7 @@ void template_t::change_delimiter(const std::string& opentag, { otag = opentag; ctag = closetag; - // tag and section regex - template_t::tag.assign(otag + "(#|=|&|!|>|\\{)?(.+?)(\\})?" + ctag); - template_t::section.assign(otag + "(\\^|\\#)([^\\}]*)" + ctag + - "\\s*(.+?)\\s*" + otag + "/\\2"+ctag); + update_tags(); } /** diff --git a/tests/test_change_delimiter.cpp b/tests/test_change_delimiter.cpp index 127e296..6a94cb8 100644 --- a/tests/test_change_delimiter.cpp +++ b/tests/test_change_delimiter.cpp @@ -41,10 +41,6 @@ class ChangeDelimiterTest : public ::testing::Test ctx["name"] = "Daniel"; ctx["pet"] = "turtles"; - Plustache::template_t t; - result_string = t.render(template_string, ctx); - Plustache::template_t t2; - result_file = t2.render(file, ctx); } virtual void TearDown() @@ -57,6 +53,8 @@ class ChangeDelimiterTest : public ::testing::Test // Tests that a simple mustache tag is replaced TEST_F(ChangeDelimiterTest, TestChangeDelimiterFromString) { + Plustache::template_t t; + result_string = t.render(template_string, ctx); std::string expected = "Hi I am Daniel.\n"; expected += "I like turtles."; EXPECT_EQ(expected, result_string); @@ -64,6 +62,8 @@ TEST_F(ChangeDelimiterTest, TestChangeDelimiterFromString) TEST_F(ChangeDelimiterTest, TestChangeDelimiterFromFile) { + Plustache::template_t t2; + result_file = t2.render(file, ctx); std::string expected = "Hi I am Daniel.\n"; expected += "I like turtles."; EXPECT_EQ(expected, result_file); diff --git a/tests/test_collections_plustache.cpp b/tests/test_collections_plustache.cpp index aa88b4e..0b4430f 100644 --- a/tests/test_collections_plustache.cpp +++ b/tests/test_collections_plustache.cpp @@ -100,3 +100,88 @@ TEST_F(CollectionsTest, TestCollectionMultipleWithMultipleFields) expected += "Hi Daniel, I am Jerry, I do Magic."; EXPECT_EQ(expected, result_multiple_fields); } +TEST_F(CollectionsTest, TestCollectionMultiLine) +{ + Plustache::Context ctx; + ctx.add("me", "Daniel"); + + PlustacheTypes::ObjectType tom; + tom["name"] = "Tom"; + tom["work"] = "Accounting"; + ctx.add("people", tom); + + PlustacheTypes::ObjectType jerry; + jerry["name"] = "Jerry"; + jerry["work"] = "Magic"; + ctx.add("people", jerry); + + std::string tmplate = +R"---tmplate---( +Hi! I am {{me}}. +{{#people}} +Hello, {{me}}; I am {{name}}, and I do {{work}}. +{{/people}} + +*crickets* +)---tmplate---"; + + std::string expected = +R"---expected---( +Hi! I am Daniel. +Hello, Daniel; I am Tom, and I do Accounting. +Hello, Daniel; I am Jerry, and I do Magic. + +*crickets* +)---expected---"; + + Plustache::template_t t; + std::string actual = t.render(tmplate, ctx); + + EXPECT_EQ(expected, actual); +} + +TEST_F(CollectionsTest, TestCollectionMultiLineConditionals) +{ + Plustache::Context ctx; + ctx.add("me", "Daniel"); + + PlustacheTypes::ObjectType tom; + tom["name"] = "Tom"; + tom["work"] = "Accounting"; + tom["surprise"] = "false"; + ctx.add("people", tom); + + PlustacheTypes::ObjectType jerry; + jerry["name"] = "Jerry"; + jerry["work"] = "Magic"; + jerry["surprise"] = "true"; + ctx.add("people", jerry); + + std::string tmplate = +R"---tmplate---( +Hi! I am {{me}}. +{{#people}} +Hello, {{me}}; I am {{name}}, and I do {{work}}. +{{#surprise}} +*{{name}} disappears in a flash of light and smoke* +{{/surprise}} +{{/people}} + +*crickets* +)---tmplate---"; + + std::string expected = +R"---expected---( +Hi! I am Daniel. +Hello, Daniel; I am Tom, and I do Accounting. +Hello, Daniel; I am Jerry, and I do Magic. +*Jerry disappears in a flash of light and smoke* + +*crickets* +)---expected---"; + + Plustache::template_t t; + std::string actual = t.render(tmplate, ctx); + + EXPECT_EQ(expected, actual); +} diff --git a/tests/test_inverted_sections.cpp b/tests/test_inverted_sections.cpp index de8efd8..0ac94bb 100644 --- a/tests/test_inverted_sections.cpp +++ b/tests/test_inverted_sections.cpp @@ -10,11 +10,7 @@ class InvertedSectionsTest : public ::testing::Test { protected: - std::string result_string; - std::string result_file; - std::string template_string; PlustacheTypes::ObjectType ctx; - std::string file; InvertedSectionsTest() { @@ -26,58 +22,76 @@ class InvertedSectionsTest : public ::testing::Test virtual void SetUp() { - template_string = "Hi I am {{name}}.\n"; - template_string += "{{# showme}}"; - template_string += "I like {{pet}}."; - template_string += "{{/ showme}}"; - template_string += "{{^ inverted}}"; - template_string += "Hope you can see me."; - template_string += "{{/ inverted}}"; - template_string += "{{^ inverted2}}"; - template_string += "me too."; - template_string += "{{/ inverted2}}"; - template_string += "{{^ stealth}}"; - template_string += "I'm invisible."; - template_string += "{{/ stealth}}"; - file = "sections.mustache"; - - std::ofstream myfile; - myfile.open (file.c_str()); - myfile << template_string; - myfile.close(); - ctx["name"] = "Daniel"; ctx["pet"] = "turtles"; ctx["showme"] = "true"; ctx["stealth"] = "true"; ctx["inverted"] = "false"; - Plustache::template_t t; - result_string = t.render(template_string, ctx); - result_file = t.render(file, ctx); } virtual void TearDown() { - remove(file.c_str()); } - }; // Tests that a simple mustache tag is replaced -TEST_F(InvertedSectionsTest, TestInvertedSectionMustacheFromString) +TEST_F(InvertedSectionsTest, TestInvertedSection) { - std::string expected = "Hi I am Daniel.\n"; - expected += "I like turtles."; - expected += "Hope you can see me."; - expected += "me too."; - EXPECT_EQ(expected, result_string); + std::string tmplate= + "Hi I am {{name}}.\n" + "{{# showme}}" + "I like {{pet}}." + "{{/ showme}}" + "{{^ inverted}}" + "Hope you can see me." + "{{/ inverted}}" + "{{^ inverted2}}" + "me too." + "{{/ inverted2}}" + "{{^ stealth}}" + "I'm invisible." + "{{/ stealth}}"; + std::string expected = + "Hi I am Daniel.\n" + "I like turtles." + "Hope you can see me." + "me too."; + + Plustache::template_t t; + std::string actual = t.render(tmplate, ctx); + + EXPECT_EQ(expected, actual); } -TEST_F(InvertedSectionsTest, TestInvertedSectionMustacheFromFile) +TEST_F(InvertedSectionsTest, TestInvertedSectionWithNewlines) { - std::string expected = "Hi I am Daniel.\n"; - expected += "I like turtles."; - expected += "Hope you can see me."; - expected += "me too."; - EXPECT_EQ(expected, result_file); + std::string tmplate = +R"---tmplate---( +Hi I am {{name}}. +{{# showme}} +I like {{pet}}. +{{/ showme}} +{{^ inverted}} +Hope you can see me. +{{/ inverted}} +{{^ inverted2}} +me too. +{{/ inverted2}} +{{^ stealth}} +I'm invisible. +{{/ stealth}} +)---tmplate---"; + + std::string expected = +R"---expected---( +Hi I am Daniel. +I like turtles. +Hope you can see me. +me too. +)---expected---"; + + Plustache::template_t t; + std::string actual = t.render(tmplate, ctx); + + EXPECT_EQ(expected, actual); }