From d63d0405ff8a477ddf540a6029d05d2f1ac6a2b6 Mon Sep 17 00:00:00 2001 From: Dennis Schridde Date: Wed, 1 Feb 2017 18:50:56 +0100 Subject: [PATCH 1/2] Make block-tag checks more flexible --- src/lustache/renderer.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lustache/renderer.lua b/src/lustache/renderer.lua index bcbc9a1..b190d52 100755 --- a/src/lustache/renderer.lua +++ b/src/lustache/renderer.lua @@ -24,6 +24,11 @@ local html_escape_characters = { ["/"] = "/" } +local block_tags = { + ["#"] = true, + ["^"] = true, +} + local function is_array(array) if type(array) ~= "table" then return false end local max, n = 0, 0 @@ -89,7 +94,7 @@ local function nest_tokens(tokens) local token, section for i,token in ipairs(tokens) do - if token.type == "#" or token.type == "^" then + if block_tags[token.type] then token.tokens = {} sections[#sections+1] = token collector[#collector+1] = token From 10262a0ba12862b48407358dc6e3731194149d39 Mon Sep 17 00:00:00 2001 From: Dennis Schridde Date: Wed, 1 Feb 2017 18:58:03 +0100 Subject: [PATCH 2/2] Support explicit iteration over arrays and maps Explicit iteration blocks are e.g. necessary to support iteration over maps/hashes, as in the following example: ```mustache Key/value pairs: {{*hashmap}} - {{k}} = {{v}} {{/hashmap}} ``` I did not include tests, because their data is included in the corresponding pull request to the Mustache spec. See-Also: https://github.com/mustache/spec/pull/23 --- src/lustache/renderer.lua | 53 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/lustache/renderer.lua b/src/lustache/renderer.lua index b190d52..fe2447f 100755 --- a/src/lustache/renderer.lua +++ b/src/lustache/renderer.lua @@ -12,7 +12,7 @@ local patterns = { nonSpace = "%S", eq = "%s*=", curly = "%s*}", - tag = "[#\\^/>{&=!]" + tag = "[#\\^/>{&=!*]" } local html_escape_characters = { @@ -27,6 +27,7 @@ local html_escape_characters = { local block_tags = { ["#"] = true, ["^"] = true, + ["*"] = true, } local function is_array(array) @@ -42,6 +43,18 @@ local function is_array(array) return n == max end +local function is_map(map) + if type(map) ~= "table" then + return false + end + for k, _ in pairs(map) do + if type(k) == "number" then + return false + end + end + return true +end + -- Low-level function that compiles the given `tokens` into a -- function that accepts two arguments: a Context and a -- Renderer. @@ -63,6 +76,9 @@ local function compile_tokens(tokens, originalTemplate) for i, token in ipairs(tokens) do local t = token.type buf[#buf+1] = + t == "*" and rnd:_iterate( + token, ctx, subrender(i, token.tokens) + ) or t == "#" and rnd:_section( token, ctx, subrender(i, token.tokens), originalTemplate ) or @@ -208,6 +224,41 @@ function renderer:render(template, view, partials) return fn(view) end +function renderer:_iterate(token, context, callback) + local value = context:lookup(token.value) + + if type(value) == "table" then + local sub_type + if is_array(value) then + sub_type = "array" + elseif is_map(value) then + sub_type = "map" + end + + if sub_type == "array" then + local buffer = "" + + for i,v in ipairs(value) do + buffer = buffer .. callback(context:push(v), self) + end + + return buffer + elseif sub_type == "map" then + local buffer = "" + + for k,v in pairs(value) do + buffer = buffer .. callback(context:push({k = k, v = v}), self) + end + + return buffer + end + + return error("Can only iterate over arrays and maps, got neither:" .. token.value) + end + + return error("Can only iterate over pure arrays and maps (tables), got " .. type(value) .. ":" .. token.value) +end + function renderer:_section(token, context, callback, originalTemplate) local value = context:lookup(token.value)