From 528fa67e4edee7f21aca33dbd9429d910d90451d Mon Sep 17 00:00:00 2001 From: Wim Leflere Date: Wed, 16 Jun 2021 21:02:33 +0200 Subject: [PATCH 1/5] add join function --- include/inja/function_storage.hpp | 2 ++ include/inja/renderer.hpp | 18 ++++++++++++++++++ single_include/inja/inja.hpp | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/include/inja/function_storage.hpp b/include/inja/function_storage.hpp index 1b6070b7..b4bd092d 100644 --- a/include/inja/function_storage.hpp +++ b/include/inja/function_storage.hpp @@ -65,6 +65,7 @@ class FunctionStorage { Sort, Upper, Super, + Join, Callback, ParenLeft, ParenRight, @@ -109,6 +110,7 @@ class FunctionStorage { {std::make_pair("upper", 1), FunctionData { Operation::Upper }}, {std::make_pair("super", 0), FunctionData { Operation::Super }}, {std::make_pair("super", 1), FunctionData { Operation::Super }}, + {std::make_pair("join", 2), FunctionData { Operation::Join }}, }; public: diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp index d33cb468..f086fca2 100644 --- a/include/inja/renderer.hpp +++ b/include/inja/renderer.hpp @@ -528,6 +528,24 @@ class Renderer : public NodeVisitor { json_tmp_stack.push_back(result_ptr); json_eval_stack.push(result_ptr.get()); } break; + case Op::Join: { + const auto args = get_arguments<2>(node); + const auto separator = args[1]->get(); + std::ostringstream os; + std::string sep; + for (const auto &value : *args[0]) { + os << sep; + if (value.is_string()) { + os << value.get(); // otherwise the value is surrounded with "" + } else { + os << value; + } + sep = separator; + } + result_ptr = std::make_shared(os.str()); + json_tmp_stack.push_back(result_ptr); + json_eval_stack.push(result_ptr.get()); + } break; case Op::ParenLeft: case Op::ParenRight: case Op::None: diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp index e1625cfd..7cfc6b87 100644 --- a/single_include/inja/inja.hpp +++ b/single_include/inja/inja.hpp @@ -1598,6 +1598,7 @@ class FunctionStorage { Sort, Upper, Super, + Join, Callback, ParenLeft, ParenRight, @@ -1642,6 +1643,7 @@ class FunctionStorage { {std::make_pair("upper", 1), FunctionData { Operation::Upper }}, {std::make_pair("super", 0), FunctionData { Operation::Super }}, {std::make_pair("super", 1), FunctionData { Operation::Super }}, + {std::make_pair("join", 2), FunctionData { Operation::Join }}, }; public: @@ -4018,6 +4020,24 @@ class Renderer : public NodeVisitor { json_tmp_stack.push_back(result_ptr); json_eval_stack.push(result_ptr.get()); } break; + case Op::Join: { + const auto args = get_arguments<2>(node); + const auto separator = args[1]->get(); + std::ostringstream os; + std::string sep; + for (const auto& value : *args[0]) { + os << sep; + if (value.is_string()) { + os << value.get(); // otherwise the value is surrounded with "" + } else { + os << value; + } + sep = separator; + } + result_ptr = std::make_shared(os.str()); + json_tmp_stack.push_back(result_ptr); + json_eval_stack.push(result_ptr.get()); + } break; case Op::ParenLeft: case Op::ParenRight: case Op::None: From 34da074429880177854f6b970ae8a7db58108418 Mon Sep 17 00:00:00 2001 From: Wim Leflere Date: Thu, 17 Jun 2021 09:38:25 +0200 Subject: [PATCH 2/5] fix formatting to match single include --- include/inja/renderer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/inja/renderer.hpp b/include/inja/renderer.hpp index f086fca2..ef951b99 100644 --- a/include/inja/renderer.hpp +++ b/include/inja/renderer.hpp @@ -533,7 +533,7 @@ class Renderer : public NodeVisitor { const auto separator = args[1]->get(); std::ostringstream os; std::string sep; - for (const auto &value : *args[0]) { + for (const auto& value : *args[0]) { os << sep; if (value.is_string()) { os << value.get(); // otherwise the value is surrounded with "" From 190118b939a57fdc4e41a13c2568709a1e88d75c Mon Sep 17 00:00:00 2001 From: Wim Leflere Date: Thu, 17 Jun 2021 20:27:20 +0200 Subject: [PATCH 3/5] add join test --- test/test-functions.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test-functions.cpp b/test/test-functions.cpp index e920ff24..d9516bb0 100644 --- a/test/test-functions.cpp +++ b/test/test-functions.cpp @@ -174,6 +174,11 @@ TEST_CASE("functions") { "[inja.exception.render_error] (at 1:22) variable 'sister' not found"); } + SUBCASE("join") { + CHECK(env.render("{{ join(names, \" | \") }}", data) == "Jeff | Seb | Peter | Tom"); + CHECK(env.render("{{ join(vars, \", \") }}", data) == "2, 3, 4, 0, -1, -2, -3"); + } + SUBCASE("isType") { CHECK(env.render("{{ isBoolean(is_happy) }}", data) == "true"); CHECK(env.render("{{ isBoolean(vars) }}", data) == "false"); From cdf8b6c75ad08979e136b148129edf47cba1cfe1 Mon Sep 17 00:00:00 2001 From: Wim Leflere Date: Thu, 17 Jun 2021 20:40:31 +0200 Subject: [PATCH 4/5] add join to documentation --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 92e45ad1..0bf6de57 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,10 @@ render("{{ last(guests) }} was last.", data); // "Patir was last." render("{{ sort([3,2,1]) }}", data); // "[1,2,3]" render("{{ sort(guests) }}", data); // "[\"Jeff\", \"Patrick\", \"Tom\"]" +// Join a list with a separator +render("{{ join([1,2,3], \" + \") }}", data); // "1 + 2 + 3" +render("{{ join(guests, \", \") }}", data); // "Jeff, Patrick, Tom" + // Round numbers to a given precision render("{{ round(3.1415, 0) }}", data); // 3 render("{{ round(3.1415, 3) }}", data); // 3.142 From be7222878e72b139d9ec51ebf286c5f3c8799d13 Mon Sep 17 00:00:00 2001 From: Wim Leflere Date: Thu, 17 Jun 2021 20:47:02 +0200 Subject: [PATCH 5/5] fix MSVC warning: signed/unsigned mismatch --- include/inja/parser.hpp | 2 +- single_include/inja/inja.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/inja/parser.hpp b/include/inja/parser.hpp index a211d310..0c1f8671 100644 --- a/include/inja/parser.hpp +++ b/include/inja/parser.hpp @@ -81,7 +81,7 @@ class Parser { auto function = operator_stack.top(); operator_stack.pop(); - for (size_t i = 0; i < function->number_args; ++i) { + for (int i = 0; i < function->number_args; ++i) { function->arguments.insert(function->arguments.begin(), arguments.back()); arguments.pop_back(); } diff --git a/single_include/inja/inja.hpp b/single_include/inja/inja.hpp index 7cfc6b87..c985b792 100644 --- a/single_include/inja/inja.hpp +++ b/single_include/inja/inja.hpp @@ -2918,7 +2918,7 @@ class Parser { auto function = operator_stack.top(); operator_stack.pop(); - for (size_t i = 0; i < function->number_args; ++i) { + for (int i = 0; i < function->number_args; ++i) { function->arguments.insert(function->arguments.begin(), arguments.back()); arguments.pop_back(); }