diff --git a/README.md b/README.md index 7e3fac5..fd289a8 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,11 @@ render("{{ exists(\"guests\") }}", data); // "true" render("{{ exists(\"city\") }}", data); // "false" render("{{ existsIn(time, \"start\") }}", data); // "true" render("{{ existsIn(time, neighbour) }}", data); // "false" + +// Check if a key is a specific type +render("{{ isString(neighbour) }}", data); // "true" +render("{{ isArray(guests) }}", data); // "true" +// Implemented type checks: isArray, isBoolean, isFloat, isInteger, isNumber, isObject, isString, ``` ### Callbacks diff --git a/src/inja.hpp b/src/inja.hpp index b2ff1db..059e473 100644 --- a/src/inja.hpp +++ b/src/inja.hpp @@ -278,6 +278,13 @@ struct Parsed { ReadJson, Exists, ExistsInObject, + IsBoolean, + IsNumber, + IsInteger, + IsFloat, + IsObject, + IsArray, + IsString, Default }; @@ -521,6 +528,34 @@ public: const json d = eval_expression(element.args[0], data); return d.find(name) != d.end(); } + case Parsed::Function::IsBoolean: { + const json d = eval_expression(element.args[0], data); + return d.is_boolean(); + } + case Parsed::Function::IsNumber: { + const json d = eval_expression(element.args[0], data); + return d.is_number(); + } + case Parsed::Function::IsInteger: { + const json d = eval_expression(element.args[0], data); + return d.is_number_integer(); + } + case Parsed::Function::IsFloat: { + const json d = eval_expression(element.args[0], data); + return d.is_number_float(); + } + case Parsed::Function::IsObject: { + const json d = eval_expression(element.args[0], data); + return d.is_object(); + } + case Parsed::Function::IsArray: { + const json d = eval_expression(element.args[0], data); + return d.is_array(); + } + case Parsed::Function::IsString: { + const json d = eval_expression(element.args[0], data); + return d.is_string(); + } } inja_throw("render_error", "unknown function in renderer: " + element.command); @@ -699,6 +734,13 @@ public: {Parsed::Function::Upper, function_regex("upper", 1)}, {Parsed::Function::Exists, function_regex("exists", 1)}, {Parsed::Function::ExistsInObject, function_regex("existsIn", 2)}, + {Parsed::Function::IsBoolean, function_regex("isBoolean", 1)}, + {Parsed::Function::IsNumber, function_regex("isNumber", 1)}, + {Parsed::Function::IsInteger, function_regex("isInteger", 1)}, + {Parsed::Function::IsFloat, function_regex("isFloat", 1)}, + {Parsed::Function::IsObject, function_regex("isObject", 1)}, + {Parsed::Function::IsArray, function_regex("isArray", 1)}, + {Parsed::Function::IsString, function_regex("isString", 1)}, {Parsed::Function::ReadJson, Regex{"\\s*([^\\(\\)]*\\S)\\s*"}} }; diff --git a/test/src/unit-renderer.cpp b/test/src/unit-renderer.cpp index 57bf2a7..e0caa44 100644 --- a/test/src/unit-renderer.cpp +++ b/test/src/unit-renderer.cpp @@ -107,6 +107,10 @@ TEST_CASE("functions") { data["brother"]["name"] = "Chris"; data["brother"]["daughters"] = {"Maria", "Helen"}; data["property"] = "name"; + data["age"] = 29; + data["is_happy"] = true; + data["is_sad"] = false; + data["vars"] = {2, 3, 4, 0, -1, -2, -3}; SECTION("upper") { CHECK( env.render("{{ upper(name) }}", data) == "PETER" ); @@ -222,6 +226,23 @@ TEST_CASE("functions") { 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" ); } + + SECTION("isType") { + CHECK( env.render("{{ isBoolean(is_happy) }}", data) == "true" ); + CHECK( env.render("{{ isBoolean(vars) }}", data) == "false" ); + CHECK( env.render("{{ isNumber(age) }}", data) == "true" ); + CHECK( env.render("{{ isNumber(name) }}", data) == "false" ); + CHECK( env.render("{{ isInteger(age) }}", data) == "true" ); + CHECK( env.render("{{ isInteger(is_happy) }}", data) == "false" ); + CHECK( env.render("{{ isFloat(temperature) }}", data) == "true" ); + CHECK( env.render("{{ isFloat(age) }}", data) == "false" ); + CHECK( env.render("{{ isObject(brother) }}", data) == "true" ); + CHECK( env.render("{{ isObject(vars) }}", data) == "false" ); + CHECK( env.render("{{ isArray(vars) }}", data) == "true" ); + CHECK( env.render("{{ isArray(name) }}", data) == "false" ); + CHECK( env.render("{{ isString(name) }}", data) == "true" ); + CHECK( env.render("{{ isString(names) }}", data) == "false" ); + } } TEST_CASE("callbacks") {