Advertisement
einsteinK

Class DependenceTable

Feb 13th, 2016
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.58 KB | None | 0 0
  1. -- I actually wrote this for a stackoverflow question:
  2. -- http://stackoverflow.com/questions/35369854/is-it-possible-to-make-a-collapsing-variables-without-making-individual-function/35385290#35385290
  3. -- I had fun writing it and released it on stackoverflow anyway, so now I also put it on my pastebin.
  4. -- There's some kind of summary-ish thing at the bottom of the script, along with the output.
  5.  
  6. local function getNeededVars(tab,func)
  7.     local needed,this = {}
  8.     this = setmetatable({},{
  9.         __index = function(s,k)
  10.             -- See if the requested variable exists.
  11.             -- If it doesn't, we obviously complain.
  12.             -- If it does, we log it and return the value.
  13.             local var = tab.vars[k]
  14.             if not var then
  15.                 error("Eh, "..k.." isn't registered (yet?)",5)
  16.             end needed[k] = true return tab.vals[k]
  17.         end;
  18.     }) func(this) return needed
  19. end
  20.  
  21. local function updateStuff(self,key,done)
  22.     for k,v in pairs(self.levars) do
  23.         if v.needed and v.needed[key] then
  24.             if not done[v] then done[v] = true
  25.                 self.vals[v.name] = v.func(self)
  26.                 updateStuff(self,v.name,done)
  27.             end
  28.         end
  29.     end
  30. end
  31.  
  32. local function createSubTable(self,key,tab)
  33.     return setmetatable({},{
  34.         __newindex = function(s,k,v)
  35.             tab[k] = v updateStuff(self,key,{})
  36.         end; __index = tab;
  37.     })
  38. end
  39.  
  40. local dependenceMeta
  41. dependenceMeta = {
  42.     __index = function(self,k)
  43.         -- Allow methods, because OOP
  44.         local method = dependenceMeta[k]
  45.         if method then return method end
  46.         local variable = self.vars[k]
  47.         if not variable then
  48.             error("Variable "..k.." not found",2)
  49.         end return self.vals[k]
  50.     end;
  51.     __newindex = function(self,k,v)
  52.         local variable = self.vars[k]
  53.         if not variable then
  54.             error("Use :Register() to add stuff",2)
  55.         elseif type(v) == "table" then
  56.             self.vals[k] = createSubTable(self,k,v)
  57.             return updateStuff(self,k,{})
  58.         end self.vals[k] = v updateStuff(self,k,{})
  59.     end
  60. }
  61. function dependenceMeta:Register(var,value)
  62.     local varobject = {func=value,name=var}
  63.     self.vars[var] = varobject
  64.     table.insert(self.levars,varobject)
  65.     if type(value) == "function" then
  66.         varobject.needed = getNeededVars(self,value)
  67.         self.vals[var] = value(self)
  68.     elseif type(value) == "table" then
  69.         self.vals[var] = createSubTable(self,var,value)
  70.     elseif value then
  71.         self.vals[var] = value
  72.     end
  73. end
  74. function dependenceMeta:RegisterAll(tab)
  75.     for k,v in pairs(tab) do
  76.         self:Register(k,v)
  77.     end
  78. end
  79.  
  80. local function DependenceTable()
  81.     return setmetatable({
  82.         levars = {};
  83.         vars = {};
  84.         vals = {};
  85.     },dependenceMeta)
  86. end
  87.  
  88. local test = DependenceTable()
  89. test:Register("border",{
  90.     x=20; y=50;
  91.     height=200;
  92.     width=100;
  93. })
  94. test:Register("body",function(self)
  95.     return {x=self.border.x+1,y=self.border.y+1,
  96.         height=self.border.height-2,
  97.         width=self.border.width-2}
  98. end)
  99. test:Register("font",function(self)
  100.     local size = (self.body.height+2)-(math.floor((self.body.height+2)/4)+1);
  101.     return { size = size; -- Since we use it in the table constructor...
  102.         height = size-4; --love.graphics.setNewFont( self.font.size ):getHeight();
  103.         -- I don't run this on love, so can't use the above line. Should work though.
  104.     }
  105. end)
  106. test:Register("padding",function(self)
  107.     local height = math.floor(self.border.height*(2/29))
  108.     return { height = height; width = height*3 } -- again dependency
  109. end)
  110. test:Register("text",{input=""}) -- Need this initially to keep input
  111. test:Register("text",function(self)
  112.     return { input = self.text.input;
  113.         centerHeight = math.ceil(self.body.y+((self.body.height-self.font.height)/2));
  114.         left = self.body.x+self.padding.width+self.padding.height;
  115.     }
  116. end)
  117. test:Register("backspace",{key = false, rate = 3, time = 0, pausetime = 20, pause = true})
  118. -- Again, didn't use gui.id() on the line below because my lack of LÖVE
  119. test:Register("config",{active=true,devmode=false,debug=false,id=123,type='textbox'})
  120.  
  121. print("border.x=20, test.text.left="..test.text.left)
  122. test.border = {x=30; y=50; height=200; width=100;}
  123. print("border.x=30, test.text.left="..test.text.left)
  124. test.border.x = 40
  125. print("border.x=40, test.text.left="..test.text.left)
  126.  
  127. --[[OUTPUT FROM ABOVE
  128. border.x=20, test.text.left=73
  129. border.x=30, test.text.left=83
  130. border.x=40, test.text.left=93
  131. ]]
  132.  
  133. if true then return end
  134. -- API "summary" below
  135.  
  136. local hmm = DependenceTable() -- Create a new one
  137. print(hmm.field) -- Would error, "field" doesn't exist yet
  138.  
  139. -- Sets the property 'idk' to 123.
  140. -- Everything except functions and tables are "primitive".
  141. -- They're like constants, they never change unless you do it.
  142. hmm:Register("idk",123)
  143. -- If you want to actually set a regular table/function, you
  144. -- can register a random value, then do hmm.idk = func/table
  145. -- (the "constructor registering" only happens during :Register())
  146.  
  147. -- Sets the field to a constructor, which first gets validated.
  148. -- During registering, the constructor is already called once.
  149. -- Afterwards, it'll get called when it has to update.
  150. -- (Whenever 'idk' changes, since 'field' depends on 'idk' here)
  151. hmm:Register("field",function(self) return self.idk+1 end)
  152. -- This errors because 'nonexistant' isn't reigstered yet
  153. hmm:Register("error",function(self) return self.nonexistant end)
  154. -- Basicly calls hmm:Register() twice with key/value as parameters
  155. hmm:RegisterAll{
  156.     lower = function(self) return self.field - 5 end;
  157.     higher = function(self) return self.field + 5 end;
  158. }
  159. -- This sets the property 'idk' to 5.
  160. -- Since 'field' depends on this property, it'll also update.
  161. -- Since 'lower' and 'higher' depend on 'field', they too.
  162. -- (It happens in order, so there should be no conflicts)
  163. hmm.idk = 5
  164. -- This prints 6 since 'idk' is 5 and 'field' is idk+1
  165. print(hmm.field)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement