return result;
}
+template<typename T>
+static value empty_value_fn(const func_args &) {
+ if constexpr (std::is_same_v<T, value_int>) {
+ return mk_val<T>(0);
+ } else if constexpr (std::is_same_v<T, value_float>) {
+ return mk_val<T>(0.0);
+ } else if constexpr (std::is_same_v<T, value_bool>) {
+ return mk_val<T>(false);
+ } else {
+ return mk_val<T>();
+ }
+}
template<typename T>
static value test_type_fn(const func_args & args) {
args.ensure_count(1);
JJ_DEBUG("test_type_fn: type=%s or %s result=%d", typeid(T).name(), typeid(U).name(), is_type ? 1 : 0);
return mk_val<value_bool>(is_type);
}
+template<typename T, typename U, typename V>
+static value test_type_fn(const func_args & args) {
+ args.ensure_count(1);
+ bool is_type = is_val<T>(args.get_pos(0)) || is_val<U>(args.get_pos(0)) || is_val<V>(args.get_pos(0));
+ JJ_DEBUG("test_type_fn: type=%s, %s or %s result=%d", typeid(T).name(), typeid(U).name(), typeid(V).name(), is_type ? 1 : 0);
+ return mk_val<value_bool>(is_type);
+}
template<value_compare_op op>
static value test_compare_fn(const func_args & args) {
args.ensure_count(2, 2);
{"test_is_integer", test_type_fn<value_int>},
{"test_is_float", test_type_fn<value_float>},
{"test_is_number", test_type_fn<value_int, value_float>},
- {"test_is_iterable", test_type_fn<value_array, value_string>},
- {"test_is_sequence", test_type_fn<value_array, value_string>},
+ {"test_is_iterable", test_type_fn<value_array, value_string, value_undefined>},
+ {"test_is_sequence", test_type_fn<value_array, value_string, value_undefined>},
{"test_is_mapping", test_type_fn<value_object>},
{"test_is_lower", [](const func_args & args) -> value {
args.ensure_vals<value_string>();
static const func_builtins builtins = {
{"default", default_value},
{"tojson", tojson},
- {"string", [](const func_args &) -> value { return mk_val<value_string>("None"); }}
+ {"string", [](const func_args &) -> value {
+ return mk_val<value_string>("None");
+ }},
+ {"safe", [](const func_args &) -> value {
+ return mk_val<value_string>("None");
+ }},
};
return builtins;
}
const func_builtins & value_undefined_t::get_builtins() const {
static const func_builtins builtins = {
{"default", default_value},
- {"tojson", [](const func_args & args) -> value {
- args.ensure_vals<value_undefined>();
- return mk_val<value_string>("null");
- }},
+ {"capitalize", empty_value_fn<value_string>},
+ {"first", empty_value_fn<value_undefined>},
+ {"items", empty_value_fn<value_array>},
+ {"join", empty_value_fn<value_string>},
+ {"last", empty_value_fn<value_undefined>},
+ {"length", empty_value_fn<value_int>},
+ {"list", empty_value_fn<value_array>},
+ {"lower", empty_value_fn<value_string>},
+ {"map", empty_value_fn<value_array>},
+ {"max", empty_value_fn<value_undefined>},
+ {"min", empty_value_fn<value_undefined>},
+ {"reject", empty_value_fn<value_array>},
+ {"rejectattr", empty_value_fn<value_array>},
+ {"replace", empty_value_fn<value_string>},
+ {"reverse", empty_value_fn<value_array>},
+ {"safe", empty_value_fn<value_string>},
+ {"select", empty_value_fn<value_array>},
+ {"selectattr", empty_value_fn<value_array>},
+ {"sort", empty_value_fn<value_array>},
+ {"string", empty_value_fn<value_string>},
+ {"strip", empty_value_fn<value_string>},
+ {"sum", empty_value_fn<value_int>},
+ {"title", empty_value_fn<value_string>},
+ {"truncate", empty_value_fn<value_string>},
+ {"unique", empty_value_fn<value_array>},
+ {"upper", empty_value_fn<value_string>},
+ {"wordcount", empty_value_fn<value_int>},
};
return builtins;
}
"empty"
);
+ test_template(t, "for undefined empty",
+ "{% for i in items %}{{ i }}{% else %}empty{% endfor %}",
+ json::object(),
+ "empty"
+ );
+
test_template(t, "nested for",
"{% for i in a %}{% for j in b %}{{ i }}{{ j }}{% endfor %}{% endfor %}",
{{"a", json::array({1, 2})}, {"b", json::array({"x", "y"})}},
{{"x", {{"a", 1}}}},
"yes"
);
+
+ test_template(t, "undefined is sequence",
+ "{{ 'yes' if x is sequence }}",
+ json::object(),
+ "yes"
+ );
+
+ test_template(t, "undefined is iterable",
+ "{{ 'yes' if x is iterable }}",
+ json::object(),
+ "yes"
+ );
}
static void test_string_methods(testing & t) {
{{"s", "banana"}},
"bXnXna"
);
+
+ test_template(t, "undefined|capitalize",
+ "{{ arr|capitalize }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|title",
+ "{{ arr|title }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|truncate",
+ "{{ arr|truncate(9) }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|upper",
+ "{{ arr|upper }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|lower",
+ "{{ arr|lower }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|replace",
+ "{{ arr|replace('a', 'b') }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|trim",
+ "{{ arr|trim }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|wordcount",
+ "{{ arr|wordcount }}",
+ json::object(),
+ "0"
+ );
}
static void test_array_methods(testing & t) {
// {{"arr", json::array({"a", "b", "c"})}},
// "a,x,b,c"
// );
+
+ test_template(t, "undefined|select",
+ "{% for item in items|select('odd') %}{{ item.name }} {% endfor %}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|selectattr",
+ "{% for item in items|selectattr('active') %}{{ item.name }} {% endfor %}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|reject",
+ "{% for item in items|reject('even') %}{{ item.name }} {% endfor %}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|rejectattr",
+ "{% for item in items|rejectattr('active') %}{{ item.name }} {% endfor %}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|list",
+ "{{ arr|list|string }}",
+ json::object(),
+ "[]"
+ );
+
+ test_template(t, "undefined|string",
+ "{{ arr|string }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|first",
+ "{{ arr|first }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|last",
+ "{{ arr|last }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|length",
+ "{{ arr|length }}",
+ json::object(),
+ "0"
+ );
+
+ test_template(t, "undefined|join",
+ "{{ arr|join }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|sort",
+ "{{ arr|sort|string }}",
+ json::object(),
+ "[]"
+ );
+
+ test_template(t, "undefined|reverse",
+ "{{ arr|reverse|join }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|map",
+ "{% for v in arr|map(attribute='age') %}{{ v }} {% endfor %}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|min",
+ "{{ arr|min }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|max",
+ "{{ arr|max }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|unique",
+ "{{ arr|unique|join }}",
+ json::object(),
+ ""
+ );
+
+ test_template(t, "undefined|sum",
+ "{{ arr|sum }}",
+ json::object(),
+ "0"
+ );
}
static void test_object_methods(testing & t) {
json::object(),
"True"
);
+
+ test_template(t, "undefined|items",
+ "{{ arr|items|join }}",
+ json::object(),
+ ""
+ );
}
static void test_hasher(testing & t) {