From 83448304527d8a1dde233f2f33b98124bced5f88 Mon Sep 17 00:00:00 2001 From: sanine Date: Fri, 18 Aug 2023 01:42:20 -0500 Subject: implement some basic svg rendering --- marigold.lua | 101 ++++++++++++++++++++++++++++++++++++-------------------- test.lua | 106 +++++++++++++++++++++-------------------------------------- 2 files changed, 103 insertions(+), 104 deletions(-) diff --git a/marigold.lua b/marigold.lua index a6223df..9daa808 100644 --- a/marigold.lua +++ b/marigold.lua @@ -36,27 +36,6 @@ local marigold = {} -marigold.get_metavars = function() - local vars = { - "AUTH_TYPE", "CONTENT_LENGTH", - "CONTENT_TYPE", "GATEWAY_INTERFACE", - "PATH_INFO", "PATH_TRANSLATED", - "QUERY_STRING", "REMOTE_ADDR", - "REMOTE_HOST", "REMOTE_IDENT", - "REMOTE_USER", "REQUEST_METHOD", - "SCRIPT_NAME", "SERVER_NAME", - "SERVER_PORT", "SERVER_PROTOCOL", - "SERVER_SOFTWARE" - } - - local metavars = {} - for _, var in ipairs(vars) do - metavars[string.lower(var)] = os.getenv(var) - end - return metavars -end - - marigold.h = function(tag_type, content, tbl) if type(content) == 'table' and tbl == nil then tbl = content @@ -90,7 +69,7 @@ marigold.h = function(tag_type, content, tbl) end -marigold.html = function(tbl, indent_level) +local function render_internal(tbl, indent_level) indent_level = indent_level or 0 local indent = string.rep('\t', indent_level) @@ -117,7 +96,7 @@ marigold.html = function(tbl, indent_level) local children = '' for _, child in ipairs(tbl.children) do - children = children .. marigold.html(child, indent_level+1) .. '\n' + children = children .. render_internal(child, indent_level+1) .. '\n' end return string.format('%s%s%s\n%s%s%s', @@ -126,25 +105,75 @@ marigold.html = function(tbl, indent_level) indent, close) end -marigold.decode_percent = function(str) - return string.gsub(str, "%%(%x%x)", function(digits) - return string.char(tonumber(digits, 16)) - end) +marigold.render = function(tbl) + local str = render_internal(tbl, 0) + return '\n' .. str end -marigold.decode_query = function(str) - local tbl = {} - local cleanString = function(str) - return marigold.decode_percent( - string.gsub(str, "+", " ") - ) + +-- built-in svg types + +local function set(tbl) + local s = {} + for _, v in ipairs(tbl) do + s[v] = true end + return s +end - for k, v in string.gmatch(str, "([^=]-)=([^&]*)&?") do - tbl[cleanString(k)] = cleanString(v) +local function validate(tagname, valid, tbl) + local valid_set = set(valid) + -- inject the core svg attributes + valid_set.id = true + valid_set.tabindex = true + valid_set.lang = true + valid_set['xml:space'] = true + valid_set.class = true + valid_set.style = true + for k in pairs(tbl) do + if not valid_set[k] then return string.format( + "ERROR: attempted to set invalid attribute '%s' on tag of type %s", + k, tagname + ) end end + return nil +end + +local function maketag(tag, content, tbl, valid) + local t = marigold.h(tag, content, tbl) + local err = validate(tag, valid, t.attributes) + if err then return nil, err end + return t, nil +end - return tbl + +marigold.svg = function(tbl) + local tbl = tbl or {} + tbl.xmlns = 'http://www.w3.org/2000/svg' + local tag, err = maketag('svg', '', tbl, { 'xmlns', 'viewBox', 'width', 'height' }) + if err then error(err) end + return tag end + +marigold.g = function(tbl) + local tbl = tbl or {} + local tag, err = maketag('g', '', tbl, { 'transform' }) + if err then error(err) end + return tag +end + + +marigold.rect = function(tbl) + local tag, err = maketag('rect', '', tbl, { 'x', 'y', 'width', 'height', 'rx', 'ry', 'transform', }) + if err then error(err) end + return tag +end + + +marigold.text = function(tbl) +end + + + return marigold diff --git a/test.lua b/test.lua index e359c7e..47c7fed 100755 --- a/test.lua +++ b/test.lua @@ -1,6 +1,6 @@ -#!/usr/bin/lua +#!/usr/bin/env lua5.1 -local marigold = require 'marigold' +local svg = require 'marigold' function test(description, func) io.write(description .. ': ') @@ -15,45 +15,8 @@ function test(description, func) end -test("marigold.get_metavars correctly calls os.getenv", function() - -- mock os.getenv - local old_getenv = os.getenv - local env_tbl = { - AUTH_TYPE = 'some auth type', - CONTENT_LENGTH = 'a zillion', - GATEWAY_INTERFACE = 'idk, something', - PATH_INFO = 'youll see, its a secret', - PATH_TRANSLATED = 'i told you its a secret!', - QUERY_STRING = 'which string do you want?', - REMOTE_ADDR = 'probably somewhere in nunavut', - REMOTE_HOST = 'woah wait are we talking about parasites?', - REMOTE_IDENT = 'are you a cop?', - REMOTE_USER = 'seriously, you have to tell me if you are', - REQUEST_METHOD = 'uhh, to do what?', - SCRIPT_NAME = 'pretty sure this is hamlet', - SERVER_NAME = 'this isnt a restaurant', - SERVER_PORT = 'what, like a ship?', - SERVER_PROTOCOL = 'no really, not a restaurant', - SERVER_SOFTWARE = 'not familiar with that dish...', - } - os.getenv = function(varname) return env_tbl[varname] end - - -- actually call the function - metavars = marigold.get_metavars() - - assert(type(metavars) == 'table') - for k, v in pairs(env_tbl) do - assert(metavars[string.lower(k)]) - assert(metavars[string.lower(k)] == env_tbl[k]) - end - - -- restore os.getenv - os.getenv = old_getenv -end) - - -test("marigold.h produces a correct basic tag", function() - local h = marigold.h +test("svg.h produces a correct basic tag", function() + local h = svg.h local h1 = h('h1', 'hello, world!') assert(type(h1) == 'table') assert(h1.tag == 'h1') @@ -66,8 +29,8 @@ test("marigold.h produces a correct basic tag", function() end) -test("marigold.h correctly adds children", function() - local h = marigold.h +test("svg.h correctly adds children", function() + local h = svg.h local div = h('div', "some stuff", { h('p', "the first paragraph"), h('p', "the second paragraph"), @@ -87,8 +50,8 @@ test("marigold.h correctly adds children", function() end) -test("marigold.h correctly ignores missing content", function() - local h = marigold.h +test("svg.h correctly ignores missing content", function() + local h = svg.h local div = h('div', { h('p', "the first paragraph"), h('p', "the second paragraph"), @@ -108,8 +71,8 @@ test("marigold.h correctly ignores missing content", function() end) -test("marigold.h correctly sets attributes and children", function() - local h = marigold.h +test("svg.h correctly sets attributes and children", function() + local h = svg.h local div = h('div', { id="root", class="blinking bold", h('p', "the first paragraph"), @@ -130,24 +93,24 @@ test("marigold.h correctly sets attributes and children", function() end) -test("marigold.html correctly renders basic html table", function() +test("svg.render correctly renders basic render table", function() local tbl = { tag='p', content='some paragraph', attributes={}, children={}} - local html = marigold.html(tbl) - assert(html == '

