aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ClientHamr/GuiLua/skang.lua
diff options
context:
space:
mode:
authorDavid Walter Seikel2014-04-01 22:52:55 +1000
committerDavid Walter Seikel2014-04-01 22:52:55 +1000
commit61f2d31ba18f0cc516893ce3aabc24008e900e29 (patch)
treeea23e6ecb00ae09ce6896425a25eced585e16eba /ClientHamr/GuiLua/skang.lua
parentMassage Thing design notes into docs, and clean up some Stuff as a result. (diff)
downloadSledjHamr-61f2d31ba18f0cc516893ce3aabc24008e900e29.zip
SledjHamr-61f2d31ba18f0cc516893ce3aabc24008e900e29.tar.gz
SledjHamr-61f2d31ba18f0cc516893ce3aabc24008e900e29.tar.bz2
SledjHamr-61f2d31ba18f0cc516893ce3aabc24008e900e29.tar.xz
Separate out the metatable __ stuff from Thing, put it into Mum.
Diffstat (limited to 'ClientHamr/GuiLua/skang.lua')
-rw-r--r--ClientHamr/GuiLua/skang.lua140
1 files changed, 70 insertions, 70 deletions
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 -
57do -- Only I'm not gonna indent this. 57do -- Only I'm not gonna indent this.
58 58
59 59
60-- There is no ThingSpace, or Stuff, now it's all just in this meta table. Predefined here coz moduleBegin references Thing.
61local Thing = {}
62
63
64-- TODO - This needs to be expanded a bit to cover things like 1.42 60-- TODO - This needs to be expanded a bit to cover things like 1.42
65local versions = { 61local versions = {
66 '0%.0', 'unwritten', 'Just a stub, no code at all, or completely non-existant.', 62 '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
427 parent[thing] = value -> __newindex(parent, thing, value) -> meta(parent).__values[thing] = value 423 parent[thing] = value -> __newindex(parent, thing, value) -> meta(parent).__values[thing] = value
428 424
429 425
430A Stuff is a description table of a Thing that includes - 426Each Thing has a description table that includes -
431 names - An array of names, the first one is the "official" name. 427 names - An array of names, the first one is the "official" name.
432 types - An array of types, the first one is the "official" type. 428 types - An array of types, the first one is the "official" type.
433 help - A descriptive text for humans to read. 429 help - A descriptive text for humans to read.
@@ -436,14 +432,15 @@ A Stuff is a description table of a Thing that includes -
436 required - If the Thing is required. 432 required - If the Thing is required.
437 isValid - A function that tests if the Thing is valid. 433 isValid - A function that tests if the Thing is valid.
438 errors - Any errors related to the Thing. 434 errors - Any errors related to the Thing.
439 isKeyed - Is this thing itself a parent for Stuff that is stored under an arbitrary key. 435 isKeyed - Is this a parent for Things that are stored under an arbitrary key.
440 stuff - An array of Stuff's for sub Things, so Things that are tables can have their own Things. 436 stuff - An array of descriptions for sub Things, so Things that are tables can have their own Things.
441 and other things that aren't actually used yet. 437 and other things that aren't actually used yet.
442All things that a Stuff doesn't have should be inherited from the Thing table. 438All things that a description doesn't have should be inherited from the Thing table.
443Stuff's should be able to be easily shared by various Things. 439 setmetatable(aStuff, {__index = Thing})
440Descriptions should be able to be easily shared by various Things.
444 441
445 442
446A parent's metatable has __self, which is it's own Stuff. 443A parent's metatable has __self, which is it's own description.
447A parent is free to use it's own name space for anything it wants. 444A parent is free to use it's own name space for anything it wants.
448Only the variables it specifies as managed Things are dealt with here. 445Only the variables it specifies as managed Things are dealt with here.
449 446
@@ -451,13 +448,16 @@ Only the variables it specifies as managed Things are dealt with here.
451TODO - 448TODO -
452 test.foo -> test.__index(test, 'foo') -> test.__values[foo]; if that's nil, and test.stuff[foo], then return an empty table instead? 449 test.foo -> test.__index(test, 'foo') -> test.__values[foo]; if that's nil, and test.stuff[foo], then return an empty table instead?
453 stuff.s = {a='foo'} -> changes a, deletes everything else, or should. 450 stuff.s = {a='foo'} -> changes a, deletes everything else, or should.
454 Got rid of Stuff.parent, but do we still need a parent pointer? 451 Do we still need a parent pointer?
455 Should be in __values I guess. 452 Should be in __values I guess.
456 __values[key].value 453 __values[key].value
457 __values[key].parent 454 __values[key].parent
458]] 455]]
459 456
460 457
458-- There is no ThingSpace, or Stuff, now it's all just in this meta table.
459local Thing = {}
460
461-- Default things values. 461-- Default things values.
462-- help - help text describing this Thing. 462-- help - help text describing this Thing.
463-- default - the default value. This could be a funcion, making this a command. 463-- 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().
495Thing.isValid = function (self, parent) -- Check if this Thing is valid, return resulting error messages in errors. 495Thing.isValid = function (self, parent) -- Check if this Thing is valid, return resulting error messages in errors.
496 -- Anything that overrides this method, should call this super method first. 496 -- Anything that overrides this method, should call this super method first.
497 local name = self.names[1] 497 local name = self.names[1]
498 local mumThing = getmetatable(parent) 498 local metaMum = getmetatable(parent)
499 local value = mumThing.__values[name] 499 local value = metaMum.__values[name]
500 local mum = metaMum.__self.names[1]
500 501
501 local t = type(value) or 'nil' 502 local t = type(value) or 'nil'
502 self.errors = {} 503 self.errors = {}
503 -- TODO - Naturally there should be formatting functions for stuffing Thing stuff into strings, and overridable output functions. 504 -- TODO - Naturally there should be formatting functions for stuffing Thing stuff into strings, and overridable output functions.
504 if 'nil' == t then 505 if 'nil' == t then
505 if self.required then table.insert(self.errors, mumThing.__self.names[1] .. '.' .. name .. ' is required!') end 506 if self.required then table.insert(self.errors, mum .. '.' .. name .. ' is required!') end
506 else 507 else
507 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 .. '!') 508 if self.types[1] ~= t then table.insert(self.errors, mum .. '.' .. name .. ' should be a ' .. self.types[1] .. ', but it is a ' .. t .. '!')
508 else 509 else
509 if 'number' == t then value = '' .. value end 510 if 'number' == t then value = '' .. value end
510 if ('number' == t) or ('string' == t) then 511 if ('number' == t) or ('string' == t) then
511 if 1 ~= string.find(value, '^' .. self.pattern .. '$') then table.insert(self.errors, mumThing.__self.names[1] .. '.' .. name .. ' does not match pattern "' .. self.pattern .. '"!') end 512 if 1 ~= string.find(value, '^' .. self.pattern .. '$') then table.insert(self.errors, mum .. '.' .. name .. ' does not match pattern "' .. self.pattern .. '"!') end
512 end 513 end
513 end 514 end
514 end 515 end
@@ -528,45 +529,44 @@ Thing.remove = function (self) -- Delete this Thing.
528end 529end
529 530
530 531
531Thing.__index = function (parent, key) 532local Mum =
533{
534__index = function (parent, key)
532 -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. 535 -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist.
533 -- TODO - Java skang called isValid() on get(). On the other hand, doesn't seem to call it on set(), but calls it on append(). 536 -- TODO - Java skang called isValid() on get(). On the other hand, doesn't seem to call it on set(), but calls it on append().
534 -- Ah, it was doing isValid() on setStufflet(). 537 -- Ah, it was doing isValid() on setStufflet().
535 538
536 -- First see if this is a Thing. 539 -- First see if this is a Thing.
537 local mumThing = getmetatable(parent) 540 local metaMum = getmetatable(parent)
538 local thingy
539 541
540 if mumThing and mumThing.__self then 542 if metaMum and metaMum.__self then
541 thingy = mumThing.__self.stuff[key] 543 local thingy = metaMum.__self.stuff[key]
542 if thingy then 544 if thingy then
543 local name = thingy.names[1]; 545 return metaMum.__values[thingy.names[1] ] or thingy.default
544 return mumThing.__values[name] or thingy.default
545 end 546 end
546 end 547 end
547 548
548 -- Then see if we can inherit it from Thing. 549 -- Then see if we can inherit it from Thing.
549 return Thing[key] 550 return Thing[key]
550end 551end,
551 552
552Thing.__newindex = function (parent, key, value) 553__newindex = function (parent, key, value)
553 -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. 554 -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist.
554 local mumThing = getmetatable(parent)
555 555
556 if mumThing and mumThing.__self then 556 -- First see if this is a Thing.
557 -- This is a proxy table, the values never exist in the real table. In theory. 557 local metaMum = getmetatable(parent)
558 558
559 -- Find the Thing and get it done. 559 if metaMum and metaMum.__self then
560 local thingy = mumThing.__self.stuff[key] 560 local thingy = metaMum.__self.stuff[key]
561 561
562 if not thingy then 562 if not thingy then
563 -- Deal with setting a new Stuff[key]. 563 -- Deal with setting a new Keyed table entry.
564 if mumThing.__self.isKeyed and (nil == mumThing.__values[key]) then 564 if metaMum.__self.isKeyed and (nil == metaMum.__values[key]) then
565 local newThing = copy(parent, key) 565 local newThing = copy(parent, key)
566 rawset(mumThing.__values, key, newThing) 566 rawset(metaMum.__values, key, newThing)
567 thingy = {names={key}, types={'table'}, parent=newThing, stuff=getmetatable(newThing).__self.stuff, } 567 thingy = {names={key}, types={'table'}, parent=newThing, stuff=getmetatable(newThing).__self.stuff, }
568 setmetatable(thingy, {__index = Thing}) -- To pick up isValid, pattern, and the other stuff by default. 568 setmetatable(thingy, {__index = Thing}) -- To pick up isValid, pattern, and the other stuff by default.
569 mumThing.__self.stuff[key] = thingy 569 metaMum.__self.stuff[key] = thingy
570 end 570 end
571 end 571 end
572 572
@@ -575,8 +575,8 @@ Thing.__newindex = function (parent, key, value)
575 local valueMeta 575 local valueMeta
576 576
577 if 'table' == type(value) then 577 if 'table' == type(value) then
578 -- Coz setting it via mumThing screws with the __index stuff somehow. 578 -- Coz setting it via metaMum screws with the __index stuff somehow.
579 local oldValue = mumThing.__values[name] 579 local oldValue = metaMum.__values[name]
580 if 'table' == type(oldValue) then 580 if 'table' == type(oldValue) then
581 valueMeta = getmetatable(oldValue) 581 valueMeta = getmetatable(oldValue)
582 if valueMeta then 582 if valueMeta then
@@ -589,7 +589,7 @@ Thing.__newindex = function (parent, key, value)
589 end 589 end
590 end 590 end
591 end 591 end
592 if nil == valueMeta then mumThing.__values[name] = value end 592 if nil == valueMeta then metaMum.__values[name] = value end
593 -- NOTE - invalid values are still stored, this is by design. 593 -- NOTE - invalid values are still stored, this is by design.
594 if not thingy:isValid(parent) then 594 if not thingy:isValid(parent) then
595 for i, v in ipairs(thingy.errors) do 595 for i, v in ipairs(thingy.errors) do
@@ -603,10 +603,22 @@ Thing.__newindex = function (parent, key, value)
603 end 603 end
604 604
605 rawset(parent, key, value) -- Stuff it normally. 605 rawset(parent, key, value) -- Stuff it normally.
606end 606end,
607 607
608Thing.__call = function (func, ...) 608__call = function (func, ...)
609 return thingasm(func, ...) -- (func, {...}) 609 return thingasm(func, ...) -- (func, {...})
610end,
611
612}
613
614newMum = function ()
615 local result = {}
616 for k, v in pairs(Mum) do
617 result[k] = v
618 end
619 result.__self = {stuff={}}
620 result.__values = {}
621 return result
610end 622end
611 623
612 624
@@ -614,20 +626,19 @@ end
614--[[ It can be called in many different ways - 626--[[ It can be called in many different ways -
615 627
616It can be called with positional arguments - (names, help, default, types, widget, required, acl, boss) 628It can be called with positional arguments - (names, help, default, types, widget, required, acl, boss)
617Or it can be called with a table - {names, help, pattern='...', acl='rwx'} 629Or it can be called with a table - {names, help, pattern='.*', acl='rwx'}
618 630
619The first argument can be another Thing (the parent), or a string list of names (see below). 631The first argument can be another Thing (the parent), or a string list of names (see below).
620 632
621It can be called by itself, with no parent specified - 633It can be called by itself, with no parent specified -
622 thingasm('foo', 'help text) 634 thingasm('foo', 'help text)
623
624In this case the surrounding Lua environment becomes the parent of foo. 635In this case the surrounding Lua environment becomes the parent of foo.
625 If the first argument (or first in the table) is a string, then it's this form. 636 If the first argument (or first in the table) is a string, then it's this form.
626All others include the parent as the first argument, which would be a table. 637All others include the parent as the first argument, which would be a table.
627 638
628It can be called by calling the parent as a function - 639It can be called by calling the parent as a function -
629 foo('bar', 'some help', types='table') -- ___call(foo, 'bar', ...) And now foo is the parent. 640 foo('bar', 'some help', types='table') -- ___call(foo, 'bar', ...) And now foo is the parent.
630 foo.bar{'baz', types='Stuff'} -- thingasm({foo.bar, 'baz', ...}) 641 foo.bar{'baz', types='Keyed'} -- thingasm({foo.bar, 'baz', ...})
631 foo.bar.baz{'field0'} -- thingasm({foo.bar.baz, 'field0'}) 642 foo.bar.baz{'field0'} -- thingasm({foo.bar.baz, 'field0'})
632 foo.bar.baz{'field1'} 643 foo.bar.baz{'field1'}
633]] 644]]
@@ -669,24 +680,16 @@ thingasm = function (names, ...)
669 680
670 -- Grab the environment of the calling function if no parent was passed in. 681 -- Grab the environment of the calling function if no parent was passed in.
671 parent = parent or getfenv(2) 682 parent = parent or getfenv(2)
672 local mumThing = getmetatable(parent) 683 local metaMum = getmetatable(parent)
673 if nil == mumThing then 684 -- Coz at module creation time, Thing is an empty table, or in case this is for a new parent.
674 mumThing = {} 685 if nil == metaMum then
675 setmetatable(parent, mumThing) 686 metaMum = newMum()
676 end 687 metaMum.__self.names = {parent._NAME or 'NoName'}
677 -- Coz at module creation time, Thing is an empty table, and setmetatable(mumThing, {__index = Thing}) doesn't do the right thing. 688 if parent._NAME then metaMum.__self.types = {'Module'} end
678 if nil == mumThing.__self then 689 setmetatable(parent, metaMum)
679 mumThing.__self = {stuff={}}
680 -- Seems this does not deal with __index and __newindex, and also screws up stuff somehow.
681-- setmetatable(mumThing, {__index = Thing})
682 mumThing.__self.names = {parent._NAME or 'NoName'}
683 if parent._NAME then mumThing.__self.types = {'Module'} end
684 mumThing.__values = {}
685 mumThing.__index = Thing.__index
686 mumThing.__newindex = Thing.__newindex
687 end 690 end
688 691
689 local thingy = mumThing.__self.stuff[name] 692 local thingy = metaMum.__self.stuff[name]
690 if not thingy then -- This is a new Thing. 693 if not thingy then -- This is a new Thing.
691 new = true 694 new = true
692 thingy = {} 695 thingy = {}
@@ -721,32 +724,29 @@ thingasm = function (names, ...)
721 if '' == types then types = typ end 724 if '' == types then types = typ end
722 thingy.types = csv2table(types) 725 thingy.types = csv2table(types)
723 726
727 -- Deal with Keyed and tables.
724 if 'Keyed' == thingy.types[1] then 728 if 'Keyed' == thingy.types[1] then
725 thingy.types[1] = 'table' 729 thingy.types[1] = 'table'
726 thingy.isKeyed = true 730 thingy.isKeyed = true
727 end 731 end
728 if 'table' == thingy.types[1] then 732 if 'table' == thingy.types[1] then
733 -- Default in this case becomes a parent.
729 if '' == thingy.default then thingy.default = {} end 734 if '' == thingy.default then thingy.default = {} end
730 setmetatable(thingy.default, 735 local thisMum = newMum()
731 { 736 thisMum.__self = thingy
732 __self = thingy, 737 setmetatable(thingy.default, thisMum)
733 __values = {},
734 __index = Thing.__index,
735 __newindex = Thing.__newindex,
736 __call = Thing.__call,
737 })
738 end 738 end
739 739
740 -- Remove old names, then stash the Thing under all of it's new names. 740 -- Remove old names, then stash the Thing under all of it's new names.
741 for i, v in ipairs(oldNames) do 741 for i, v in ipairs(oldNames) do
742 mumThing.__self.stuff[v] = nil 742 metaMum.__self.stuff[v] = nil
743 end 743 end
744 for i, v in ipairs(thingy.names) do 744 for i, v in ipairs(thingy.names) do
745 mumThing.__self.stuff[v] = thingy 745 metaMum.__self.stuff[v] = thingy
746 end 746 end
747 747
748 -- This triggers the Thing.__newindex metamethod above. If nothing else, it triggers thingy.isValid() 748 -- This triggers the Mum.__newindex metamethod above. If nothing else, it triggers thingy.isValid()
749 if new and not mumThing.__self.isKeyed then parent[name] = thingy.default end 749 if new and not metaMum.__self.isKeyed then parent[name] = thingy.default end
750end 750end
751 751
752 752