10000 Implement 'reject', 'rejectattr', 'select' and 'selectattr' filters · jinja2cpp/Jinja2Cpp@8763669 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8763669

Browse files
committed
Implement 'reject', 'rejectattr', 'select' and 'selectattr' filters
1 parent e8eab9e commit 8763669

File tree

7 files changed

+116
-19
lines changed

7 files changed

+116
-19
lines changed

src/expression_evaluator.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@
1212
namespace jinja2
1313
{
1414

15-
std::unordered_map<std::string, IsExpression::TesterFactoryFn> IsExpression::s_testers = {
16-
{"defined", &TesterFactory<testers::Defined>::Create},
17-
{"startsWith", &TesterFactory<testers::StartsWith>::Create},
18-
};
19-
2015
InternalValue FullExpressionEvaluator::Evaluate(RenderContext& values)
2116
{
2217
if (!m_expression)
@@ -126,11 +121,9 @@ InternalValue ExpressionFilter::Evaluate(const InternalValue& baseVal, RenderCon
126121
IsExpression::IsExpression(ExpressionEvaluatorPtr<> value, std::string tester, CallParams params)
127122
: m_value(value)
128123
{
129-
auto p = s_testers.find(tester);
130-
if (p == s_testers.end())
124+
m_tester = CreateTester(std::move(tester), std::move(params));
125+
if (!m_tester)
131126
throw std::runtime_error("Can't find tester '" + tester + "'");
132-
133-
m_tester = p->second(std::move(params));
134127
}
135128

136129
InternalValue IsExpression::Evaluate(RenderContext& context)

src/expression_evaluator.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ class IsExpression : public Expression
247247
private:
248248
ExpressionEvaluatorPtr<> m_value;
249249
std::shared_ptr<ITester> m_tester;
250-
static std::unordered_map<std::string, TesterFactoryFn> s_testers;
251250
};
252251

253252
class CallExpression : public Expression

src/filters.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "filters.h"
2+
#include "testers.h"
23
#include "value_visitors.h"
34
#include "value_helpers.h"
45

@@ -482,13 +483,64 @@ InternalValue StringFormat::Filter(const InternalValue& baseVal, RenderContext&
482483
}
483484

484485
Tester::Tester(FilterParams params, Tester::Mode mode)
486+
: m_mode(mode)
485487
{
488+
FilterParams newParams;
489+
490+
if ((mode == RejectMode || mode == SelectMode) && params.kwParams.empty() && params.posParams.empty())
491+
{
492+
m_noParams = true;
493+
return;
494+
}
495+
496+
if (mode == RejectMode || mode == SelectMode)
497+
ParseParams({{"tester", false}}, params);
498+
else
499+
ParseParams({{"attribute", true}, {"tester", false}}, params);
486500

501+
m_testingParams.kwParams = std::move(m_args.extraKwArgs);
502+
m_testingParams.posParams = std::move(m_args.extraPosArgs);
487503
}
488504

489505
InternalValue Tester::Filter(const InternalValue& baseVal, RenderContext& context)
490506
{
491-
return InternalValue();
507+
InternalValue testerName = GetArgumentValue("tester", context);
508+
InternalValue attrName = GetArgumentValue("attribute", context);
509+
510+
TesterPtr tester;
511+
512+
if (!IsEmpty(testerName))
513+
{
514+
tester = CreateTester(AsString(testerName), m_testingParams);
515+
516+
if (!tester)
517+
return InternalValue();
518+
}
519+
520+
bool isConverted = false;
521+
auto list = ConvertToList(baseVal, isConverted);
522+
if (!isConverted)
523+
return InternalValue();
524+
525+
InternalValueList resultList;
526+
resultList.reserve(list.GetSize());
527+
std::copy_if(list.begin(), list.end(), std::back_inserter(resultList), [this, tester, attrName, &context](auto& val)
528+
{
529+
InternalValue attrVal;
530+
bool isAttr = !IsEmpty(attrName);
531+
if (isAttr)
532+
attrVal = Subscript(val, attrName);
533+
534+
bool result = false;
535+
if (tester)
536+
result = tester->Test(isAttr ? attrVal : val, context);
537+
else
538+
result = ConvertToBool(isAttr ? attrVal : val);
539+
540+
return (m_mode == SelectMode || m_mode == SelectAttrMode) ? result : !result;
541+
});
542+
543+
return ListAdapter::CreateAdapter(std::move(resultList));
492544
}
493545

494546
ValueConverter::ValueConverter(FilterParams params, ValueConverter::Mode mode)

src/filters.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,11 @@ class Tester : public FilterBase
207207
Tester(FilterParams params, Mode mode);
208208

209209
InternalValue Filter(const InternalValue& baseVal, RenderContext& context);
210+
211+
private:
212+
Mode m_mode;
213+
CallParams m_testingParams;
214+
bool m_noParams = false;
210215
};
211216

212217
class ValueConverter : public FilterBase

src/testers.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@
33

44
namespace jinja2
55
{
6+
7+
template<typename F>
8+
struct TesterFactory
9+
{
10+
static TesterPtr Create(TesterParams params)
11+
{
12+
return std::make_shared<F>(std::move(params));
13+
}
14+
};
15+
16+
std::unordered_map<std::string, IsExpression::TesterFactoryFn> s_testers = {
17+
{"defined", &TesterFactory<testers::Defined>::Create},
18+
{"startsWith", &TesterFactory<testers::StartsWith>::Create},
19+
};
20+
21+
TesterPtr CreateTester(std::string testerName, CallParams params)
22+
{
23+
auto p = s_testers.find(testerName);
24+
if (p == s_testers.end())
25+
TesterPtr();
26+
27+
return p->second(std::move(params));
28+
}
29+
630
namespace testers
731
{
832

src/testers.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,7 @@ namespace jinja2
1313
using TesterPtr = std::shared_ptr<IsExpression::ITester>;
1414
using TesterParams = CallParams;
1515

16-
template<typename F>
17-
struct TesterFactory
18-
{
19-
static TesterPtr Create(TesterParams params)
20-
{
21-
return std::make_shared<F>(std::move(params));
22-
}
23-
};
16+
extern TesterPtr CreateTester(std::string testerName, CallParams params);
2417

2518
namespace testers
2619
{

test/filters_test.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,34 @@ INSTANTIATE_TEST_CASE_P(Map, ListIteratorTest, ::testing::Values(
173173
"Str2, Str3, Str4, Str5"}
174174
));
175175

176+
177+
INSTANTIATE_TEST_CASE_P(Reject, ListIteratorTest, ::testing::Values(
178+
InputOutputPair{"['', 'str1', '', 'str2', '', 'str3', '', 'str4'] | reject", ", , , "},
179+
InputOutputPair{"['_str1', 'str1', '_str2', 'str2', '_str3', 'str3', '_str4', 'str4'] | reject('startsWith', '_')",
180+
"str1, str2, str3, str4"},
181+
InputOutputPair{"['_str1', 'str1', '_str2', 'str2', '_str3', 'str3', '_str4', 'str4'] | reject('startsWith', str='_')",
182+
"str1, str2, str3, str4"}
183+
));
184+
185+
INSTANTIATE_TEST_CASE_P(RejectAttr, ListIteratorTest, ::testing::Values(
186+
InputOutputPair{"reflectedList | rejectattr('boolValue') | map(attribute='strValue')",
187+
"test string 0, test string 2, test string 4, test string 6, test string 8"},
188+
InputOutputPair{"reflectedList | rejectattr(attribute='boolValue') | map(attribute='strValue')",
189+
"test string 0, test string 2, test string 4, test string 6, test string 8"}
190+
));
191+
192+
INSTANTIATE_TEST_CASE_P(Select, ListIteratorTest, ::testing::Values(
193+
InputOutputPair{"['', 'str1', '', 'str2', '', 'str3', '', 'str4'] | select", "str1, str2, str3, str4"},
194+
InputOutputPair{"['_str1', 'str1', '_str2', 'str2', '_str3', 'str3', '_str4', 'str4'] | select('startsWith', '_')",
195+
"_str1, _str2, _str3, _str4"},
196+
InputOutputPair{"['_str1', 'str1', '_str2', 'str2', '_str3', 'str3', '_str4', 'str4'] | select('startsWith', str='_')",
197+
"_str1, _str2, _str3, _str4"}
198+
));
199+
200+
INSTANTIATE_TEST_CASE_P(SelectAttr, ListIteratorTest, ::testing::Values(
201+
InputOutputPair{"reflectedList | selectattr('boolValue') | map(attribute='strValue')",
202+
"test string 1, test string 3, test string 5, test string 7, test string 9"},
203+
InputOutputPair{"reflectedList | selectattr(attribute='boolValue') | map(attribute='strValue')",
204+
"test string 1, test string 3, test string 5, test string 7, test string 9"}
205+
));
206+

0 commit comments

Comments
 (0)
0