8000 Implement 'map' filter · jinja2cpp/Jinja2Cpp@ab147e2 · GitHub
[go: up one dir, main page]

Skip to content

Commit ab147e2

Browse files
committed
Implement 'map' filter
1 parent 27230f9 commit ab147e2

File tree

5 files changed

+121
-69
lines changed

5 files changed

+121
-69
lines changed

src/expression_evaluator.cpp

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

15-
std::unordered_map<std::string, ExpressionFilter::FilterFactoryFn> ExpressionFilter::s_filters = {
16-
{"attr", &FilterFactory<filters::Attribute>::Create},
17-
{"batch", FilterFactory<filters::Slice>::MakeCreator(filters::Slice::BatchMode)},
18-
{"camelize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::CamelMode)},
19-
{"capitalize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::CapitalMode)},
20-
{"default", &FilterFactory<filters::Default>::Create},
21-
{"d", &FilterFactory<filters::Default>::Create},
22-
{"dictsort", &FilterFactory<filters::DictSort>::Create},
23-
{"escape", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::EscapeHtmlMode)},
24-
{"escapecpp", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::EscapeCppMode)},
25-
{"first", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::FirstItemMode)},
26-
{"float", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToFloatMode)},
27-
{"format", FilterFactory<filters::StringFormat>::MakeCreator(filters::StringFormat::PythonMode)},
28-
{"groupby", &FilterFactory<filters::GroupBy>::Create},
29-
{"int", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToIntMode)},
30-
{"join", &FilterFactory<filters::Join>::Create},
31-
{"last", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::LastItemMode)},
32-
{"length", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::LengthMode)},
33-
{"list", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToListMode)},
34-
{"map", &FilterFactory<filters::Map>::Create},
35-
{"max", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::MaxItemMode)},
36-
{"min", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::MinItemMode)},
37-
{"pprint", &FilterFactory<filters::PrettyPrint>::Create},
38-
{"random", &FilterFactory<filters::Random>::Create},
39-
{"reject", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::RejectMode)},
40-
{"rejectattr", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::RejectAttrMode)},
41-
{"replace", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::ReplaceMode)},
42-
{"round", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::RoundMode)},
43-
{"reverse", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::ReverseMode)},
44-
{"select", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::SelectMode)},
45-
{"selectattr", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::SelectAttrMode)},
46-
{"slice", FilterFactory<filters::Slice>::MakeCreator(filters::Slice::SliceMode)},
47-
{"sort", &FilterFactory<filters::Sort>::Create},
48-
{"sum", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::SumItemsMode)},
49-
{"title", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TitleMode)},
50-
{"tojson", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::JsonMode)},
51-
{"toxml", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::XmlMode)},
52-
{"toyaml", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::YamlMode)},
53-
{"trim", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TrimMode)},
54-
{"truncate", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TruncateMode)},
55-
{"unique", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::UniqueItemsMode)},
56-
{"upper", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::UpperMode)},
57-
{"wordcount", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::WordCountMode)},
58-
{"wordwrap", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::WordWrapMode)},
59-
{"underscorize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::UnderscoreMode)},};
60-
6115
std::unordered_map<std::string, IsExpression::TesterFactoryFn> IsExpression::s_testers = {
6216
{"defined", &TesterFactory<testers::Defined>::Create},
6317
{"startsWith", &TesterFactory<testers::StartsWith>::Create},
@@ -156,11 +110,9 @@ InternalValue DictCreator::Evaluate(RenderContext& context)
156110

157111
ExpressionFilter::ExpressionFilter(std::string filterName, CallParams params)
158112
{
159-
auto p = s_filters.find(filterName);
160-
if (p == s_filters.end())
113+
m_filter = CreateFilter(std::move(filterName), std::move(params));
114+
if (!m_filter)
161115
throw std::runtime_error("Can't find filter '" + filterName + "'");
162-
163-
m_filter = p->second(std::move(params));
164116
}
165117

166118
InternalValue ExpressionFilter::Evaluate(const InternalValue& baseVal, RenderContext& context)

src/expression_evaluator.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,6 @@ class ExpressionFilter
298298
private:
299299
std::shared_ptr<IExpressionFilter> m_filter;
300300
std::shared_ptr<ExpressionFilter> m_parentFilter;
301-
302-
static std::unordered_map<std::string, FilterFactoryFn> s_filters;
303301
};
304302

305303

src/filters.cpp

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,77 @@
77

88
namespace jinja2
99
{
10+
11+
template<typename F>
12+
struct FilterFactory
13+
{
14+
static FilterPtr Create(FilterParams params)
15+
{
16+
return std::make_shared<F>(std::move(params));
17+
}
18+
19+
template<typename ... Args>
20+
static ExpressionFilter::FilterFactoryFn MakeCreator(Args&& ... args)
21+
{
22+
return [args...](FilterParams params) {return std::make_shared<F>(std::move(params), args...);};
23+
}
24+
};
25+
26+
std::unordered_map<std::string, ExpressionFilter::FilterFactoryFn> s_filters = {
27+
{"attr", &FilterFactory<filters::Attribute>::Create},
28+
{"batch", FilterFactory<filters::Slice>::MakeCreator(filters::Slice::BatchMode)},
29+
{"camelize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::CamelMode)},
30+
{"capitalize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::CapitalMode)},
31+
{"default", &FilterFactory<filters::Default>::Create},
32+
{"d", &FilterFactory<filters::Default>::Create},
33+
{"dictsort", &FilterFactory<filters::DictSort>::Create},
34+
{"escape", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::EscapeHtmlMode)},
35+
{"escapecpp", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::EscapeCppMode)},
36+
{"first", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::FirstItemMode)},
37+
{"float", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToFloatMode)},
38+
{"format", FilterFactory<filters::StringFormat>::MakeCreator(filters::StringFormat::PythonMode)},
39+
{"groupby", &FilterFactory<filters::GroupBy>::Create},
40+
{"int", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToIntMode)},
41+
{"join", &FilterFactory<filters::Join>::Create},
42+
{"last", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::LastItemMode)},
43+
{"length", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::LengthMode)},
44+
{"list", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToListMode)},
45+
{"map", &FilterFactory<filters::Map>::Create},
46+
{"max", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::MaxItemMode)},
47+
{"min", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::MinItemMode)},
48+
{"pprint", &FilterFactory<filters::PrettyPrint>::Create},
49+
{"random", &FilterFactory<filters::Random>::Create},
50+
{"reject", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::RejectMode)},
51+
{"rejectattr", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::RejectAttrMode)},
52+
{"replace", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::ReplaceMode)},
53+
{"round", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::RoundMode)},
54+
{"reverse", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::ReverseMode)},
55+
{"select", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::SelectMode)},
56+
{"selectattr", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::SelectAttrMode)},
57+
{"slice", FilterFactory<filters::Slice>::MakeCreator(filters::Slice::SliceMode)},
58+
{"sort", &FilterFactory<filters::Sort>::Create},
59+
{"sum", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::SumItemsMode)},
60+
{"title", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TitleMode)},
61+
{"tojson", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::JsonMode)},
62+
{"toxml", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::XmlMode)},
63+
{"toyaml", FilterFactory<filters:: 10000 Serialize>::MakeCreator(filters::Serialize::YamlMode)},
64+
{"trim", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TrimMode)},
65+
{"truncate", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TruncateMode)},
66+
{"unique", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::UniqueItemsMode)},
67+
{"upper", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::UpperMode)},
68+
{"wordcount", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::WordCountMode)},
69+
{"wordwrap", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::WordWrapMode)},
70+
{"underscorize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::UnderscoreMode)},};
71+
72+
extern FilterPtr CreateFilter(std::string filterName, CallParams params)
73+
{
74+
auto p = s_filters.find(filterName);
75+
if (p == s_filters.end())
76+
return FilterPtr();
77+
78+
return p->second(std::move(params));
79+
}
80+
1081
namespace filters
1182
{
1283

@@ -142,12 +213,43 @@ InternalValue GroupBy::Filter(const InternalValue& baseVal, RenderContext& conte
142213

143214
Map::Map(FilterParams params)
144215
{
216+
FilterParams newParams;
217+
218+
if (params.kwParams.size() == 1 && params.posParams.empty() && params.kwParams.count("attribute") == 1)
219+
{
220+
newParams.kwParams["name"] = params.kwParams["attribute"];
221+
newParams.kwParams["filter"] = std::make_shared<ConstantExpression>(std::string("attr"));
222+
}
223+
else
224+
{
225+
newParams = std::move(params);
226+
}
145227

228+
ParseParams({{"filter", true}}, newParams);
229+
m_mappingParams.kwParams = m_args.extraKwArgs;
230+
m_mappingParams.posParams = m_args.extraPosArgs;
146231
}
147232

148233
InternalValue Map::Filter(const InternalValue& baseVal, RenderContext& context)
149234
{
150-
return InternalValue();
235+
InternalValue filterName = GetArgumentValue("filter", context);
236+
if (IsEmpty(filterName))
237+
return InternalValue();
238+
239+
auto filter = CreateFilter(AsString(filterName), m_mappingParams);
240+
if (!filter)
241+
return InternalValue();
242+
243+
bool isConverted = false;
244+
auto list = ConvertToList(baseVal, isConverted);
245+
if (!isConverted)
246+
return InternalValue();
247+
248+
InternalValueList resultList;
249+
resultList.reserve(list.GetSize());
250+
std::transform(list.begin(), list.end(), std::back_inserter(resultList), [filter, &context](auto& val) {return filter->Filter(val, context);});
251+
252+
return ListAdapter::CreateAdapter(std::move(resultList));
151253
}
152254

153255
PrettyPrint::PrettyPrint(FilterParams params)

src/filters.h

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,7 @@ namespace jinja2
1313
using FilterPtr = std::shared_ptr<ExpressionFilter::IExpressionFilter>;
1414
using FilterParams = CallParams;
1515

16-
template<typename F>
17-
struct FilterFactory
18-
{
19-
static FilterPtr Create(FilterParams params)
20-
{
21-
return std::make_shared<F>(std::move(params));
22-
}
23-
24-
template<typename ... Args>
25-
static ExpressionFilter::FilterFactoryFn MakeCreator(Args&& ... args)
26-
{
27-
return [args...](FilterParams params) {return std::make_shared<F>(std::move(params), args...);};
28-
}
29-
};
16+
extern FilterPtr CreateFilter(std::string filterName, CallParams params);
3017

3118
namespace filters
3219
{
@@ -87,6 +74,9 @@ class Map : public FilterBase
8774
Map(FilterParams params);
8875

8976
InternalValue Filter(const InternalValue& baseVal, RenderContext& context);
77+
78+
private:
79+
FilterParams m_mappingParams;
9080
};
9181

9282
class PrettyPrint : public FilterBase

test/filters_test.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,9 @@ INSTANTIATE_TEST_CASE_P(Unique, ListIteratorTest, ::testing::Values(
146146
InputOutputPair{"['Str2', 'str2', 'str3'] | unique", "Str2, str3"},
147147
InputOutputPair{"['Str2', 'str1', 'str3'] | unique(case_sensitive=true)", "Str2, str1, str3"},
148148
InputOutputPair{"[3, 1, 2] | unique", "3, 1, 2"},
149-
InputOutputPair{"[3.0, 3, 1] | unique", "3, 1"}
150-
// InputOutputPair{"reflectedList | unique(attribute='strValue')", "test string 0test string 1test string 2test string 3test string 4test string 5test string 6test string 7test string 8test string 9"}
149+
InputOutputPair{"[3.0, 3, 1] | unique", "3, 1"},
150+
InputOutputPair{"reflectedList | unique(attribute='strValue') | map(attribute='strValue')",
151+
"test string 0, test string 1, test string 2, test string 3, test string 4, test string 5, test string 6, test string 7, test string 8, test string 9"}
151152
));
152153

153154
INSTANTIATE_TEST_CASE_P(Attr, FilterGenericTest, ::testing::Values(
@@ -160,3 +161,12 @@ INSTANTIATE_TEST_CASE_P(Attr, FilterGenericTest, ::testing::Values(
160161
InputOutputPair{"filledReflectedPtrVal | attr('strValue')", "test string 0"}
161162
));
162163

164+
INSTANTIATE_TEST_CASE_P(Map, ListIteratorTest, ::testing::Values(
165+
InputOutputPair{"reflectedList | map(attribute='intValue')", "0, 1, 2, 3, 4, 5, 6, 7, 8, 9"},
166+
InputOutputPair{"[[0, 1], [1, 2], [2, 3], [3, 4]] | map('first')", "0, 1, 2, 3"},
167+
InputOutputPair{"[['str1', 'Str2'], ['str2', 'Str3'], ['str3', 'Str4'], ['str4', 'Str5']] | map('min')",
168+
"str1, str2, str3, str4"},
169+
InputOutputPair{"[['str1', 'Str2'], ['str2', 'Str3'], ['str3', 'Str4'], ['str4', 'Str5']] | map('min', case_sensitive=true)",
170+
"Str2, Str3, Str4, Str5"}
171+
));
172+

0 commit comments

Comments
 (0)
0