some paragraph

') + local render = svg.render(tbl) + assert(render == '\n

some paragraph

') end) -test("marigold.html correctly renders tag attributes", function() +test("svg.render correctly renders tag attributes", function() local tbl = { tag='p', content='some paragraph', attributes={ id='p1', class='blinking bold' }, children={}} - local html = marigold.html(tbl) - assert(html == '

some paragraph

') + local render = svg.render(tbl) + assert(render == '\n

some paragraph

') end) -test("marigold.html correctly renders children", function() +test("svg.render correctly renders children", function() local tbl = { tag = 'div', content='', attributes = {id="root"}, children = { @@ -156,27 +119,34 @@ test("marigold.html correctly renders children", function() } } - local html = marigold.html(tbl) - assert(html == [[
+ local render = svg.render(tbl) + assert(render == [[ +

p1

p2

]]) end) -test("marigold.decode_percent correctly decodes percent-encoded strings", function() - local str = '%20%21%23%24%25%26%27%28%29%2A%2B%2C%2F%3A%3B%3D%3F%40%5B%5D' - assert(marigold.decode_percent(str) == " !#$%&'()*+,/:;=?@[]") - assert(marigold.decode_percent('%25+%2b') == '%++') + + +test("svg.svg correctly has xmlns attribute set", function() + local tbl = svg.svg() + assert(tbl.tag == 'svg') + assert(tbl.content == '') + assert(tbl.attributes.xmlns == 'http://www.w3.org/2000/svg') + assert(#tbl.children == 0) end) -test("marigold.decode_query correctly obtains data", function() - local tbl - tbl = marigold.decode_query('') - tbl = marigold.decode_query('name=john') - assert(tbl.name == 'john') - tbl = marigold.decode_query('string=hello%2C+world%21&name=jane') - assert(tbl.string == 'hello, world!') - assert(tbl.name == 'jane') +test("svg.g can set transform attribute", function() + local tbl = svg.g{ + transform = "rotate(45deg)", + svg.g(), + svg.g(), + } + assert(tbl.tag == 'g') + assert(tbl.content == '') + assert(tbl.attributes.transform == 'rotate(45deg)') + assert(#tbl.children == 2) end) -- cgit v1.2.1