Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- I actually wrote this for a stackoverflow question:
- -- http://stackoverflow.com/questions/35369854/is-it-possible-to-make-a-collapsing-variables-without-making-individual-function/35385290#35385290
- -- I had fun writing it and released it on stackoverflow anyway, so now I also put it on my pastebin.
- -- There's some kind of summary-ish thing at the bottom of the script, along with the output.
- local function getNeededVars(tab,func)
- local needed,this = {}
- this = setmetatable({},{
- __index = function(s,k)
- -- See if the requested variable exists.
- -- If it doesn't, we obviously complain.
- -- If it does, we log it and return the value.
- local var = tab.vars[k]
- if not var then
- error("Eh, "..k.." isn't registered (yet?)",5)
- end needed[k] = true return tab.vals[k]
- end;
- }) func(this) return needed
- end
- local function updateStuff(self,key,done)
- for k,v in pairs(self.levars) do
- if v.needed and v.needed[key] then
- if not done[v] then done[v] = true
- self.vals[v.name] = v.func(self)
- updateStuff(self,v.name,done)
- end
- end
- end
- end
- local function createSubTable(self,key,tab)
- return setmetatable({},{
- __newindex = function(s,k,v)
- tab[k] = v updateStuff(self,key,{})
- end; __index = tab;
- })
- end
- local dependenceMeta
- dependenceMeta = {
- __index = function(self,k)
- -- Allow methods, because OOP
- local method = dependenceMeta[k]
- if method then return method end
- local variable = self.vars[k]
- if not variable then
- error("Variable "..k.." not found",2)
- end return self.vals[k]
- end;
- __newindex = function(self,k,v)
- local variable = self.vars[k]
- if not variable then
- error("Use :Register() to add stuff",2)
- elseif type(v) == "table" then
- self.vals[k] = createSubTable(self,k,v)
- return updateStuff(self,k,{})
- end self.vals[k] = v updateStuff(self,k,{})
- end
- }
- function dependenceMeta:Register(var,value)
- local varobject = {func=value,name=var}
- self.vars[var] = varobject
- table.insert(self.levars,varobject)
- if type(value) == "function" then
- varobject.needed = getNeededVars(self,value)
- self.vals[var] = value(self)
- elseif type(value) == "table" then
- self.vals[var] = createSubTable(self,var,value)
- elseif value then
- self.vals[var] = value
- end
- end
- function dependenceMeta:RegisterAll(tab)
- for k,v in pairs(tab) do
- self:Register(k,v)
- end
- end
- local function DependenceTable()
- return setmetatable({
- levars = {};
- vars = {};
- vals = {};
- },dependenceMeta)
- end
- local test = DependenceTable()
- test:Register("border",{
- x=20; y=50;
- height=200;
- width=100;
- })
- test:Register("body",function(self)
- return {x=self.border.x+1,y=self.border.y+1,
- height=self.border.height-2,
- width=self.border.width-2}
- end)
- test:Register("font",function(self)
- local size = (self.body.height+2)-(math.floor((self.body.height+2)/4)+1);
- return { size = size; -- Since we use it in the table constructor...
- height = size-4; --love.graphics.setNewFont( self.font.size ):getHeight();
- -- I don't run this on love, so can't use the above line. Should work though.
- }
- end)
- test:Register("padding",function(self)
- local height = math.floor(self.border.height*(2/29))
- return { height = height; width = height*3 } -- again dependency
- end)
- test:Register("text",{input=""}) -- Need this initially to keep input
- test:Register("text",function(self)
- return { input = self.text.input;
- centerHeight = math.ceil(self.body.y+((self.body.height-self.font.height)/2));
- left = self.body.x+self.padding.width+self.padding.height;
- }
- end)
- test:Register("backspace",{key = false, rate = 3, time = 0, pausetime = 20, pause = true})
- -- Again, didn't use gui.id() on the line below because my lack of LÖVE
- test:Register("config",{active=true,devmode=false,debug=false,id=123,type='textbox'})
- print("border.x=20, test.text.left="..test.text.left)
- test.border = {x=30; y=50; height=200; width=100;}
- print("border.x=30, test.text.left="..test.text.left)
- test.border.x = 40
- print("border.x=40, test.text.left="..test.text.left)
- --[[OUTPUT FROM ABOVE
- border.x=20, test.text.left=73
- border.x=30, test.text.left=83
- border.x=40, test.text.left=93
- ]]
- if true then return end
- -- API "summary" below
- local hmm = DependenceTable() -- Create a new one
- print(hmm.field) -- Would error, "field" doesn't exist yet
- -- Sets the property 'idk' to 123.
- -- Everything except functions and tables are "primitive".
- -- They're like constants, they never change unless you do it.
- hmm:Register("idk",123)
- -- If you want to actually set a regular table/function, you
- -- can register a random value, then do hmm.idk = func/table
- -- (the "constructor registering" only happens during :Register())
- -- Sets the field to a constructor, which first gets validated.
- -- During registering, the constructor is already called once.
- -- Afterwards, it'll get called when it has to update.
- -- (Whenever 'idk' changes, since 'field' depends on 'idk' here)
- hmm:Register("field",function(self) return self.idk+1 end)
- -- This errors because 'nonexistant' isn't reigstered yet
- hmm:Register("error",function(self) return self.nonexistant end)
- -- Basicly calls hmm:Register() twice with key/value as parameters
- hmm:RegisterAll{
- lower = function(self) return self.field - 5 end;
- higher = function(self) return self.field + 5 end;
- }
- -- This sets the property 'idk' to 5.
- -- Since 'field' depends on this property, it'll also update.
- -- Since 'lower' and 'higher' depend on 'field', they too.
- -- (It happens in order, so there should be no conflicts)
- hmm.idk = 5
- -- This prints 6 since 'idk' is 5 and 'field' is idk+1
- print(hmm.field)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement