From 22271b5c9dd9bcc9a39de87f314eb3f1c2929637 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Wed, 26 Mar 2014 14:45:11 +1000 Subject: Re arrange so that the Thing definitions are all together. --- ClientHamr/GuiLua/skang.lua | 244 ++++++++++++++++++++++---------------------- 1 file changed, 120 insertions(+), 124 deletions(-) (limited to 'ClientHamr') diff --git a/ClientHamr/GuiLua/skang.lua b/ClientHamr/GuiLua/skang.lua index 0ba16cb..418cd10 100644 --- a/ClientHamr/GuiLua/skang.lua +++ b/ClientHamr/GuiLua/skang.lua @@ -52,12 +52,79 @@ The old skang argument types are - ]] - -- Wrapping the entire module in do .. end helps if people just join a bunch of modules together, which apparently is popular. -- By virtue of the fact we are stuffing our result into package.loaded[], just plain running this works as "loading the module". do -- Only I'm not gonna indent this. +-- There is no ThingSpace, now it's all just in this table, and meta table. Predefined here coz moduleBegin references Thing. +things = {} +Thing = {} + + +-- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated. +moduleBegin = function (name, author, copyright, version, timestamp, skin) + local _M = {} -- This is what we return to require(). + local level = 2 + + package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end. + -- Returning it at the end does the same thing. + -- This is so that we can have all the module stuff at the top, in this function. + -- Should do this before any further require(), so that circular references don't blow out. + + -- Save the callers environment. + local savedEnvironment = getfenv(level) + + -- Clone the environment into _M, so the module can access everything as usual after the setfenv() below. + --[[ TODO - Check if this also clones _G or _ENV. And see if it leaks stuff in either direction. + local _G = _G -- Only sets a local _G for this function. + _M._G = _G -- This clone loop might do this, but we don't want to be able to access the old _G from outside via this leak. + In Lua 5.1 at least, _G was special. In 5.2, _ENV sorta replaces setfenv(), but no idea if this clone loop stomps on that. + ]] + for k, v in pairs(savedEnvironment) do + _M[k] = v + end + + _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M. + _M._NAME = name + _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name. + + -- TODO - Should parse in an entire copyright message, and strip that down into bits, to put back together. + _M.AUTHOR = author + _M.COPYRIGHT = copyright .. ' ' .. author + -- TODO - Translate the version number into a version string. + _M.VERSION = version .. ' lookup version here ' .. timestamp + -- TODO - If there's no skin passed in, try to find the file skin .. '.skang' and load that instead. + _M.DEFAULT_SKANG = skin + + + --_G[_M._NAME] = _M -- Stuff it into a global of the same name. + -- Not such a good idea to stomp on global name space. + -- It's also redundant coz we get stored in package.loaded[_M._NAME] anyway. + -- This is why module() is broken. + + setmetatable(_M, Thing) + _M.savedEnvironment = savedEnvironment + -- setfenv() sets the environment for the FUNCTION, stack level deep. + -- The number is the stack level - + -- 0 running thread, 1 current function, 2 function that called this function, etc + setfenv(level, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names. + -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd(). + -- Next question, does this screw with the environment of the skang module? No it doesn't, coz that's set up at require 'skang' time. + + return _M +end + +-- Restore the environment. +moduleEnd = function (module) + setfenv(2, module.savedEnvironment) +end + +-- Call this now so that from now on, this is like any other module. +local _M = moduleBegin('skang', 'David Seikel', '2014', '0.0', '2014-03-19 19:01:00') + + + --[[ Thing package matrix-RAD had Thing as the base class of everything. Lua doesn't have @@ -119,38 +186,31 @@ Other Thing things are - Actually, not sure matrix-RAD solved that either. lol ]] +Thing.action = 'nada' -- An optional action to perform. +Thing.tell = '' -- The skang command that created this Thing. --- There is no ThingSpace, now it's just in this table - -things = -{ -} - -Thing = -{ - action = 'nada', -- An optional action to perform. - tell = '', -- The skang command that created this Thing. +Thing.append = function (self,data) -- Append to the value of this Thing. + end - append = function (self,data) -- Append to the value of this Thing. - end, - isValid = function (self) -- Check if this Thing is valid, return resulting error messages in errors. +Thing.isValid = function (self) -- Check if this Thing is valid, return resulting error messages in errors. self.errors = {} -- TODO - Should check for required, matching mask, matching type, etc. return true - end, - remove = function (self) -- Delete this Thing. - end, + end - errors = {}, -- A list of errors returned by isValid(). +Thing.remove = function (self) -- Delete this Thing. + end - isReadOnly = false, -- Is this Thing read only? - isServer = false, -- Is this Thing server side? - isStub = false, -- Is this Thing a stub? - isStubbed = false, -- Is this Thing stubbed elsewhere? +Thing.errors = {} -- A list of errors returned by isValid(). - hasCrashed = 0, -- How many times this Thing has crashed. +Thing.isReadOnly = false -- Is this Thing read only? +Thing.isServer = false -- Is this Thing server side? +Thing.isStub = false -- Is this Thing a stub? +Thing.isStubbed = false -- Is this Thing stubbed elsewhere? +Thing.hasCrashed = 0 -- How many times this Thing has crashed. - __index = function (table, key) +Thing.__index = function (table, key) -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. local thing = things[key] @@ -158,7 +218,7 @@ Thing = if thing then local result = nil if key ~= thing.names[1] then - result = table[thing.names[1] ] + result = table[thing.names[1] ] -- This might be recursive. end return result or thing.default end @@ -169,14 +229,14 @@ Thing = -- If all else fails, return nil. return nil - end, - + end - __newindex = function (table, key, value) +Thing.__newindex = function (table, key, value) local thing = things[key] if thing then local name = thing.names[1] + rawset(table, name, value) -- Only stuff it under the first name, the rest are left as nil. if 'function' == type(value) then thing.func = value local types = '' @@ -189,114 +249,22 @@ Thing = print(thing.types[1] .. ' ' .. thing.module._NAME .. '.' .. name .. ' = ' .. (value or 'nil') .. ' -> ' .. thing.help) -- TODO - Go through it's linked things and set them to. end - rawset(table, name, value) else - rawset(table, key, value) + rawset(table, key, value) -- Stuff it normally. end - end, - + end -- TODO - Seemed like a good idea at the time, but do we really need it? --- __call = function (func, ...) +--Thing.__call = function (func, ...) -- return func.func(...) --- end, -} - - --- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated. -moduleBegin = function (name, author, copyright, version, timestamp, skin) - local _M = {} -- This is what we return to require(). - local level = 2 - - package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end. - -- Returning it at the end does the same thing. - -- This is so that we can have all the module stuff at the top, in this function. - -- Should do this before any further require(), so that circular references don't blow out. +-- end - -- Save the callers environment. - local savedEnvironment = getfenv(level) - - -- Clone the environment into _M, so the module can access everything as usual after the setfenv() below. - --[[ TODO - Check if this also clones _G or _ENV. And see if it leaks stuff in either direction. - local _G = _G -- Only sets a local _G for this function. - _M._G = _G -- This clone loop might do this, but we don't want to be able to access the old _G from outside via this leak. - In Lua 5.1 at least, _G was special. In 5.2, _ENV sorta replaces setfenv(), but no idea if this clone loop stomps on that. - ]] - for k, v in pairs(savedEnvironment) do - _M[k] = v - end - - _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M. - _M._NAME = name - _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name. - - -- TODO - Should parse in an entire copyright message, and strip that down into bits, to put back together. - _M.AUTHOR = author - _M.COPYRIGHT = copyright .. ' ' .. author - -- TODO - Translate the version number into a version string. - _M.VERSION = version .. ' lookup version here ' .. timestamp - -- TODO - If there's no skin passed in, try to find the file skin .. '.skang' and load that instead. - _M.DEFAULT_SKANG = skin - - - --_G[_M._NAME] = _M -- Stuff it into a global of the same name. - -- Not such a good idea to stomp on global name space. - -- It's also redundant coz we get stored in package.loaded[_M._NAME] anyway. - -- This is why module() is broken. - - setmetatable(_M, Thing) - _M.savedEnvironment = savedEnvironment - -- setfenv() sets the environment for the FUNCTION, stack level deep. - -- The number is the stack level - - -- 0 running thread, 1 current function, 2 function that called this function, etc - setfenv(level, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names. - -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd(). - -- Next question, does this screw with the environment of the skang module? No it doesn't, coz that's set up at require 'skang' time. - - return _M -end - --- Restore the environment. -moduleEnd = function (module) - setfenv(2, module.savedEnvironment) -end - --- Call this now so that from now on, this is like any other module. -local _M = moduleBegin('skang', 'David Seikel', '2014', '0.0', '2014-03-19 19:01:00') - - ---[[ TODO - It might be worth it to combine parameters and commands, since in Lua, functions are first class types like numbers and strings. - Merging widgets might work to. B-) - This does make the entire "Things with the same name link automatically" deal work easily, since they ARE the same Thing. - - Parameter gets a type, which might help since Lua is untyped, versus Java being strongly typed. - Widgets get a type as well, which would be label, button, edit, grid, etc. - A grid could even have sub types - grid,number,string,button,date. B-) - - Required commands makes no sense, but can just be ignored. - A required widget might mean that the window HAS to have one. - - Default for a command would be the actual function. - Default being a function makes this Thing a command. - Default for a widget could be the default creation arguments - '"Press me", 1, 1, 10, 50' - - skang.thing(_M, 'foo,s,fooAlias', 'Foo is a bar, not the drinking type.', function () print('foo') end, nil, '"button", "The foo :"' 1, 1, 10, 50') - myButton = skang.widget('foo') -- Gets the default widget creation arguments. - myButton:colour(1, 2, 3, 4) - myEditor = skang.widget('foo', "edit", "Edit foo :", 5, 15, 10, 100) - myEditor:colour(1, 2, 3, 4, 5, 6, 7, 8) - myButton = 'Not default' -- myEditor and _M.foo change to. Though now _M.foo is a command, not a parameter, so maybe don't change that. - -- Though the 'quit' Thing could have a function that does quitting, this is just an example of NOT linking to a Thing. - -- If we had linked to this theoretical 'quit' Thing, then pushing that Quit button would invoke it's Thing function. - quitter = skang.widget(nil, 'button', 'Quit', 0.5, 0.5, 0.5, 0.5) - quitter:action('quit') -]] -- skang.thing() stashes the default value into _M['bar'], and the details into things['bar']. -- names - a comma seperated list of names, aliasas, and shortcuts. The first one is the official name. -- help - help text describing this Thing. -- default - the default value. This could be a funcion, making this a command. --- types - a comma separated list of types. The first is the type of the Thing itself, the rest are for multi value Things. Or argument types for functions. +-- types - a comma separated list of types. The first is the type of the Thing itself, the rest are for multi value Things. Or argument types for commands. -- widget - default widget command arguments for creating this Thing as a widget. -- required - "boolean" to say if this thing is required. TODO - Maybe fold this into types somehow, or acl? -- acl - Access Control List defining security restrains. @@ -336,6 +304,34 @@ thing = function (module, names, help, default, types, widget, required, acl, bo module[name] = default end +--[[ TODO - It might be worth it to combine parameters and commands, since in Lua, functions are first class types like numbers and strings. + Merging widgets might work to. B-) + This does make the entire "Things with the same name link automatically" deal work easily, since they ARE the same Thing. + + Parameter gets a type, which might help since Lua is untyped, versus Java being strongly typed. + Widgets get a type as well, which would be label, button, edit, grid, etc. + A grid could even have sub types - grid,number,string,button,date. B-) + + Required commands makes no sense, but can just be ignored. + A required widget might mean that the window HAS to have one. + + Default for a command would be the actual function. + Default being a function makes this Thing a command. + Default for a widget could be the default creation arguments - '"Press me", 1, 1, 10, 50' + + skang.thing(_M, 'foo,s,fooAlias', 'Foo is a bar, not the drinking type.', function () print('foo') end, nil, '"button", "The foo :"' 1, 1, 10, 50') + myButton = skang.widget('foo') -- Gets the default widget creation arguments. + myButton:colour(1, 2, 3, 4) + myEditor = skang.widget('foo', "edit", "Edit foo :", 5, 15, 10, 100) + myEditor:colour(1, 2, 3, 4, 5, 6, 7, 8) + myButton = 'Not default' -- myEditor and _M.foo change to. Though now _M.foo is a command, not a parameter, so maybe don't change that. + -- Though the 'quit' Thing could have a function that does quitting, this is just an example of NOT linking to a Thing. + -- If we had linked to this theoretical 'quit' Thing, then pushing that Quit button would invoke it's Thing function. + quitter = skang.widget(nil, 'button', 'Quit', 0.5, 0.5, 0.5, 0.5) + quitter:action('quit') +]] + + -- TODO - Some function stubs, for now. Fill them up later. nada = function () end -- cgit v1.1