add join function (#204)
* add join function
* fix formatting to match single include
* add join test
* add join to documentation
* fix MSVC warning: signed/unsigned mismatch
Co-authored-by: Wim Leflere <wleflere@cochlear.com>
diff --git a/README.md b/README.md
index 92e45ad..0bf6de5 100644
--- a/README.md
+++ b/README.md
@@ -224,6 +224,10 @@
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
diff --git a/include/inja/function_storage.hpp b/include/inja/function_storage.hpp
index 1b6070b..b4bd092 100644
--- a/include/inja/function_storage.hpp
+++ b/include/inja/function_storage.hpp
@@ -65,6 +65,7 @@
Sort,
Upper,
Super,
+ Join,
Callback,
ParenLeft,
ParenRight,
@@ -109,6 +110,7 @@
{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 d33cb46..ef951b9 100644
--- a/include/inja/renderer.hpp
+++ b/include/inja/renderer.hpp
@@ -528,6 +528,24 @@
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::string>();
+ std::ostringstream os;
+ std::string sep;
+ for (const auto& value : *args[0]) {
+ os << sep;
+ if (value.is_string()) {
+ os << value.get<std::string>(); // otherwise the value is surrounded with ""
+ } else {
+ os << value;
+ }
+ sep = separator;
+ }
+ result_ptr = std::make_shared<json>(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 7fca9f3..03e19a0 100644
--- a/single_include/inja/inja.hpp
+++ b/single_include/inja/inja.hpp
@@ -1602,6 +1602,7 @@
Sort,
Upper,
Super,
+ Join,
Callback,
ParenLeft,
ParenRight,
@@ -1646,6 +1647,7 @@
{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:
@@ -4022,6 +4024,24 @@
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::string>();
+ std::ostringstream os;
+ std::string sep;
+ for (const auto& value : *args[0]) {
+ os << sep;
+ if (value.is_string()) {
+ os << value.get<std::string>(); // otherwise the value is surrounded with ""
+ } else {
+ os << value;
+ }
+ sep = separator;
+ }
+ result_ptr = std::make_shared<json>(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/test/test-functions.cpp b/test/test-functions.cpp
index e0f3a6e..4ec4c25 100644
--- a/test/test-functions.cpp
+++ b/test/test-functions.cpp
@@ -174,6 +174,11 @@
"[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");