SHARE
TWEET

Lua Setters and Getters

Oeed Jun 1st, 2015 293 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. BaseClass = {
  2.         -- if you're doing static methods, this would be one
  3.         new = function(self)
  4.                 -- Obviously all this stuff won't have to be written each time, but instead embeded in the language
  5.                 local newRaw = {} -- the object with the actual values in it
  6.  
  7.                 setmetatable(newRaw, { __index = self })
  8.  
  9.                 -- these are to prevent infinite loops in getters and setters (so, for example, doing self.speed = 10 in setSpeed doesn't cause setSpeed to be called a million times)
  10.                 local lockedSetters = {}
  11.                 local lockedGetters = {}
  12.  
  13.                 local newProxy = {} -- the proxy. 'self' always needs to be this, NOT newRaw
  14.                 setmetatable(newProxy, {
  15.                         __index = function(t, k)
  16.                                 -- just an idea, see the set and get functions
  17.                                 -- this basically allows a global filter or notification on all get
  18.                                 if not lockedGetters[k] and newRaw.get and type(newRaw.get) == 'function' then
  19.                                         lockedGetters[k] = true
  20.                                         local use, value = newRaw.get(newProxy, k)
  21.                                         lockedGetters[k] = nil
  22.                                         if use then
  23.                                                 return value
  24.                                         end    
  25.                                 end
  26.  
  27.                                 -- basically, if the get'Key' function is set, return it's value
  28.                                 -- names are capitalised, so .name becomes getName; This might cause a few issues regarding collisions, but really, how many (good) coders are using .name and .Name
  29.                                 -- non-function properties can't use it, because, well, it's just futile really
  30.                                 local getFunc = 'get' .. k:sub(1, 1):upper() .. k:sub(2, -1)
  31.                                 if not lockedGetters[k] and type(newRaw[k]) ~= 'function' and newRaw[getFunc] and type(newRaw[getFunc]) == 'function' then
  32.                                         lockedGetters[k] = true
  33.                                         local value = newRaw[getFunc](newProxy)
  34.                                         lockedGetters[k] = nil
  35.                                         return value
  36.                                 else
  37.                                         return newRaw[k] -- return the raw value if not using the getter
  38.                                 end
  39.                         end,
  40.  
  41.                         __newindex = function (t,k,v)
  42.                                 -- just an idea, see the set and get functions
  43.                                 -- this basically allows a global filter or notification on all sets
  44.                                 if not lockedSetters[k] and type(newRaw.set) and type(newRaw.set) == 'function' then
  45.                                         lockedSetters[k] = true
  46.                                         local use, value = newRaw.set(newProxy, k, v)
  47.                                         lockedSetters[k] = nil
  48.                                         if use then
  49.                                                 newRaw[k] = value
  50.                                                 return
  51.                                         end    
  52.                                 end
  53.  
  54.                                 -- if the filter wasn't applied, if the set'Key' function is set, call it
  55.                                 local setFunc = 'set' .. k:sub(1, 1):upper() .. k:sub(2, -1)
  56.                                 if not lockedSetters[k] and type(newRaw[k]) ~= 'function' and newRaw[setFunc] and type(newRaw[setFunc]) == 'function' then
  57.                                         lockedSetters[k] = true
  58.                                         newRaw[setFunc](newProxy, v) -- see the comment for newRaw[getFunc](newRaw) regarding the use of newRaw
  59.                                         lockedSetters[k] = nil
  60.  
  61.                                         -- alternate way of doing it, return the value instead of setting it
  62.                                         -- newRaw[k] = newRaw[setFunc](newRaw, v) -- see the comment for newRaw[getFunc](newRaw) regarding the use of newRaw
  63.                                 else
  64.                                         newRaw[k] = v -- use the passed value if not using the setter
  65.                                 end
  66.                         end
  67.                 })
  68.  
  69.                 -- use the setters with all the starting values
  70.                 for k, v in pairs(self) do
  71.                         if type(self[k]) ~= 'function' then
  72.                                 newProxy[k] = v
  73.                         end
  74.                 end
  75.  
  76.                 return newProxy
  77.         end
  78. }
  79.  
  80.  
  81.  
  82.  
  83. Person = {
  84.         name = 'Default Name', -- doesn't actually have to be set, but this acts as a default
  85.  
  86.         -- again, not sure about the naming convention here. the __ looked ugly really, although it did kinda make sense.
  87.         setName = function(self, name)
  88.                 -- for example, let's capitalise the name
  89.                 -- I'm not sure if returning of setting the name is better than this though (see the comment in __newindex)
  90.                 self.name = name:sub(1, 1):upper() .. name:sub(2, -1)
  91.         end,
  92.  
  93.         getName = function(self)
  94.                 -- and then tack an underscore on the front for the sake of it
  95.                 if self.name and #self.name > 0 then
  96.                         return '_' .. self.name
  97.                 end
  98.         end,
  99.  
  100.         set = function(self, key, value)
  101.                 -- we don't want to set the value, return false.
  102.                 -- these functions doesn't actually need to be here in this example, but may be useful for things such as UI updates when any of the values (text, colour, etc.) change
  103.                 return false
  104.         end,
  105.  
  106.         get = function(self, key)
  107.                 -- we don't want to alter the returned value, return false
  108.                 return false
  109.         end,
  110. }
  111. -- you'd obviously automate this bit
  112. setmetatable(Person, { __index = BaseClass })
  113.  
  114.  
  115.  
  116.  
  117. -- example where both aren't required
  118. Car = {
  119.         speed = 0, -- can poetentially be false
  120.         speedLimit = 5,
  121.  
  122.         -- again, not sure about the naming convention here. the __ looked ugly really, although it did kinda make sense.
  123.         setSpeed = function(self, speed)
  124.                 -- don't go speeding there mate!
  125.                 self.speed = math.min(speed, self.speedLimit)
  126.         end,
  127.  
  128.         getSpeedLimit = function(self)
  129.                 -- for example, moving through different roads and detecting the limit from GPS
  130.                 local i = math.ceil(math.random() * 3)
  131.                 local limits = { 30, 50, 100 }
  132.  
  133.                 return limits[i]
  134.         end
  135. }
  136. setmetatable(Car, { __index = BaseClass })
  137.  
  138.  
  139.  
  140.  
  141. -- example where the globals are used
  142. Button = {
  143.         x = 2,
  144.         y = 10,
  145.         text = 'Click Me',
  146.         backgroundColour = colours.blue,
  147.         width = 1,
  148.  
  149.         -- US spelling catchers. YAY!
  150.         setBackgroundColor = function(self, color)
  151.                 self.backgroundColour = color
  152.         end,
  153.  
  154.         getBackgroundColor = function(self)
  155.                 return self.backgroundColour
  156.         end,
  157.  
  158.         setText = function(self, text)
  159.                 self.width = #text + 2
  160.                 self.text = text
  161.         end,
  162.  
  163.         set = function(self, key, value)
  164.                 self:draw()
  165.                 -- again, we don't actually want to edit the value, simply know when any of them were changed
  166.                 return false
  167.         end,
  168.  
  169.         draw = function(self)
  170.                 -- haven't done this for simplicity, but given the right setup with a draw queue (because this would get called a lot more than it would actually need to be redraw) it would work 100%
  171.         end
  172. }
  173. setmetatable(Button, { __index = BaseClass })
  174.  
  175.  
  176.  
  177.  
  178. -- Ideally you couldn't do Person.Name (instance function), only static functions on Person. It's not essential though
  179. local oeed = Person:new()
  180. oeed.name = 'oeed'
  181. print(oeed.name) -- _Oeed
  182.  
  183. local sportsCar = Car:new()
  184. sportsCar.speed = 120
  185. print(sportsCar.speed) -- 30, 50 or 100
  186.  
  187. sportsCar.speed = 40
  188. print(sportsCar.speed) -- 30 or 40
  189.  
  190.  
  191. local button = Button:new()
  192. -- the button would be draw without any other work
  193. button.text = 'I am a rather wide button!'
  194. button.y = 20
  195. -- the button would now appear wide, with that text and at y = 20
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top