Advertisement
Guest User

qOOP Source

a guest
Mar 30th, 2012
273
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.12 KB | None | 0 0
  1. ---------------------------------------------------------------------------------------------
  2. --[[
  3.     qOOP - Quick Object Oriented Programming Library
  4.     Copyright (C) 2011.
  5.     Written by Roland Yonaba - E-mail: roland[dot]yonaba[at]gmail[dot]com
  6.     Project Hosted At: http://qooplua.codeplex.com/
  7.     qOOP is a simple and quick-written Library which offers some OOP facilities
  8.             and syntax for Lua Programming Language.
  9.     Version: 1.3.2
  10.     Current Features :
  11.         - Class creation with default methods granted
  12.         - Static class and Final classes emulation
  13.         - Single and Multiple Inheritance features
  14.         - Default constructors provided with class() call as functions.
  15.         - Access to super metamethods.
  16.  
  17. --]]
  18. ----------------------------------------------------------------------------------------------
  19.  
  20. -- Localizing some globals funcs
  21. local setmetatable, getmetatable, rawset, rawget, pcall, error = setmetatable, getmetatable, rawset, rawget, pcall, error
  22. local type ,ipairs, pairs, insert, unpack = type, ipairs, pairs, table.insert, unpack
  23.  
  24. -- Hold the list of reserved keywords
  25. -- They are all part of any class, and should neither be propagated from a superclass to its subclasses
  26. -- nor from a class to its instances
  27. local reserved_keywords = {
  28.                             '__super',
  29.                             ',__sub',
  30.                             '__index',
  31.                             '__static',
  32.                             '__final',
  33.                             '__class',
  34.                           }
  35.  
  36. -- Searches a method in a list of tables. This will be the core
  37. -- of multiple inheritance feature implementation
  38. local function call_method(method,...)
  39.     for k in ipairs(arg) do
  40.         local m = arg[k][method]
  41.         if m and type(m)=='function' then return m end
  42.     end
  43.     return nil
  44. end
  45.  
  46. -- Searches an item in a table.
  47. -- Returns true on success, plus the key, otherwise false.
  48. local function table_find(item,table)
  49.     for k in pairs(table) do
  50.         if table[k] == item then return true,k end
  51.     end
  52.     return false
  53. end
  54.  
  55. -- Returns a reference-independant copy of a table
  56. -- Functions and reserved_keywords entries are not copied.
  57. local function table_copy(to,from)
  58.     for k,v in pairs(from) do
  59.         if not table_find(k,reserved_keywords) then
  60.             if type(v) ~='function' then
  61.                 if type(v) == 'table' then
  62.                     if isObject(v) then
  63.                         local properties = {}
  64.                         for property,value in pairs(v) do properties[property] = value end
  65.                         local super = getmetatable(v)
  66.                         to[k] = super(properties)
  67.                     else
  68.                         to[k]={}
  69.                         table_copy(to[k],v)
  70.                     end
  71.                 else
  72.                     to[k] = v
  73.                 end
  74.             end
  75.         end
  76.     end
  77. end
  78.  
  79. -- Generates a new instance of a class
  80. local function instance(class)
  81.     local o = {}
  82.     table_copy(o,class)
  83.     return setmetatable(o,class)
  84. end
  85.  
  86. --- Checks if the given argument is a qOOP class
  87. -- @param class [table] The reference holding the qOOP class to be tested
  88. -- @return [boolean] True if 'class' is a qOOP class, otherwise False
  89. -- @usage <pre class='example'>
  90. --        <br>
  91. --        myClass = class() <br>
  92. --        print(isClass(myClass)) --> True <br>
  93. --        </pre>
  94. function isClass(class)
  95.     local c = (class and class.__class)
  96.     return (c and c==class or false)
  97. end
  98.  
  99. --- Checks if the given argument is an instance from any qOOP class
  100. -- @param o [table] The reference holding the instance to be tested
  101. -- @return [boolean] True if 'o' is an instance from any qOOP class, otherwise False
  102. -- @usage <pre class='example'>
  103. --        <br>
  104. --        myClass = class() <br>
  105. --        myObject = new(myClass) <br>
  106. --        print(isObject(myObject)) --> True <br>
  107. --        </pre>
  108. function isObject(o)
  109.     local mt = getmetatable(o)
  110.     if type(o)~='table' or not mt then return false end
  111.         local check = false
  112.         for i,reserved in ipairs(reserved_keywords) do
  113.             check = table_find(reserved,reserved_keywords)
  114.             if not check then return false end
  115.         end
  116.     if rawget(o,'getClass') or rawget(o,'getSuperClass') then return false end
  117.     return check
  118. end
  119.  
  120. --- Checks if the given argument is an instance from a specific qOOP class
  121. -- @param o [table] The reference holding the instance to be tested
  122. -- @param class [table] The reference holding the qOOP class from which the instance should belong to
  123. -- @return [boolean] True if 'o' is an instance from qOOP class 'class', otherwise False
  124. -- @usage <pre class='example'>
  125. --        <br>
  126. --        myClass = class() <br>
  127. --        myObject = new(myClass) <br>
  128. --        print(isObjectOf(myObject, myClass)) --> True <br>
  129. --        </pre>
  130. function isObjectOf(o,class)
  131.     if not isClass(class) then error('class is not a qOOP class!',2) end
  132.     if not o.getClass then error('object is not a qOOP object!',2) end
  133.     local c = o:getClass()
  134.     return (c == class)
  135. end
  136.  
  137. -- Checks class.method existence
  138. local function is_MemberOf(member,class)
  139.     if not isClass(class) then error('class is not a qOOP class!',2) end
  140.     return (class[member] and true or false)
  141. end
  142.  
  143. -- Inits 'class' members/extra-members
  144. local function setMembers(class,arg)
  145.     if not isClass(class) then error('class is not a qOOP class!',2) end
  146.     table_copy(class,arg)
  147.     return class
  148. end
  149.  
  150. --- An interator function which processes all over the subclasses of a qOOP class
  151. -- @param class [table] The reference holding the qOOP class
  152. -- @return  [table] a qOOP class which is a child of 'class' at each call.
  153. -- @usage <pre class='example'>
  154. --        <br>
  155. --        myClass = class() <br>
  156. --        for child_class in children(myClass) do <br>
  157. --           ... <br>
  158. --        end <br>
  159. --        </pre>
  160. function children(class)
  161.     if not isClass(class) then error('class is not a qOOP class!',2) end
  162.     local child = 0
  163.     local num_child = #class.__sub
  164.     return function()
  165.             child = child + 1
  166.                 if child <= num_child then return class.__sub[child] end
  167.             end
  168. end
  169.  
  170. --- An interator function which processes all over the superclasses of a qOOP class
  171. -- @param class [table] The reference holding the qOOP class
  172. -- @return  [table] a qOOP class which is an ancestor of 'class' at each call.
  173. -- @usage <pre class='example'>
  174. --        <br>
  175. --        myClass = class() <br>
  176. --        for ancestor_class in ancestors(myClass) do <br>
  177. --           ... <br>
  178. --        end <br>
  179. --        </pre>
  180. function ancestors(class)
  181.     if not isClass(class) then error('class is not a qOOP class!',2) end
  182.     local super = 0
  183.     local num_super = #class.__super
  184.         return function()
  185.                 super = super + 1
  186.                     if super <= num_super then return class.__super[super] end
  187.                 end
  188. end
  189.  
  190.  
  191. -- Basic class creation
  192. local function Class(...)
  193.     local new_class = {}
  194.     local super = {}
  195.     if arg and #arg > 0 then
  196.         for i,parent in ipairs(arg) do
  197.             if parent.__final then error('Arg #'..i..' is a final qOOP class!',2) end
  198.             insert(super,parent)
  199.             insert(parent.__sub,new_class)
  200.         end
  201.     end
  202.     new_class.__super = super
  203.     new_class.__sub = {}
  204.     setmetatable(new_class,{__index = function (t,m)
  205.                                         return call_method(m,unpack(new_class.__super))
  206.                                     end,
  207.                             __call = function(self,t)
  208.                                         if self.__static then error('Cannot instantiate from static qOOP class!',2) end
  209.                                         local object = instance(self)
  210.                                         if t then table_copy(object,t) end
  211.                                         return object
  212.                                     end
  213.                             })
  214.     new_class.__index = new_class
  215.     new_class.__static = false
  216.     new_class.__final = false
  217.     new_class.__class = new_class
  218.  
  219.     --- Default class constructor. Creates and returns an instance of [class] qOOP class.
  220.     -- @name [class]:new
  221.     -- @param properties [table] An index-named table holding a set of properties for the new instance.
  222.     -- @return [table] An instance of [class] qOOP class
  223.     -- @usage <pre class='example'>
  224.     --        <br>
  225.     --        myClass = class() <br>
  226.     --        myObject = myClass:new() <br>
  227.     --        </pre>
  228.     function new_class:new(properties)
  229.         return new_class(properties)
  230.     end
  231.  
  232.     --- Inits [class] qOOP class members.
  233.     -- @name [class]:has
  234.     -- @param members [table] An index-named table containing a collection of parameters for a qOOP class with initial values.
  235.     -- @return [table] The qOOP class itself
  236.     -- @usage <pre class='example'>
  237.     --        <br>
  238.     --        myClass = class() <br>
  239.     --        myClass:has {classMemberOne = 1, classMemberTwo = 'Hello', ...} <br>
  240.     --        </pre>
  241.     function new_class:has(members)
  242.         if not isClass(self) then error('setMembers() must be called from a qOOP class, not an instance!',2) end
  243.         return setMembers(self,members)
  244.     end
  245.  
  246.     --- Checks if the given argument is a member of [class] qOOP class.
  247.     -- @name [class]:hasMember
  248.     -- @param member [string] A string reference.
  249.     -- @return [boolean] True if [class].member exists, otherwise returns False.
  250.     -- @usage <pre class='example'>
  251.     --        <br>
  252.     --        myClass = class() <br>
  253.     --        print(myClass:hasMember('classMember')) --> False <br>
  254.     --        </pre>
  255.     function new_class:hasMember(member)
  256.         return is_MemberOf(member,self)
  257.     end
  258.  
  259.     --- Checks if qOOP class [class] derives from the given argument 'class'.
  260.     -- @name [class]:inherits
  261.     -- @param class [table] A reference holding a qOOP class.
  262.     -- @return [boolean] True if [class] derives from argument 'class', otherwise returns False.
  263.     -- @usage <pre class='example'>
  264.     --        <br>
  265.     --        myClass = class() <br>
  266.     --        myDerivedClass = class(myClass) <br>
  267.     --        print(myDerivedClass:inherits(myClass)) --> True <br>
  268.     --        </pre>
  269.     function new_class:inherits(class)
  270.         if not isClass(self) then error('inherits() must be called from a qOOP class!',2) end
  271.         return (table_find(class,self.__super))
  272.     end
  273.  
  274.     --- Checks if the qOOP class given as argument derives from qOOP class [class].
  275.     -- @name [class]:ancestor
  276.     -- @param class [table] A reference holding a qOOP class.
  277.     -- @return [boolean] True if 'class' argument derives from [class], otherwise returns False.
  278.     -- @usage <pre class='example'>
  279.     --        <br>
  280.     --        myClass = class() <br>
  281.     --        myDerivedClass = class(myClass) <br>
  282.     --        print(myClass:ancestor(myDerivedClass)) --> True <br>
  283.     --        </pre>
  284.     function new_class:ancestor(class)
  285.         if not isClass(self) then error('ancestor() must be called from a qOOP class!',2) end
  286.         return (table_find(class,self.__sub))
  287.     end
  288.  
  289.     --- Returns the class from which a qOOP instance was created.
  290.     -- @name [instance]:getClass
  291.     -- @return [table] The qOOP class from which the calling object was instantiated or the qOOP class itself.
  292.     -- @usage <pre class='example'>
  293.     --        <br>
  294.     --        myClass = class() <br>
  295.     --        myObject = new(myClass) <br>
  296.     --        print(myObject:getClass() == myClass) --> True <br>
  297.     --        </pre>
  298.     function new_class:getClass()
  299.         return new_class
  300.     end
  301.  
  302.     --- Returns a list of qOOP classes from which the qOOP class [class] derives.
  303.     -- @name [class]:getAncestors
  304.     -- @return [table] A table containing [class] ancestors.
  305.     -- @usage <pre class='example'>
  306.     --        <br>
  307.     --        myClass = class() <br>
  308.     --        myDerivedClass = class(myClass) <br>
  309.     --        local listOfAncestors = myClass:getAncestors() <br>
  310.     --        table.foreach(listOfAncestors, print) <br>
  311.     --        </pre>
  312.     function new_class:getAncestors()
  313.         if not isClass(self) then error('getAncestors() must be called from a qOOP class!',2) end
  314.         return (new_class.__super)
  315.     end
  316.  
  317.     --- Returns a list of qOOP classes deriving from [class] qOOP class.
  318.     -- @name [class]:getChildren
  319.     -- @return [table] A table containing [class] children.
  320.     -- @usage <pre class='example'>
  321.     --        <br>
  322.     --        myClass = class() <br>
  323.     --        myDerivedClass = class(myClass) <br>
  324.     --        local listOfChildren = myClass:getChildren() <br>
  325.     --        table.foreach(listOfChildren, print) <br>
  326.     --        </pre>
  327.     function new_class:getChildren()
  328.         if not isClass(self) then error('getChildren() must be called from a qOOP class!',2) end
  329.         return (new_class.__sub)
  330.     end
  331.  
  332.     --- Calls a metamethod defined in 'new_class' qOOP class ancestors.
  333.     -- @name [class]:super
  334.     -- @param method [string] A string reference
  335.     -- @param ... [tables] A collection of arguments for [class]:method() metamethod.
  336.     -- @return The result of [class]:method(...)
  337.     -- @usage <pre class='example'>
  338.     --        <br>
  339.     --        myClass = class() <br>
  340.     --        function myClass:operate(a,b) return a+b end <br>
  341.     --        myDerivedClass = class(myClass) <br>
  342.     --        function myDerivedClass:operate(a,b) return a-b end <br>
  343.     --        print(myDerivedClass:operate(10,5)) --> 5 <br>
  344.     --        print(myDerivedClass:super('operate',10,5)) --> 15 <br>
  345.     --        </pre>
  346.     function new_class:super(method,...)
  347.         local parents = self.__super
  348.         if #parents > 0 then
  349.             local m = call_method(method,unpack(parents))
  350.             if m then
  351.                 m(self,unpack(arg))
  352.             else
  353.                 error('Cannot find metamethod '..method..'() in class parents!',2)
  354.             end
  355.         else
  356.             error('qOOP Class has no parent!',2)
  357.         end
  358.     end
  359.  
  360.     return new_class
  361. end
  362.  
  363. -- Final Classes
  364. local function finalClass(...)
  365.     local try, catch = pcall(Class,...)
  366.     if not try then
  367.         error(catch,2)
  368.     else
  369.         catch.__final = true
  370.         return catch
  371.     end
  372. end
  373.  
  374. -- Static Classes
  375. local function staticClass(...)
  376.     local try, catch = pcall(Class,...)
  377.     if not try then
  378.         error(catch,2)
  379.     else
  380.         catch.__static = true
  381.         return catch
  382.     end
  383. end
  384.  
  385. --- Creates and returns a qOOP class. Single and multiple inheritance are supported.
  386. -- @param ... [tables] Optional list of qOOP classes from which the new qOOP class will derive. Can be nil.
  387. -- @return  [table] a qOOP class
  388. -- @usage <pre class='example'>
  389. --        <br>
  390. --        myClass = class() <br>
  391. --        </pre>
  392. -- @see class.final
  393. -- @see class.static
  394. function class(...) return end
  395. class = setmetatable( {}, {__call = function(self,...) return Class(...) end})
  396.  
  397. --- Creates and returns a final qOOP class.Single and multiple inheritance are supported.
  398. -- <br/>A final class is a class from which no class can inherit.
  399. -- @param ... [tables] Optional list of qOOP classes from which the new qOOP class will derive. Can be nil.
  400. -- @return  [table] a final qOOP class.
  401. -- @usage <pre class='example'>
  402. --        <br>
  403. --        myClass = class.final() <br>
  404. --        </pre>
  405. -- @see class
  406. -- @see class.static
  407. function class.final(...) return end
  408. class.final = finalClass
  409.  
  410. --- Creates and returns a static qOOP class.Single and multiple inheritance are supported.
  411. -- <br/>A static class is a class from which instantiation is not possible.
  412. -- @param ... [tables] Optional list of qOOP classes from which the new qOOP class will derive. Can be nil.
  413. -- @return  [table] a static qOOP class.
  414. -- @usage <pre class='example'>
  415. --        <br>
  416. --        myClass = class.static() <br>
  417. --        </pre>
  418. -- @see class
  419. -- @see class.final
  420. function class.static(...) return end
  421. class.static = staticClass
  422.  
  423. --- Creates and returns an instance from a qOOP class.
  424. -- <br/>The new instance will have default class parameters.
  425. -- @param class [table] The qOOP class from which the new object instantiate.
  426. -- @param arg [table] Optional set of properties for the new instance.
  427. -- @return  [table] An instance of 'class' qOOP class
  428. -- @usage <pre class='example'>
  429. --        <br>
  430. --        myClass = class() <br>
  431. --        myObject = new(myClass) <br>
  432. --        </pre>
  433. -- @see [class]:new
  434. function new(class,arg)
  435.     if not isClass(class) then
  436.         error('class is not a qOOP class!',2)
  437.     end
  438.     return class(arg)
  439. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement