Skip to content

Beckett2000/object.lua

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

113 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

object.lua

This class has a collection of methods and functionality which could be used to build and debug code when working in Lua. There are also certain structures which can make code structures feel like other scripting languages.

Constructor: object() / object.new()
local value = object() / object.new()
print("Hello object!")

One of the goals with writing this class of methods is to provide more functions / methods to apply to the lua base classes. The :ext() is meant to help with dot or colon syntax chaining, while the inheritence is meant to help extend classes. Logging is meant to help with the debug process such that at any level of the code chain a table representation could potentially be expanded.


-- Example of a pseudo class using object and :ext(?

getTestClass = function()
  
   ------- ------ ----- ------ ------- >>
   -- Object class declarations ...
  
   local baseObject = object()
  
   ------ ---- ------ ---- ------ ---- 
  
   baseObject.list = function(self)
    return self:indexies()
   end
  
   ------ ---- ------ ---- ------ ----  
   baseObject:ext("list") 
   ------ ---- ------ ---- ------ ----
     
   baseObject.list.numbers = function(self)

    local numbers = object()
    for _,index in pairs({self:indexies()}) do
     if type(index) == "number" then
      numbers:push(index) end end
     return numbers
  
   end 
  
   baseObject.list.strings = function(self)
    
     local strings = object()
     for _,index in pairs({self:indexies()}) do
       if type(index) == "string" then
        strings:push(index) end end
      return strings
    
   end
  
   ------ ---- ------ ---- ------ ----
   local list = baseObject.list
   ------ ---- ------ ---- ------ ----
   list:extend("numbers")
   ------ ---- ------ ---- ------ ----
  
   -- (helper) - list even or odd indexies
   local function _evenOrOdd(self,even)
     
    local numbers = self.list:numbers()
    local numberList = object()
    for i = 1,#numbers do
     local number = numbers[i]
     if number % 2 == (even and 0 or 1) then
       numberList:push(number)
     end end    
    return numberList
    
  end
  
  ---- ---- ----
  
  list.numbers.even = function(self)
    return _evenOrOdd(self,true)  
   end
  
  list.numbers.odd = function(self)
    return _evenOrOdd(self,false)  
  end
  
  
  ------- ------ ----- ------ ------- >>
  
  return baseObject -- returns: test object 
  
end
-- Tests the pseudo class code ...

testObject = function()
  
  local sampleObject = {"a",44,"b",a=4,22,"c","d",1,2,3,4,5,"e" 
  ,3.14159,"ff"}
  
  local testClass = getTestClass()
  
  local test = testClass(sampleObject)
  
  test:extend("unshift")
  test.unshift.twice = function(self,...)
    for i = 1,2 do self:unshift(...) end
    return self 
  end
  
  test:push(343,357):unshift(547)
  test.unshift:twice("foo","bar")
  
  print(test,testClass:tostring("v"))
  
  print(test.listnumbers:odd())
  
  print(test.list.numbers.self) -- self pointer for proxy :ext() object

end

object.ext / object.extend - Object Extensions

-- object:ext("name") -> object.name 
-- object:name.value = ??
-- object.name.value:ext("otherName")
-- object.name.value.otherName = ?? ...

-- local someObject = object()

-- someObject inherits from object (base class) and ":exts" allow for dot / colon chaining back to the self object (someObject)


Custom Object Syntax

-- These prefix extensions search for the insert or remove prefix when referenced to create custom method call blocks. Using the declaration syntax, subclasses can append custom local methods to these extensions. The usage structure is below:
Declaration: object.|insert/remove|Extension IE: object.insertValue
Calling Syntax Examples: 

object:insertValue() 

object.insert:value() / object.insert:Value()
object.insert.value() / object.insert.Value() 

object:insert():Value() / object:insert():value()
object:insert().Value() / object:insert().value()

Usage example:

local tree = object{leaves = "green"}
tree:insertFirst("branches") --> tree{"branches",leaves = "green"}
tree.insert.first("bark") --> tree{"bark","branches",leaves = "green"}
tree.insert:Last("dew") --> tree{"bark","branches",leaves = "green","dew"}

Note: In the case of object.insert, the key of insert (on the object) is a custom object which passes its 'selfness' as the instance of the object which it is a part of. i.e in the case of object.insert.first, insert.first takes an object (self) as its first argument to the function call. This argument takes 'object' as the implicit self as opposed to insert.

-- syntax options -> i.e. object.insert.first
-- note: this is implemented in the object base class using object:extend("insert"). It should later also work on subclasses without unexpected overrides. - WIP

local myObject = object{"bar"}
local val = "foo"

-- These would all have the same effect ...

---- ----- ----- ----- 
object.insert:first(val)
object:insertFirst(val)
object.insert:First(val)
object.insertfirst(val)
---- ----- ----- ----- 
object.insert.first(val) -- with (dotObjectRef) flag
---- ----- ----- ----- 
object:unshift(val) -- alias
---- ----- ----- ----- 

-- output:
-- (object[2]):{01:"foo", 02:"bar"}


object.insert - extension / custom object

 object.insert.first(self,...) --> self
 -- alias: object.unshift
 object.insert.last(self,...) --> self
 -- alias: object.push
 object.insert.atIndex(self,...) --> self
object.insert.firstIndexiesFromTable
object.insert.lastIndexiesFromTable
object.insert.atIndexIndexiesFromTable
object.insert.keysFromTable

object.remove - extension / custom object

 object.remove.indexies(self,...) --> vararg - removals
 object.remove.keys(self,...) --> vararg - removals
 object.remove.first(self,number) --> vararg - removals
  -- alias: object.unshift
 object.remove.last(self,number) --> vararg - removals
  -- alias: object.pop
object.remove.atIndex
object.remove.beforeIndex
object.remove.afterIndex
object.remove.firstIndexOf
object.remove.lastIndexOf
object.remove.indexiesOf
object.remove.range
object.remove.entry
object.remove.entries

object.first / object.last - extensions / custom objects

 object.first(count) --> vararg - elements at first (count) indicies
 object.last(count) --> vararg - elements at last (count) indiciez

 object.first.indexOf(...) --> vararg - first indice of occurance of elements passed into method
 object.last.indexOf(...) --> vararg - last indice of occurance of elements passed into method

utility functions / methods:

object.countElements | object.length
object.contains

object.indexiesOf
object.keysOf

object.keys
object.hasKeys

object.range

object.inverseIndexies
object.type
object.isTypeOf

object.copy
object.meta
object.super | object.prototype | object.proto

Logging / Pretty Print: object has a (.toString) method which can be used to handle converting lua data to strings and decorating them in the serial display.


object.toString - extension / custom object

 object.toString(value,options) --> string (see __tostring below)

 object.toString:config { --> nill - (sets behavior for toStringHandler) -> object:meta().__tostring

  offsets = true,
  length = true,
  depth = 1

  style = "block"
  spacer = "  "
  
 }
 object.concat(table,sep) --> string
local function getToStringSettings()
    
  ---------- ---------- ---------- ------
  --> __tostring settings: [name]:type
    
  local settings = { ------ ------ ----
        
    -- show offsets --> table: 0x311d85a00
    offsets = "boolean", -- true|false
    ------ ----- -------- ---- -----    
    -- show lengths --> table[3]: {a,b,c}  
    lengths = "boolean", -- true|false
    ------ ----- -------- ---- -----   
     -- show sub tables --> {a,b,c,{d,e}}
    depth = "number", -- (0 -> math.huge)
    -- <----- <----- <----- <----- <---
    -----> -----> -----> -----> ----->
    -- [pretty print] --> style name    
    style = "string", -- 'vertical'|'block' 
    ------ ----- -------- ---- -----   
    -- [pretty print] --> spacer string        
    spacer = "string" -- "\t"," ",etc.
        
  } ------ ------ ------
  ---------- ---------- ---------- ------
    
  return settings ---> returns: {table}
    
end
 local tree = object{"leaves","bark",
  kind = "oak", ["1"] = "one", alpha = {"a","b","c"}}
    
 print(tree:toString{
 ---- ---- ---- ----
  style = "vertical",
  depth = 2,
  spacer = "..",
  ---- ---- ---- ----
  offsets = true,
  lengths = true
  ---- ---- ---- ----
 })
output:

(object[2]: 0x306f20140):{
....01:"leaves", 
....02:"bark", 
....["1"]:"one", 
....kind:"oak", 
....alpha:(table[3]: 0x306f20bc0):{
......01:"a", 
......02:"b", 
......03:"c"
....}
}
print(tree) -- uses defaults
(object[2]: 0x306f20140):{01:"leaves", 02:"bark", alpha:(table[3]: 0x306f20bc0), kind:"oak", ["1"]:"one"}
-- configure the default behavior of __tostring for object instance (tree)
-- note: this only changes defined properties and does not overwrite the entire config table
tree.toString:config {
 offsets = false,
 depth = 2
}

print(tree) -- uses new configs
(object[2]):{01:"leaves", 02:"bark", ["1"]:"one", kind:"oak", alpha:(table[3]):{01:"a", 02:"b", 03:"c"}}

Chaining: Calls which return an object can be chained

local colors = object()
colors:unshift("red","green"):push("blue") 
print(colors) --> colors{"red","green","blue"}
(object[3]: 0x306c9f440):{01:"red", 02:"green", 03:"blue"}

Note 4/10/25 - The scope stack methods are being updated. The code below isn't currently working with module imports in all cases.


Object Methods: Scope Stack


object:inScopeOf() -- Iterator overload - Iterate once and set scope to object implicitly -> local scope becomes object 

for scope in object:inScopeOf do
end

pushScope() -- Add to array and set dynamic pointer
popScope() -- Remove from array and set dynamic pointer
(WIP) setScope(scope,bind/reset) - Update Dynamic Pointer

for all) -> returns: scope


