diff options
-rw-r--r-- | ClientHamr/GuiLua/skang.lua | 211 | ||||
-rw-r--r-- | ClientHamr/GuiLua/test.lua | 12 |
2 files changed, 108 insertions, 115 deletions
diff --git a/ClientHamr/GuiLua/skang.lua b/ClientHamr/GuiLua/skang.lua index 1eb7a64..75a0cd4 100644 --- a/ClientHamr/GuiLua/skang.lua +++ b/ClientHamr/GuiLua/skang.lua | |||
@@ -52,69 +52,11 @@ The old skang argument types are - | |||
52 | ]] | 52 | ]] |
53 | 53 | ||
54 | 54 | ||
55 | -- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated. | ||
56 | 55 | ||
57 | -- Wrapping the entire module in do .. end helps if people just join a bunch of modules together, which apparently is popular. | 56 | -- Wrapping the entire module in do .. end helps if people just join a bunch of modules together, which apparently is popular. |
58 | -- By virtue of the fact we are stuffing our result into package.loaded[], just plain running this works as "loading the module". | 57 | -- By virtue of the fact we are stuffing our result into package.loaded[], just plain running this works as "loading the module". |
59 | do -- Only I'm not gonna indent this. | 58 | do -- Only I'm not gonna indent this. |
60 | 59 | ||
61 | moduleBegin = function (name, author, copyright, version, timestamp, skin) | ||
62 | local _M = {} -- This is what we return to require(). | ||
63 | |||
64 | package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end. | ||
65 | -- Returning it at the end does the same thing. | ||
66 | -- This is so that we can have all the module stuff at the top, in this function. | ||
67 | -- Should do this before any further require(), so that circular references don't blow out. | ||
68 | |||
69 | -- Save the callers environment. | ||
70 | local savedEnvironment = getfenv(3) | ||
71 | |||
72 | -- Clone the environment into _M, so the module can access everything as usual after the setfenv() below. | ||
73 | --[[ TODO - Check if this also clones _G or _ENV. And see if it leaks stuff in either direction. | ||
74 | local _G = _G -- Only sets a local _G for this function. | ||
75 | _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. | ||
76 | 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. | ||
77 | ]] | ||
78 | for k, v in pairs(savedEnvironment) do | ||
79 | _M[k] = v | ||
80 | end | ||
81 | |||
82 | _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M. | ||
83 | _M._NAME = name | ||
84 | _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name. | ||
85 | |||
86 | -- TODO - Should parse in an entire copyright message, and strip that down into bits, to put back together. | ||
87 | _M.AUTHOR = author | ||
88 | _M.COPYRIGHT = copyright .. ' ' .. author | ||
89 | -- TODO - Translate the version number into a version string. | ||
90 | _M.VERSION = version .. ' lookup version here ' .. timestamp | ||
91 | -- TODO - If there's no skin passed in, try to find the file skin .. '.skang' and load that instead. | ||
92 | _M.DEFAULT_SKANG = skin | ||
93 | |||
94 | |||
95 | --_G[_M._NAME] = _M -- Stuff it into a global of the same name. | ||
96 | -- Not such a good idea to stomp on global name space. | ||
97 | -- It's also redundant coz we get stored in package.loaded[_M._NAME] anyway. | ||
98 | -- This is why module() is broken. | ||
99 | |||
100 | _M.savedEnvironment = savedEnvironment | ||
101 | -- setfenv() sets the environment for the FUNCTION, stack level deep. | ||
102 | -- The number is the stack level - | ||
103 | -- 0 running thread, 1 current function, 2 function that called this function, etc | ||
104 | setfenv(2, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names. | ||
105 | -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd(). | ||
106 | -- 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. | ||
107 | |||
108 | return _M | ||
109 | end | ||
110 | |||
111 | -- Call this now so that from now on, this is like any other module. | ||
112 | local _M = moduleBegin('skang', 'David Seikel', '2014', '0.0', '2014-03-19 19:01:00') | ||
113 | |||
114 | -- Restore the environment. | ||
115 | moduleEnd = function (module) | ||
116 | setfenv(2, module.savedEnvironment) | ||
117 | end | ||
118 | 60 | ||
119 | --[[ Thing package | 61 | --[[ Thing package |
120 | 62 | ||
@@ -148,21 +90,15 @@ built BonsiaTree and LeafLike, for the old FDO system I built dumbtrees. | |||
148 | Perhaps some combination of the two will work here? On the other hand, | 90 | Perhaps some combination of the two will work here? On the other hand, |
149 | with Lua tables, who needs trees? lol | 91 | with Lua tables, who needs trees? lol |
150 | 92 | ||
151 | Get/set variables would be done here, though the widget package, for | 93 | Since skang Lua scripts should be defined as modules, we can use |
152 | instance, would override this to deal with the UI side, and call the | 94 | module semantics instead of get/set - |
153 | parents function to deal with the variable side - | ||
154 | |||
155 | foo:set('stuff') | ||
156 | bar = foo:get() | ||
157 | |||
158 | Also, since skang Lua scripts should be defined as modules, we can use | ||
159 | module semantics - | ||
160 | 95 | ||
161 | local other = require('otherPackageName') | 96 | local other = require('otherPackageName') |
162 | other.foo = 'stuff' | 97 | other.foo = 'stuff' |
163 | bar = other.foo | 98 | bar = other.foo |
164 | 99 | ||
165 | Other Thing things are - | 100 | Other Thing things are - |
101 | get/set The getter and setter. | ||
166 | number No idea how this was useful. | 102 | number No idea how this was useful. |
167 | skang The owning object, a Skang (actually got this, called module for now). | 103 | skang The owning object, a Skang (actually got this, called module for now). |
168 | owner The owning object, a String (module._NAME). | 104 | owner The owning object, a String (module._NAME). |
@@ -174,17 +110,50 @@ Other Thing things are - | |||
174 | Also various functions to wrap checking the security, like canDo, canRead, etc. | 110 | Also various functions to wrap checking the security, like canDo, canRead, etc. |
175 | ]] | 111 | ]] |
176 | 112 | ||
113 | |||
114 | --[[ TODO - Users might want to use two or more copies of this module. Keep that in mind. local a = require 'test', b = require 'test' might handle that though? | ||
115 | Not unless skang.thing() knows about a and b, which it wont. | ||
116 | Both a and b get the same table, not different copies of it. | ||
117 | Perhaps clone the table if it exists? Only clone the parameters, the rest can be linked back to the original. | ||
118 | Then we have to deal with widgets linking to specific clones. | ||
119 | Actually, not sure matrix-RAD solved that either. lol | ||
120 | ]] | ||
121 | |||
122 | |||
177 | -- There is no ThingSpace, now it's just in this table - | 123 | -- There is no ThingSpace, now it's just in this table - |
178 | things = {} | 124 | things = |
125 | { | ||
126 | } | ||
179 | 127 | ||
180 | Thing = | 128 | Thing = |
181 | { | 129 | { |
130 | action = 'nada', -- An optional action to perform. | ||
131 | tell = '', -- The skang command that created this Thing. | ||
132 | |||
133 | append = function (self,data) -- Append to the value of this Thing. | ||
134 | end, | ||
135 | isValid = function (self) -- Check if this Thing is valid, return resulting error messages in errors. | ||
136 | self.errors = {} | ||
137 | return true | ||
138 | end, | ||
139 | remove = function (self) -- Delete this Thing. | ||
140 | end, | ||
141 | |||
142 | errors = {}, -- A list of errors returned by isValid(). | ||
143 | |||
144 | isReadOnly = false, -- Is this Thing read only? | ||
145 | isServer = false, -- Is this Thing server side? | ||
146 | isStub = false, -- Is this Thing a stub? | ||
147 | isStubbed = false, -- Is this Thing stubbed elsewhere? | ||
148 | |||
149 | hasCrashed = 0, -- How many times this Thing has crashed. | ||
150 | |||
182 | __index = function (table, key) | 151 | __index = function (table, key) |
183 | -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. | 152 | -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. |
184 | local thing = things[key] | 153 | local thing = things[key] |
185 | 154 | ||
186 | -- First see if this is a Thing. | 155 | -- First see if this is a Thing. |
187 | if thing then return thing.default end | 156 | if thing then return table[thing.names[1] ] end |
188 | 157 | ||
189 | -- Then see if we can inherit it from Thing. | 158 | -- Then see if we can inherit it from Thing. |
190 | thing = Thing[key] | 159 | thing = Thing[key] |
@@ -217,45 +186,73 @@ Thing = | |||
217 | end | 186 | end |
218 | end, | 187 | end, |
219 | 188 | ||
220 | -- Not an actual metatable event until it gets set as the metatable above. | 189 | -- TODO - Seemed like a good idea at the time, but do we really need it? |
221 | _call = function (func, ...) | 190 | -- __call = function (func, ...) |
222 | return func.func(...) | 191 | -- return func.func(...) |
223 | end, | 192 | -- end, |
193 | } | ||
224 | 194 | ||
225 | action = 'nada', -- An optional action to perform. | ||
226 | tell = '', -- The skang command that created this Thing. | ||
227 | 195 | ||
228 | get = function (self) -- Get the value of this Thing. | 196 | -- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated. |
229 | end, | 197 | moduleBegin = function (name, author, copyright, version, timestamp, skin) |
230 | set = function (self) -- Set the value of this Thing. | 198 | local _M = {} -- This is what we return to require(). |
231 | end, | 199 | local level = 2 |
232 | append = function (self,data) -- Append to the value of this Thing. | ||
233 | end, | ||
234 | isValid = function (self) -- Check if this Thing is valid, return resulting error messages in errors. | ||
235 | self.errors = {} | ||
236 | return true | ||
237 | end, | ||
238 | remove = function (self) -- Delete this Thing. | ||
239 | end, | ||
240 | 200 | ||
241 | errors = {}, -- A list of errors returned by isValid(). | 201 | package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end. |
202 | -- Returning it at the end does the same thing. | ||
203 | -- This is so that we can have all the module stuff at the top, in this function. | ||
204 | -- Should do this before any further require(), so that circular references don't blow out. | ||
242 | 205 | ||
243 | isReadOnly = false, -- Is this Thing read only? | 206 | -- Save the callers environment. |
244 | isServer = false, -- Is this Thing server side? | 207 | local savedEnvironment = getfenv(level) |
245 | isStub = false, -- Is this Thing a stub? | ||
246 | isStubbed = false, -- Is this Thing stubbed elsewhere? | ||
247 | 208 | ||
248 | hasCrashed = 0, -- How many times this Thing has crashed. | 209 | -- Clone the environment into _M, so the module can access everything as usual after the setfenv() below. |
249 | } | 210 | --[[ TODO - Check if this also clones _G or _ENV. And see if it leaks stuff in either direction. |
211 | local _G = _G -- Only sets a local _G for this function. | ||
212 | _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. | ||
213 | 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. | ||
214 | ]] | ||
215 | for k, v in pairs(savedEnvironment) do | ||
216 | _M[k] = v | ||
217 | end | ||
250 | 218 | ||
219 | _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M. | ||
220 | _M._NAME = name | ||
221 | _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name. | ||
251 | 222 | ||
252 | --[[ TODO - Users might want to use two or more copies of this module. Keep that in mind. local a = require 'test', b = require 'test' might handle that though? | 223 | -- TODO - Should parse in an entire copyright message, and strip that down into bits, to put back together. |
253 | Not unless skang.thing() knows about a and b, which it wont. | 224 | _M.AUTHOR = author |
254 | Both a and b get the same table, not different copies of it. | 225 | _M.COPYRIGHT = copyright .. ' ' .. author |
255 | Perhaps clone the table if it exists? Only clone the parameters, the rest can be linked back to the original. | 226 | -- TODO - Translate the version number into a version string. |
256 | Then we have to deal with widgets linking to specific clones. | 227 | _M.VERSION = version .. ' lookup version here ' .. timestamp |
257 | Actually, not sure matrix-RAD solved that either. lol | 228 | -- TODO - If there's no skin passed in, try to find the file skin .. '.skang' and load that instead. |
258 | ]] | 229 | _M.DEFAULT_SKANG = skin |
230 | |||
231 | |||
232 | --_G[_M._NAME] = _M -- Stuff it into a global of the same name. | ||
233 | -- Not such a good idea to stomp on global name space. | ||
234 | -- It's also redundant coz we get stored in package.loaded[_M._NAME] anyway. | ||
235 | -- This is why module() is broken. | ||
236 | |||
237 | setmetatable(_M, Thing) | ||
238 | _M.savedEnvironment = savedEnvironment | ||
239 | -- setfenv() sets the environment for the FUNCTION, stack level deep. | ||
240 | -- The number is the stack level - | ||
241 | -- 0 running thread, 1 current function, 2 function that called this function, etc | ||
242 | setfenv(level, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names. | ||
243 | -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd(). | ||
244 | -- 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. | ||
245 | |||
246 | return _M | ||
247 | end | ||
248 | |||
249 | -- Restore the environment. | ||
250 | moduleEnd = function (module) | ||
251 | setfenv(2, module.savedEnvironment) | ||
252 | end | ||
253 | |||
254 | -- Call this now so that from now on, this is like any other module. | ||
255 | local _M = moduleBegin('skang', 'David Seikel', '2014', '0.0', '2014-03-19 19:01:00') | ||
259 | 256 | ||
260 | 257 | ||
261 | --[[ TODO - It might be worth it to combine parameters and commands, since in Lua, functions are first class types like numbers and strings. | 258 | --[[ TODO - It might be worth it to combine parameters and commands, since in Lua, functions are first class types like numbers and strings. |
@@ -320,7 +317,7 @@ thing = function (module, names, help, default, types, widget, required, acl, bo | |||
320 | -- Set it all up. | 317 | -- Set it all up. |
321 | -- TODO - might want to merge into pre existing Thing instead of over writing like this. | 318 | -- TODO - might want to merge into pre existing Thing instead of over writing like this. |
322 | local thing = {module = module, names = n, help = help, default = default, types = t, widget = widget, required = required, acl = acl, boss = boss, } | 319 | local thing = {module = module, names = n, help = help, default = default, types = t, widget = widget, required = required, acl = acl, boss = boss, } |
323 | setmetatable(thing, {__call = Thing._call, __index=Thing.__index}) | 320 | setmetatable(thing, Thing) |
324 | -- Stash the Thing under all of it's names. | 321 | -- Stash the Thing under all of it's names. |
325 | for i, v in ipairs(thing.names) do | 322 | for i, v in ipairs(thing.names) do |
326 | things[v] = thing | 323 | things[v] = thing |
@@ -331,10 +328,6 @@ end | |||
331 | 328 | ||
332 | -- TODO - Some function stubs, for now. Fill them up later. | 329 | -- TODO - Some function stubs, for now. Fill them up later. |
333 | nada = function () end | 330 | nada = function () end |
334 | get = function (name) | ||
335 | end | ||
336 | set = function (name, value) | ||
337 | end | ||
338 | 331 | ||
339 | clear = function () | 332 | clear = function () |
340 | end | 333 | end |
@@ -349,8 +342,6 @@ quit = function () | |||
349 | end | 342 | end |
350 | 343 | ||
351 | thing(_M, 'nada', 'Do nothing.', nada) | 344 | thing(_M, 'nada', 'Do nothing.', nada) |
352 | thing(_M, 'get', 'Get the current value of an existing thing.', get, 'name') | ||
353 | thing(_M, 'set', 'Set the current value of an existing Thing.', set, 'name,data') | ||
354 | thing(_M, 'clear', 'The current skin is cleared of all widgets.', clear) | 345 | thing(_M, 'clear', 'The current skin is cleared of all widgets.', clear) |
355 | thing(_M, 'window', 'The size and title of the application Frame.', window, 'x,y,name', nil, nil, 'GGG') | 346 | thing(_M, 'window', 'The size and title of the application Frame.', window, 'x,y,name', nil, nil, 'GGG') |
356 | thing(_M, 'module', 'Load a module.', module, 'file,acl') | 347 | thing(_M, 'module', 'Load a module.', module, 'file,acl') |
@@ -398,7 +389,7 @@ end | |||
398 | {"servlet", "doIfServlet", "action", "Only do this if we are a servlet.", "", ""}, | 389 | {"servlet", "doIfServlet", "action", "Only do this if we are a servlet.", "", ""}, |
399 | {"do", "doThing", "action", "Do this action.", "", ""}, | 390 | {"do", "doThing", "action", "Do this action.", "", ""}, |
400 | {"grab", "getFile", "URL", "Grab a file from a URL.", "", ""}, | 391 | {"grab", "getFile", "URL", "Grab a file from a URL.", "", ""}, |
401 | -- {"get", "getThing", "name", "Get the current value of an existing thing.", "", ""}, | 392 | {"get", "getThing", "name", "Get the current value of an existing thing.", "", ""}, |
402 | {"gimmeskin", "gimmeSkin", "", "Returns the modules default skin.", "", ""}, | 393 | {"gimmeskin", "gimmeSkin", "", "Returns the modules default skin.", "", ""}, |
403 | {"help", "helpThing", "file", "Show help page.", "", ""}, | 394 | {"help", "helpThing", "file", "Show help page.", "", ""}, |
404 | {"nada", "nothing", "data", "Does nothing B-).", "", ""}, | 395 | {"nada", "nothing", "data", "Does nothing B-).", "", ""}, |
@@ -408,7 +399,7 @@ end | |||
408 | {"quiet", "quiet", "", "Output errors and warnings only.", "", ""}, | 399 | {"quiet", "quiet", "", "Output errors and warnings only.", "", ""}, |
409 | {"remove", "removeThing", "name", "Remove an existing thing.", "", ""}, | 400 | {"remove", "removeThing", "name", "Remove an existing thing.", "", ""}, |
410 | {"sethelp", "setHelp", "name,data", "Change the help for something.", "", ""}, | 401 | {"sethelp", "setHelp", "name,data", "Change the help for something.", "", ""}, |
411 | -- {"set", "setThing", "name,data", "Set the current value of an existing Thing.", "", ""}, | 402 | {"set", "setThing", "name,data", "Set the current value of an existing Thing.", "", ""}, |
412 | -- {"skang", "skangRead", "URL", "Parse the contents of a skang file or URL.", "", ""}, | 403 | -- {"skang", "skangRead", "URL", "Parse the contents of a skang file or URL.", "", ""}, |
413 | -- {"quit", "startQuit", "", "Quit, exit, remove thyself.", "", ""}, | 404 | -- {"quit", "startQuit", "", "Quit, exit, remove thyself.", "", ""}, |
414 | {"stopwhinging", "stopWhinging", "", "Clear all messages.", "", ""}, | 405 | {"stopwhinging", "stopWhinging", "", "Clear all messages.", "", ""}, |
diff --git a/ClientHamr/GuiLua/test.lua b/ClientHamr/GuiLua/test.lua index 470fe23..6c48ca6 100644 --- a/ClientHamr/GuiLua/test.lua +++ b/ClientHamr/GuiLua/test.lua | |||
@@ -34,8 +34,8 @@ skang.thing(_M, 'fooble,f', 'Help text goes here', 1, nil, '"edit", "The fooble: | |||
34 | skang.thing(_M, 'bar', 'Help text', "Default") | 34 | skang.thing(_M, 'bar', 'Help text', "Default") |
35 | 35 | ||
36 | -- We can use inline functions if we don't need the function internally. | 36 | -- We can use inline functions if we don't need the function internally. |
37 | skang.thing(_M, 'func', 'Help Text', function (arg1, arg2) | 37 | skang.thing(_M, 'ffunc', 'Help Text', function (arg1, arg2) |
38 | print('Inside test.func ' .. arg1 .. ', ' .. arg2) | 38 | print('Inside test.ffunc ' .. arg1 .. ', ' .. arg2) |
39 | end, 'number,string') | 39 | end, 'number,string') |
40 | 40 | ||
41 | print('Ending soon') | 41 | print('Ending soon') |
@@ -47,6 +47,8 @@ end | |||
47 | -- Test it. | 47 | -- Test it. |
48 | local skang = require 'skang' | 48 | local skang = require 'skang' |
49 | local test = require 'test' | 49 | local test = require 'test' |
50 | print('End ' .. test.bar .. ' ' .. test.VERSION .. ' ' .. skang.things.func.help .. ' ->> ' .. skang.things.f.action) | 50 | print('End ' .. test.bar .. ' ' .. test.VERSION .. ' ' .. skang.things.ffunc.help .. ' ->> ' .. skang.things.f.action) |
51 | test.func('one', 2) | 51 | test.ffunc('one', 2) |
52 | skang.things.func('seven', 'aight') | 52 | --skang.things.ffunc('seven', 'aight') |
53 | test.f = 42 | ||
54 | print('f is now ' .. test.fooble .. ' ' .. test.f .. ' ' .. skang.things.f.help .. ' ' .. skang.things.fooble.help) | ||