From 61f2d31ba18f0cc516893ce3aabc24008e900e29 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Tue, 1 Apr 2014 22:52:55 +1000 Subject: Separate out the metatable __ stuff from Thing, put it into Mum. --- ClientHamr/GuiLua/skang.lua | 140 ++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 70 deletions(-) (limited to 'ClientHamr/GuiLua/skang.lua') diff --git a/ClientHamr/GuiLua/skang.lua b/ClientHamr/GuiLua/skang.lua index 8d15dfe..de0a0af 100644 --- a/ClientHamr/GuiLua/skang.lua +++ b/ClientHamr/GuiLua/skang.lua @@ -57,10 +57,6 @@ The old skang argument types are - do -- Only I'm not gonna indent this. --- There is no ThingSpace, or Stuff, now it's all just in this meta table. Predefined here coz moduleBegin references Thing. -local Thing = {} - - -- TODO - This needs to be expanded a bit to cover things like 1.42 local versions = { '0%.0', 'unwritten', 'Just a stub, no code at all, or completely non-existant.', @@ -427,7 +423,7 @@ So the values stored in this Thing are actually stored in meta(parent)__values[t parent[thing] = value -> __newindex(parent, thing, value) -> meta(parent).__values[thing] = value -A Stuff is a description table of a Thing that includes - +Each Thing has a description table that includes - names - An array of names, the first one is the "official" name. types - An array of types, the first one is the "official" type. help - A descriptive text for humans to read. @@ -436,14 +432,15 @@ A Stuff is a description table of a Thing that includes - required - If the Thing is required. isValid - A function that tests if the Thing is valid. errors - Any errors related to the Thing. - isKeyed - Is this thing itself a parent for Stuff that is stored under an arbitrary key. - stuff - An array of Stuff's for sub Things, so Things that are tables can have their own Things. + isKeyed - Is this a parent for Things that are stored under an arbitrary key. + stuff - An array of descriptions for sub Things, so Things that are tables can have their own Things. and other things that aren't actually used yet. -All things that a Stuff doesn't have should be inherited from the Thing table. -Stuff's should be able to be easily shared by various Things. +All things that a description doesn't have should be inherited from the Thing table. + setmetatable(aStuff, {__index = Thing}) +Descriptions should be able to be easily shared by various Things. -A parent's metatable has __self, which is it's own Stuff. +A parent's metatable has __self, which is it's own description. A parent is free to use it's own name space for anything it wants. Only the variables it specifies as managed Things are dealt with here. @@ -451,13 +448,16 @@ Only the variables it specifies as managed Things are dealt with here. TODO - test.foo -> test.__index(test, 'foo') -> test.__values[foo]; if that's nil, and test.stuff[foo], then return an empty table instead? stuff.s = {a='foo'} -> changes a, deletes everything else, or should. - Got rid of Stuff.parent, but do we still need a parent pointer? + Do we still need a parent pointer? Should be in __values I guess. __values[key].value __values[key].parent ]] +-- There is no ThingSpace, or Stuff, now it's all just in this meta table. +local Thing = {} + -- Default things values. -- help - help text describing this Thing. -- default - the default value. This could be a funcion, making this a command. @@ -495,20 +495,21 @@ Thing.errors = {} -- A list of errors returned by isValid(). Thing.isValid = function (self, parent) -- Check if this Thing is valid, return resulting error messages in errors. -- Anything that overrides this method, should call this super method first. local name = self.names[1] - local mumThing = getmetatable(parent) - local value = mumThing.__values[name] + local metaMum = getmetatable(parent) + local value = metaMum.__values[name] + local mum = metaMum.__self.names[1] local t = type(value) or 'nil' self.errors = {} -- TODO - Naturally there should be formatting functions for stuffing Thing stuff into strings, and overridable output functions. if 'nil' == t then - if self.required then table.insert(self.errors, mumThing.__self.names[1] .. '.' .. name .. ' is required!') end + if self.required then table.insert(self.errors, mum .. '.' .. name .. ' is required!') end else - if self.types[1] ~= t then table.insert(self.errors, mumThing.__self.names[1] .. '.' .. name .. ' should be a ' .. self.types[1] .. ', but it is a ' .. t .. '!') + if self.types[1] ~= t then table.insert(self.errors, mum .. '.' .. name .. ' should be a ' .. self.types[1] .. ', but it is a ' .. t .. '!') else if 'number' == t then value = '' .. value end if ('number' == t) or ('string' == t) then - if 1 ~= string.find(value, '^' .. self.pattern .. '$') then table.insert(self.errors, mumThing.__self.names[1] .. '.' .. name .. ' does not match pattern "' .. self.pattern .. '"!') end + if 1 ~= string.find(value, '^' .. self.pattern .. '$') then table.insert(self.errors, mum .. '.' .. name .. ' does not match pattern "' .. self.pattern .. '"!') end end end end @@ -528,45 +529,44 @@ Thing.remove = function (self) -- Delete this Thing. end -Thing.__index = function (parent, key) +local Mum = +{ +__index = function (parent, key) -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. -- TODO - Java skang called isValid() on get(). On the other hand, doesn't seem to call it on set(), but calls it on append(). -- Ah, it was doing isValid() on setStufflet(). -- First see if this is a Thing. - local mumThing = getmetatable(parent) - local thingy + local metaMum = getmetatable(parent) - if mumThing and mumThing.__self then - thingy = mumThing.__self.stuff[key] + if metaMum and metaMum.__self then + local thingy = metaMum.__self.stuff[key] if thingy then - local name = thingy.names[1]; - return mumThing.__values[name] or thingy.default + return metaMum.__values[thingy.names[1] ] or thingy.default end end -- Then see if we can inherit it from Thing. return Thing[key] -end +end, -Thing.__newindex = function (parent, key, value) +__newindex = function (parent, key, value) -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. - local mumThing = getmetatable(parent) - if mumThing and mumThing.__self then - -- This is a proxy table, the values never exist in the real table. In theory. + -- First see if this is a Thing. + local metaMum = getmetatable(parent) - -- Find the Thing and get it done. - local thingy = mumThing.__self.stuff[key] + if metaMum and metaMum.__self then + local thingy = metaMum.__self.stuff[key] if not thingy then - -- Deal with setting a new Stuff[key]. - if mumThing.__self.isKeyed and (nil == mumThing.__values[key]) then + -- Deal with setting a new Keyed table entry. + if metaMum.__self.isKeyed and (nil == metaMum.__values[key]) then local newThing = copy(parent, key) - rawset(mumThing.__values, key, newThing) + rawset(metaMum.__values, key, newThing) thingy = {names={key}, types={'table'}, parent=newThing, stuff=getmetatable(newThing).__self.stuff, } setmetatable(thingy, {__index = Thing}) -- To pick up isValid, pattern, and the other stuff by default. - mumThing.__self.stuff[key] = thingy + metaMum.__self.stuff[key] = thingy end end @@ -575,8 +575,8 @@ Thing.__newindex = function (parent, key, value) local valueMeta if 'table' == type(value) then - -- Coz setting it via mumThing screws with the __index stuff somehow. - local oldValue = mumThing.__values[name] + -- Coz setting it via metaMum screws with the __index stuff somehow. + local oldValue = metaMum.__values[name] if 'table' == type(oldValue) then valueMeta = getmetatable(oldValue) if valueMeta then @@ -589,7 +589,7 @@ Thing.__newindex = function (parent, key, value) end end end - if nil == valueMeta then mumThing.__values[name] = value end + if nil == valueMeta then metaMum.__values[name] = value end -- NOTE - invalid values are still stored, this is by design. if not thingy:isValid(parent) then for i, v in ipairs(thingy.errors) do @@ -603,10 +603,22 @@ Thing.__newindex = function (parent, key, value) end rawset(parent, key, value) -- Stuff it normally. -end +end, -Thing.__call = function (func, ...) +__call = function (func, ...) return thingasm(func, ...) -- (func, {...}) +end, + +} + +newMum = function () + local result = {} + for k, v in pairs(Mum) do + result[k] = v + end + result.__self = {stuff={}} + result.__values = {} + return result end @@ -614,20 +626,19 @@ end --[[ It can be called in many different ways - It can be called with positional arguments - (names, help, default, types, widget, required, acl, boss) -Or it can be called with a table - {names, help, pattern='...', acl='rwx'} +Or it can be called with a table - {names, help, pattern='.*', acl='rwx'} The first argument can be another Thing (the parent), or a string list of names (see below). It can be called by itself, with no parent specified - thingasm('foo', 'help text) - In this case the surrounding Lua environment becomes the parent of foo. If the first argument (or first in the table) is a string, then it's this form. All others include the parent as the first argument, which would be a table. It can be called by calling the parent as a function - foo('bar', 'some help', types='table') -- ___call(foo, 'bar', ...) And now foo is the parent. - foo.bar{'baz', types='Stuff'} -- thingasm({foo.bar, 'baz', ...}) + foo.bar{'baz', types='Keyed'} -- thingasm({foo.bar, 'baz', ...}) foo.bar.baz{'field0'} -- thingasm({foo.bar.baz, 'field0'}) foo.bar.baz{'field1'} ]] @@ -669,24 +680,16 @@ thingasm = function (names, ...) -- Grab the environment of the calling function if no parent was passed in. parent = parent or getfenv(2) - local mumThing = getmetatable(parent) - if nil == mumThing then - mumThing = {} - setmetatable(parent, mumThing) - end - -- Coz at module creation time, Thing is an empty table, and setmetatable(mumThing, {__index = Thing}) doesn't do the right thing. - if nil == mumThing.__self then - mumThing.__self = {stuff={}} - -- Seems this does not deal with __index and __newindex, and also screws up stuff somehow. --- setmetatable(mumThing, {__index = Thing}) - mumThing.__self.names = {parent._NAME or 'NoName'} - if parent._NAME then mumThing.__self.types = {'Module'} end - mumThing.__values = {} - mumThing.__index = Thing.__index - mumThing.__newindex = Thing.__newindex + local metaMum = getmetatable(parent) + -- Coz at module creation time, Thing is an empty table, or in case this is for a new parent. + if nil == metaMum then + metaMum = newMum() + metaMum.__self.names = {parent._NAME or 'NoName'} + if parent._NAME then metaMum.__self.types = {'Module'} end + setmetatable(parent, metaMum) end - local thingy = mumThing.__self.stuff[name] + local thingy = metaMum.__self.stuff[name] if not thingy then -- This is a new Thing. new = true thingy = {} @@ -721,32 +724,29 @@ thingasm = function (names, ...) if '' == types then types = typ end thingy.types = csv2table(types) + -- Deal with Keyed and tables. if 'Keyed' == thingy.types[1] then thingy.types[1] = 'table' thingy.isKeyed = true end if 'table' == thingy.types[1] then + -- Default in this case becomes a parent. if '' == thingy.default then thingy.default = {} end - setmetatable(thingy.default, - { - __self = thingy, - __values = {}, - __index = Thing.__index, - __newindex = Thing.__newindex, - __call = Thing.__call, - }) + local thisMum = newMum() + thisMum.__self = thingy + setmetatable(thingy.default, thisMum) end -- Remove old names, then stash the Thing under all of it's new names. for i, v in ipairs(oldNames) do - mumThing.__self.stuff[v] = nil + metaMum.__self.stuff[v] = nil end for i, v in ipairs(thingy.names) do - mumThing.__self.stuff[v] = thingy + metaMum.__self.stuff[v] = thingy end - -- This triggers the Thing.__newindex metamethod above. If nothing else, it triggers thingy.isValid() - if new and not mumThing.__self.isKeyed then parent[name] = thingy.default end + -- This triggers the Mum.__newindex metamethod above. If nothing else, it triggers thingy.isValid() + if new and not metaMum.__self.isKeyed then parent[name] = thingy.default end end -- cgit v1.1