From 1eb85fa1a83c821151e0752c768208a992892a7f Mon Sep 17 00:00:00 2001 From: pantor Date: Wed, 15 Nov 2017 22:07:55 +0100 Subject: [PATCH] fix round() function, tests for syntax change, smaller readme fixes --- CMakeLists.txt | 2 +- README.md | 14 +++++++------- src/inja.hpp | 16 ++++++++-------- test/CMakeLists.txt | 13 ++++++++++--- test/src/unit-parser.cpp | 7 +++++++ test/src/unit-renderer.cpp | 26 +++++++++++++++++++++++++- 6 files changed, 58 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 645e0db..d521aca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ option(BUILD_UNIT_TESTS "Build the unit tests" ON) ## CONFIGURATION ## set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall --coverage") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") set(INJA_SOURCE_DIR src/) set(INJA_HEADER_INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/dist) diff --git a/README.md b/README.md index 68d8446..a7b2d98 100644 --- a/README.md +++ b/README.md @@ -75,11 +75,11 @@ Environment env = Environment("../path/templates/"); // With global path where to save rendered files Environment env = Environment("../path/templates/", "../path/results/"); -// With other opening and closing strings (here the defaults) -env.setVariables("{{", "}}"); // Variables -env.setComments("{#", "#}"); // Comments -env.setStatements("{%", "%}"); // Statements for many things, see below -env.setLineStatements("##"); // Line statement (just an opener) +// With other opening and closing strings (here the defaults, as regex) +env.setVariables("\\{\\{", "\\}\\}"); // Variables {{ }} +env.setComments("\\{#", "#\\}"); // Comments {# #} +env.setStatements("\\{\\%", "\\%\\}"); // Statements {% %} for many things, see below +env.setLineStatements("##"); // Line statement ## (just an opener) ``` ### Variables @@ -103,7 +103,7 @@ In general, the variables can be fetched using the [JSON Pointer](https://tools. ### Statements -Statements can be written with the `{% ... %}` syntax. The most important statements are loops, conditions and file includes. All statements can be nested. +Statements can be written either with the `{% ... %}` syntax or the `##` syntax for entire lines. The most important statements are loops, conditions and file includes. All statements can be nested. #### Loops @@ -186,4 +186,4 @@ Currently, the following compilers are tested: ## License -The class is licensed under the [MIT License](https://raw.githubusercontent.com/pantor/inja/master/LICENSE). +Inja is licensed under the [MIT License](https://raw.githubusercontent.com/pantor/inja/master/LICENSE). diff --git a/src/inja.hpp b/src/inja.hpp index 14236e6..7cc2fa5 100644 --- a/src/inja.hpp +++ b/src/inja.hpp @@ -247,7 +247,7 @@ public: {Function::Lower, Regex{"lower\\(\\s*(.*?)\\s*\\)"}}, {Function::Range, Regex{"range\\(\\s*(.*?)\\s*\\)"}}, {Function::Length, Regex{"length\\(\\s*(.*?)\\s*\\)"}}, - {Function::Round, Regex{"length\\(\\s*(.*?)\\s*,\\s*(.*?)\\s*\\)"}}, + {Function::Round, Regex{"round\\(\\s*(.*?)\\s*,\\s*(.*?)\\s*\\)"}}, }; Parser() { } @@ -430,12 +430,12 @@ public: case Parser::Function::Round: { const json number = eval_variable(match_function.str(1), data); const json precision = eval_variable(match_function.str(2), data); - if (not number.is_number()) { throw std::runtime_error("Argument in length function is not a number."); } - if (not precision.is_number()) { throw std::runtime_error("Argument in length function is not a number."); } + if (not number.is_number()) { throw std::runtime_error("Argument in round function is not a number."); } + if (not precision.is_number()) { throw std::runtime_error("Argument in round function is not a number."); } return std::round(number.get() * std::pow(10.0, precision.get())) / std::pow(10.0, precision.get()); } } - + std::string input_copy = input; if (input_copy[0] != '/') { input_copy.insert(0, "/"); } json::json_pointer ptr(input_copy); @@ -581,13 +581,13 @@ public: json data = load_json(filename_data); return render_template(filename, data); } - + void write(const std::string& filename, json data, const std::string& filename_out) { - + } - + void write(const std::string& filename, const std::string& filename_data, const std::string& filename_out) { - + } std::string load_file(const std::string& filename) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d4b1eed..01f63f1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,17 +5,24 @@ set(CATCH_INCLUDE_DIR "thirdparty/catch") add_library(Catch INTERFACE) target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR}) -set(UNITTEST_TARGET_NAME "inja_unit") +set(UNITTEST_TARGET_NAME inja_unit) file(GLOB TEST_SOURCES "src/*.cpp") add_executable(${UNITTEST_TARGET_NAME} ${TEST_SOURCES}) target_link_libraries(${UNITTEST_TARGET_NAME} Catch) target_include_directories(${UNITTEST_TARGET_NAME} PRIVATE "../src" "thirdparty/json") +# Copy test files to build directory +add_custom_command( + TARGET ${UNITTEST_TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/test/data + ${CMAKE_CURRENT_BINARY_DIR}/data) + ## ## Add tests to make ## add_test(NAME "${UNITTEST_TARGET_NAME}_default" - COMMAND ${UNITTEST_TARGET_NAME} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${UNITTEST_TARGET_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/test/src/unit-parser.cpp b/test/src/unit-parser.cpp index 5bb5b50..5d68314 100644 --- a/test/src/unit-parser.cpp +++ b/test/src/unit-parser.cpp @@ -216,6 +216,7 @@ TEST_CASE("Parse functions") { data["name"] = "Peter"; data["city"] = "New York"; data["names"] = {"Jeff", "Seb", "Peter", "Tom"}; + data["temperature"] = 25.6789; SECTION("Upper") { CHECK( env.eval_variable("upper(name)", data) == "PETER" ); @@ -238,4 +239,10 @@ TEST_CASE("Parse functions") { CHECK( env.eval_variable("length(names)", data) == 4 ); CHECK_THROWS_WITH( env.eval_variable("length(5)", data), "Argument in length function is not a list." ); } + + SECTION("Round") { + CHECK( env.eval_variable("round(4, 0)", data) == 4 ); + CHECK( env.eval_variable("round(temperature, 2)", data) == 25.68 ); + CHECK_THROWS_WITH( env.eval_variable("round(name, 2)", data), "Argument in round function is not a number." ); + } } diff --git a/test/src/unit-renderer.cpp b/test/src/unit-renderer.cpp index f6b2d3a..ae24c99 100644 --- a/test/src/unit-renderer.cpp +++ b/test/src/unit-renderer.cpp @@ -54,6 +54,30 @@ TEST_CASE("Renderer") { CHECK( env.render("{% if age != 28 %}Right{% else %}Wrong{% endif %}", data) == "Right" ); CHECK( env.render("{% if age >= 30 %}Right{% else %}Wrong{% endif %}", data) == "Wrong" ); CHECK( env.render("{% if age in [28, 29, 30] %}True{% endif %}", data) == "True" ); - // CHECK( env.render(R"({% if name in ["Simon", "Tom"] %}Test1{% else if name in ["Peter"] %}Test2{% else %}Test3{% endif %})", data) == "Test2" ); + } +} + +TEST_CASE("Renderer other syntax") { + json data; + data["name"] = "Peter"; + data["names"] = {"Jeff", "Seb"}; + + SECTION("Other expression syntax") { + inja::Environment env = inja::Environment(); + + CHECK( env.render("Hello {{ name }}!", data) == "Hello Peter!" ); + + env.setExpression("\\(&", "&\\)"); + + CHECK( env.render("Hello {{ name }}!", data) == "Hello {{ name }}!" ); + CHECK( env.render("Hello (& name &)!", data) == "Hello Peter!" ); + } + + SECTION("Other comment syntax") { + inja::Environment env = inja::Environment(); + env.setComment("\\(&", "&\\)"); + + CHECK( env.render("Hello {# Test #}", data) == "Hello {# Test #}" ); + CHECK( env.render("Hello (& Test &)", data) == "Hello " ); } }