From 04abfa53fe39ed44df87c1409fcb11bd1ec9c298 Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Fri, 6 Dec 2024 19:30:02 +0000 Subject: [PATCH 1/3] Support array concat w/ + --- include/minja/minja.hpp | 12 +++++++++--- tests/test-syntax.cpp | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/minja/minja.hpp b/include/minja/minja.hpp index 66bf536..8033941 100644 --- a/include/minja/minja.hpp +++ b/include/minja/minja.hpp @@ -433,12 +433,18 @@ class Value : public std::enable_shared_from_this { return dump(); } Value operator+(const Value& rhs) const { - if (is_string() || rhs.is_string()) + if (is_string() || rhs.is_string()) { return to_str() + rhs.to_str(); - else if (is_number_integer() && rhs.is_number_integer()) + } else if (is_number_integer() && rhs.is_number_integer()) { return get() + rhs.get(); - else + } else if (is_array() && rhs.is_array()) { + auto res = Value::array(); + for (const auto& item : *array_) res.push_back(item); + for (const auto& item : *rhs.array_) res.push_back(item); + return res; + } else { return get() + rhs.get(); + } } Value operator-(const Value& rhs) const { if (is_number_integer() && rhs.is_number_integer()) diff --git a/tests/test-syntax.cpp b/tests/test-syntax.cpp index ddb2e7c..4c7451c 100644 --- a/tests/test-syntax.cpp +++ b/tests/test-syntax.cpp @@ -49,7 +49,9 @@ TEST(SyntaxTest, SimpleCases) { EXPECT_EQ( "abc", render("{% filter trim %} abc {% endfilter %}", {}, {})); - + EXPECT_EQ( + "[1, 2, 3]", + render("{{ [1] + [2, 3] }}", {}, {})); EXPECT_EQ( "a\n b\n| a\n b\n", render("{% set txt = 'a\\nb\\n' %}{{ txt | indent(2) }}|{{ txt | indent(2, first=true) }}", {}, {})); From 0c9ebbac8ada0e813ebeea8cf4ed4190db00b6fe Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Fri, 6 Dec 2024 19:30:21 +0000 Subject: [PATCH 2/3] Support `default` filter --- include/minja/minja.hpp | 15 +++++++++++++++ tests/test-syntax.cpp | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/include/minja/minja.hpp b/include/minja/minja.hpp index 8033941..b9746b7 100644 --- a/include/minja/minja.hpp +++ b/include/minja/minja.hpp @@ -2401,6 +2401,21 @@ inline std::shared_ptr Context::builtins() { auto & text = args.at("text"); return text.is_null() ? text : Value(strip(text.get())); })); + globals.set("default", Value::callable([=](const std::shared_ptr &, Value::Arguments & args) { + args.expectArgs("default", {2, 3}, {0, 1}); + auto & value = args.args[0]; + auto & default_value = args.args[1]; + bool boolean = false; + if (args.args.size() == 3) { + boolean = args.args[2].get(); + } else { + Value bv = args.get_named("boolean"); + if (!bv.is_null()) { + boolean = bv.get(); + } + } + return boolean ? (value.to_bool() ? value : default_value) : value.is_null() ? default_value : value; + })); auto escape = simple_function("escape", { "text" }, [](const std::shared_ptr &, Value & args) { return Value(html_escape(args.at("text").get())); }); diff --git a/tests/test-syntax.cpp b/tests/test-syntax.cpp index 4c7451c..eb8b60d 100644 --- a/tests/test-syntax.cpp +++ b/tests/test-syntax.cpp @@ -52,6 +52,12 @@ TEST(SyntaxTest, SimpleCases) { EXPECT_EQ( "[1, 2, 3]", render("{{ [1] + [2, 3] }}", {}, {})); + EXPECT_EQ( + "the default1", + render("{{ foo | default('the default') }}{{ 1 | default('nope') }}", {}, {})); + EXPECT_EQ( + "the default1", + render("{{ '' | default('the default', true) }}{{ 1 | default('nope', true) }}", {}, {})); EXPECT_EQ( "a\n b\n| a\n b\n", render("{% set txt = 'a\\nb\\n' %}{{ txt | indent(2) }}|{{ txt | indent(2, first=true) }}", {}, {})); From c1a6f2b6c0427c5943ec030f866b517805be3f66 Mon Sep 17 00:00:00 2001 From: Olivier Chafik Date: Fri, 6 Dec 2024 19:31:01 +0000 Subject: [PATCH 3/3] Support `lower` filter --- include/minja/minja.hpp | 8 ++++++++ tests/test-syntax.cpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/include/minja/minja.hpp b/include/minja/minja.hpp index b9746b7..db08506 100644 --- a/include/minja/minja.hpp +++ b/include/minja/minja.hpp @@ -2401,6 +2401,14 @@ inline std::shared_ptr Context::builtins() { auto & text = args.at("text"); return text.is_null() ? text : Value(strip(text.get())); })); + globals.set("lower", simple_function("lower", { "text" }, [](const std::shared_ptr &, Value & args) { + auto text = args.at("text"); + if (text.is_null()) return text; + std::string res; + auto str = text.get(); + std::transform(str.begin(), str.end(), std::back_inserter(res), ::tolower); + return Value(res); + })); globals.set("default", Value::callable([=](const std::shared_ptr &, Value::Arguments & args) { args.expectArgs("default", {2, 3}, {0, 1}); auto & value = args.args[0]; diff --git a/tests/test-syntax.cpp b/tests/test-syntax.cpp index eb8b60d..5fdb74e 100644 --- a/tests/test-syntax.cpp +++ b/tests/test-syntax.cpp @@ -52,6 +52,9 @@ TEST(SyntaxTest, SimpleCases) { EXPECT_EQ( "[1, 2, 3]", render("{{ [1] + [2, 3] }}", {}, {})); + EXPECT_EQ( + "abc", + render("{{ 'AbC' | lower }}", {}, {})); EXPECT_EQ( "the default1", render("{{ foo | default('the default') }}{{ 1 | default('nope') }}", {}, {}));