# HG changeset patch # User Matthew Wild # Date 1679571805 0 # Node ID db73c4c317cef9e47f79b9b8652807da9c9be3e8 # Parent ecae87f5aaba4aa64f0dd5e8c780a6b080c148ff stanzacmp: Support for captures diff -r ecae87f5aaba -r db73c4c317ce scansion/stanzacmp.lua --- a/scansion/stanzacmp.lua Sat May 08 13:21:56 2021 +0200 +++ b/scansion/stanzacmp.lua Thu Mar 23 11:43:25 2023 +0000 @@ -21,21 +21,38 @@ error("Unexpected scansion:strict value: "..opt); end -local function stanzas_strict_match(stanza1, stanza2) +local function is_wildcard(k, v) + if v == "{scansion:any}" then + return "attr:"..k; + end + return (v:match("^{scansion:capture:([^}]+)}$")); +end + +-- stanza1 == expected, stanza2 == variable +-- captures is an optional table to store captures (captures["foo"] == {scansion:capture:foo}) +local function stanzas_strict_match(stanza1, stanza2, captures) if stanza1.name ~= stanza2.name or stanza1.attr.xmlns ~= stanza2.attr.xmlns then return false; end for k, v in pairs(stanza1.attr) do - if not k:match("^scansion:") and v ~= "{scansion:any}" and stanza2.attr[k] ~= v then + local wildcard = is_wildcard(k, v); + if not k:match("^scansion:") and not wildcard and stanza2.attr[k] ~= v then return false; end + if wildcard and captures then + captures[wildcard] = stanza2.attr[k]; + end end for k, v in pairs(stanza2.attr) do - if stanza1.attr[k] ~= "{scansion:any}" and stanza1.attr[k] ~= v then + local wildcard = is_wildcard(k, stanza1.attr[k]); + if not wildcard and stanza1.attr[k] ~= v then return false; end + if wildcard and captures then + captures[wildcard] = v; + end end if #stanza1.tags ~= #stanza2.tags then @@ -56,7 +73,7 @@ end if type(child) == "table" and child2.name == child.name and child2.attr.xmlns == child.attr.xmlns then -- Strict deep match - match = stanzas_strict_match(child, child2); + match = stanzas_strict_match(child, child2, captures); elseif type(child) == "string" then -- Text nodes, must be equal, ignoring leading/trailing whitespace match = trim(child) == trim(child2); end @@ -71,18 +88,22 @@ -- Everything in stanza1 should be present in stanza2 -local function stanzas_match(stanza1, stanza2) +local function stanzas_match(stanza1, stanza2, captures) if wants_strict(stanza1, stanza1.attr.xmlns == nil and "no" or "yes") then - return stanzas_strict_match(stanza1, stanza2); + return stanzas_strict_match(stanza1, stanza2, captures); end if stanza1.name ~= stanza2.name or stanza1.attr.xmlns ~= stanza2.attr.xmlns then return false; end for k, v in pairs(stanza1.attr) do - if not k:match("^scansion:") and v ~= "{scansion:any}" and stanza2.attr[k] ~= v then + local wildcard = is_wildcard(k, v); + if not k:match("^scansion:") and not wildcard and stanza2.attr[k] ~= v then return false; end + if wildcard and captures then + captures[wildcard] = stanza2.attr[k]; + end end local matched_children = {}; @@ -98,7 +119,7 @@ if type(child2) == type(child) then if type(child) == "table" and child2.name == child.name and child2.attr.xmlns == child.attr.xmlns then - match = stanzas_match(child, child2); + match = stanzas_match(child, child2, captures); elseif type(child) == "string" then -- Text nodes, must be equal, ignoring leading/trailing whitespace match = trim(child) == trim(child2); end diff -r ecae87f5aaba -r db73c4c317ce spec/stanzacmp_spec.lua --- a/spec/stanzacmp_spec.lua Sat May 08 13:21:56 2021 +0200 +++ b/spec/stanzacmp_spec.lua Thu Mar 23 11:43:25 2023 +0000 @@ -18,9 +18,9 @@ return table.unpack(out, 1, n); end -local function yes(s1, s2) +local function yes(s1, s2, captures) s1, s2 = parse(s1, s2); - if not stanzacmp.stanzas_match(s1, s2) then + if not stanzacmp.stanzas_match(s1, s2, captures) then print("s1", s1) print("s2", s2) print("literal", tostring(s1) == tostring(s2)); @@ -28,9 +28,9 @@ end end -local function no(s1, s2) +local function no(s1, s2, captures) s1, s2 = parse(s1, s2); - if stanzacmp.stanzas_match(s1, s2) then + if stanzacmp.stanzas_match(s1, s2, captures) then print("s1", s1) print("s2", s2) assert(false, "Match, but they should not."); @@ -197,4 +197,28 @@ ]]); end); + + it("supports captures", function () + local captures = {}; + yes([[ + + + + + + ]], + [[ + + + + + + ]], captures); + assert.same({ + ["attr:jid"] = 'user@localhost/KeoGLEr3'; + ["attr:affiliation"] = "owner"; + ["code1"] = "201"; + ["code2"] = "110"; + }, captures); + end); end);