Usage Example: (object scope)

    local plant = object{"seed"}
    object.unshift(plant,"flower") -- plant{"flower","seed"}
    print("The plant:",plant)
    plant:shift()

    for scope in plant:inScopeOf() do
     plant:push("water")
     push("nutrients")
     print("The plant:",self) -- plant{"seed","water","nutrients"}
    end

    local tree = plant{"branch","leaves"}
    local bush = plant{leaves = "green"}
    
    bush:pushScope()
    print("The initial bush (out of scope)",bush)
    
    for scope in plant:inScopeOf() do
        
     pushScope(tree)

      print(self) -- tree{"branch","leaves"}
      print(self[1]) -- "branch"

      insert.first(self,"bark")
      print("The tree:",self) --> tree{"bark","branch","leaves"}

      pushScope(bush)

       print("The bush:",self) --> bush{["leaves"] = "green}

       print(leaves) -- "green"
       self.leaves = "purple"
       print(leaves) -- "purple"

      popScope()

      print("The tree:",self) -- tree{"branch","leaves","bark"}

      -- Note: These are all reference pointers to the same var.
      print(leaves,tree.leaves,self.leaves) -- "purple","purple","purple"

     popScope()
        
     print("The plant:",self) -- plant{"seed","water","nutrients"}
     print(plant == self) --> true

    end
    
    print("The bush (out of scope)",self) -- bush{["leaves"]="purple"}
    popScope()
    
    print("Self - should be nil!",self)

Scope Object Methods - WIP

  scope:next() / scope:previous() - scope stack movement

  scope:release() - clear stack / return to main scope
  scope:bind(scope) - (alias) - clear scope stack and set to new scope - scope:bind(nil) - same as scope:release()

About

Object Oriented Lua Programming

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages