diff --git a/README.md b/README.md index 19870c5..f568375 100644 --- a/README.md +++ b/README.md @@ -206,7 +206,7 @@ Environment env = Environment(); /* * Callbacks are defined by its: - * - name, which is equal to the function name + * - name * - number of arguments * - callback function. Implemented with std::function, you can for example use lambdas. */ diff --git a/src/inja.hpp b/src/inja.hpp index e2615e4..5efad12 100644 --- a/src/inja.hpp +++ b/src/inja.hpp @@ -217,8 +217,8 @@ inline MatchClosed search_closed(const std::string& input, const Regex& regex_st return search_closed_on_level(input, regex_statement, regex_open, regex_close, regex_close, open_match); } -template -inline MatchType match(const std::string& input, std::map regexes) { +template +inline MatchType match(const std::string& input, std::map regexes) { MatchType match; for (const auto e : regexes) { if (std::regex_match(input.cbegin(), input.cend(), match, e.second)) { @@ -330,7 +330,6 @@ struct Parsed { explicit ElementExpression(): ElementExpression(Function::ReadJson) { } explicit ElementExpression(const Function function_): Element(Type::Expression), function(function_), args({}), command("") { } }; - typedef std::vector Arguments; struct ElementLoop: public Element { Loop loop; @@ -353,6 +352,9 @@ struct Parsed { explicit ElementConditionBranch(const std::string& inner, const Condition condition_type): Element(Type::ConditionBranch, inner), condition_type(condition_type) { } explicit ElementConditionBranch(const std::string& inner, const Condition condition_type, const ElementExpression& condition): Element(Type::ConditionBranch, inner), condition_type(condition_type), condition(condition) { } }; + + using Arguments = std::vector; + using CallbackSignature = std::pair; }; @@ -369,7 +371,7 @@ class Renderer { public: ElementNotation element_notation; - std::map> map_callbacks; + std::map> map_callbacks; template bool eval_expression(const Parsed::ElementExpression& element, const json &data) { @@ -503,7 +505,8 @@ public: } } case Parsed::Function::Callback: { - return map_callbacks[element.command](element.args, data); + Parsed::CallbackSignature signature = std::make_pair(element.command, element.args.size()); + return map_callbacks.at(signature)(element.args, data); } } @@ -656,13 +659,13 @@ public: {Parsed::Function::ReadJson, Regex{"\\s*([^\\(\\)]*\\S)\\s*"}} }; - std::map regex_map_callbacks; + std::map> regex_map_callbacks; Parser() { } Parsed::ElementExpression parse_expression(const std::string& input) { - MatchType match_callback = match(input, regex_map_callbacks); - if (!match_callback.type().empty()) { + MatchType match_callback = match(input, regex_map_callbacks); + if (!match_callback.type().first.empty()) { std::vector args = {}; for (unsigned int i = 1; i < match_callback.size(); i++) { // str(0) is whole group args.push_back( parse_expression(match_callback.str(i)) ); @@ -670,7 +673,7 @@ public: Parsed::ElementExpression result = Parsed::ElementExpression(Parsed::Function::Callback); result.args = args; - result.command = match_callback.type(); + result.command = match_callback.type().first; return result; } @@ -951,8 +954,9 @@ public: } void add_callback(std::string name, int number_arguments, std::function callback) { - parser.regex_map_callbacks[name] = Parser::function_regex(name, number_arguments); - renderer.map_callbacks[name] = callback; + Parsed::CallbackSignature signature = std::make_pair(name, number_arguments); + parser.regex_map_callbacks[signature] = Parser::function_regex(name, number_arguments); + renderer.map_callbacks[signature] = callback; } template diff --git a/test/src/unit-renderer.cpp b/test/src/unit-renderer.cpp index bc1485f..a97ebf9 100644 --- a/test/src/unit-renderer.cpp +++ b/test/src/unit-renderer.cpp @@ -196,10 +196,23 @@ TEST_CASE("callbacks") { return number1 * number2; }); + env.add_callback("multiply", 3, [&env](inja::Parsed::Arguments args, json data) { + double number1 = env.get_argument(args, 0, data); + double number2 = env.get_argument(args, 1, data); + double number3 = env.get_argument(args, 2, data); + return number1 * number2 * number3; + }); + + env.add_callback("multiply", 0, [&env](inja::Parsed::Arguments args, json data) { + return 1.0; + }); + CHECK( env.render("{{ double(age) }}", data) == "56" ); CHECK( env.render("{{ half(age) }}", data) == "14" ); CHECK( env.render("{{ double-greetings }}", data) == "Hello Hello!" ); CHECK( env.render("{{ multiply(4, 5) }}", data) == "20.0" ); + CHECK( env.render("{{ multiply(3, 4, 5) }}", data) == "60.0" ); + CHECK( env.render("{{ multiply }}", data) == "1.0" ); } TEST_CASE("combinations") {