Add exists() function that checks existence of key (#38)

* Add exists() function that checks existence of key

Adds an exists() function that checks whether a given key exists in the
data. If only one argument is provided to exists(), the global data is
queried for the item. If two arguments are given, the first argument
specifies the object to query for the key given as second argument.

Also adds corresponding unit tests and updates README for
documentation.

* Split exists() into exists() and existsIn()

Splits the exists() function, which previously took both one or two
arguments, into an exists() function accepting one and an existsIn()
function accepting two arguments.
This commit is contained in:
Samuel Leweke
2018-04-02 15:54:00 +02:00
committed by pantor
parent 138e0da339
commit 1cb6b15cca
4 changed files with 40 additions and 0 deletions
+6
View File
@@ -200,6 +200,12 @@ render("{{ float(\"1.8\") > 2 }}", data); // false
// Set default values if variables are not defined
render("Hello {{ default(neighbour, \"my friend\") }}!", data); // "Hello Peter!"
render("Hello {{ default(colleague, \"my friend\") }}!", data); // "Hello my friend!"
// Check if a key exists in an object
render("{{ exists(\"guests\") }}", data); // "true"
render("{{ exists(\"city\") }}", data); // "false"
render("{{ existsIn(time, \"start\") }}", data); // "true"
render("{{ existsIn(time, neighbour) }}", data); // "false"
```
### Callbacks
+13
View File
@@ -279,6 +279,8 @@ struct Parsed {
Sort,
Upper,
ReadJson,
Exists,
ExistsInObject,
Default
};
@@ -513,6 +515,15 @@ public:
Parsed::CallbackSignature signature = std::make_pair(element.command, element.args.size());
return map_callbacks.at(signature)(element.args, data);
}
case Parsed::Function::Exists: {
const std::string name = eval_expression<std::string>(element.args[0], data);
return data.find(name) != data.end();
}
case Parsed::Function::ExistsInObject: {
const std::string name = eval_expression<std::string>(element.args[1], data);
const json d = eval_expression(element.args[0], data);
return d.find(name) != d.end();
}
}
inja_throw("render_error", "unknown function in renderer: " + element.command);
@@ -688,6 +699,8 @@ public:
{Parsed::Function::Round, function_regex("round", 2)},
{Parsed::Function::Sort, function_regex("sort", 1)},
{Parsed::Function::Upper, function_regex("upper", 1)},
{Parsed::Function::Exists, function_regex("exists", 1)},
{Parsed::Function::ExistsInObject, function_regex("existsIn", 2)},
{Parsed::Function::ReadJson, Regex{"\\s*([^\\(\\)]*\\S)\\s*"}}
};
+19
View File
@@ -104,6 +104,9 @@ TEST_CASE("functions") {
data["city"] = "New York";
data["names"] = {"Jeff", "Seb", "Peter", "Tom"};
data["temperature"] = 25.6789;
data["brother"]["name"] = "Chris";
data["brother"]["daughters"] = {"Maria", "Helen"};
data["property"] = "name";
SECTION("upper") {
CHECK( env.render("{{ upper(name) }}", data) == "PETER" );
@@ -203,6 +206,22 @@ TEST_CASE("functions") {
CHECK( env.render("{{ default(surname, \"nobody\") }}", data) == "nobody" );
CHECK_THROWS_WITH( env.render("{{ default(surname, lastname) }}", data), "[inja.exception.render_error] variable '/lastname' not found" );
}
SECTION("exists") {
CHECK( env.render("{{ exists(\"name\") }}", data) == "true" );
CHECK( env.render("{{ exists(\"zipcode\") }}", data) == "false" );
CHECK( env.render("{{ exists(name) }}", data) == "false" );
CHECK( env.render("{{ exists(property) }}", data) == "true" );
}
SECTION("existsIn") {
CHECK( env.render("{{ existsIn(brother, \"name\") }}", data) == "true" );
CHECK( env.render("{{ existsIn(brother, \"parents\") }}", data) == "false" );
CHECK( env.render("{{ existsIn(brother, property) }}", data) == "true" );
CHECK( env.render("{{ existsIn(brother, name) }}", data) == "false" );
CHECK_THROWS_WITH( env.render("{{ existsIn(sister, \"lastname\") }}", data), "[inja.exception.render_error] variable '/sister' not found" );
CHECK_THROWS_WITH( env.render("{{ existsIn(brother, sister) }}", data), "[inja.exception.render_error] variable '/sister' not found" );
}
}
TEST_CASE("callbacks") {
+2
View File
@@ -155,6 +155,8 @@ TEST_CASE("match-functions") {
CHECK( inja::match(" upper(lower()) ", map_regex).type() == inja::Parsed::Function::Upper );
CHECK( inja::match("lower(upper(test))", map_regex).type() == inja::Parsed::Function::Lower );
CHECK( inja::match("round(2, 3)", map_regex).type() == inja::Parsed::Function::Round );
CHECK( inja::match("exists(\"var\")", map_regex).type() == inja::Parsed::Function::Exists );
CHECK( inja::match("existsIn(var, \"othervar\")", map_regex).type() == inja::Parsed::Function::ExistsInObject );
}
TEST_CASE("create-regex-functions") {