Giter Club home page Giter Club logo

mayronobjects's People

Contributors

mayron avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

0mrdarn0

mayronobjects's Issues

Feature Request: List:Copy or copy constructor

I'm curious if there'd be any value in the List class having some copy utility? Sometimes I'd rather retain a copy of data (when it won't impact performance) than retain a reference to a list that may have been passed in as a function argument. I have some quick and dirty boilerplate that I use (admittedly only in 2 places ha), but thought the library might benefit from built-in support.

Feature Request: Abstract classes and protected visibility

First off, as an embedded C/C++ dev who has only just been getting into Lua for fun, this library has been a blessing! I've mostly been using it for my own library addon to provide enhancements and reusable code for other addons like WeakAuras and such. However, I was drafting a design to take advantage of Interfaces, but also realized that there are a few things I couldn't do with it. I wanted to create an abstract base class that implemented an interface to provide things like common base constructor. Below is an example of what I have now (sorry for the wall of code!)

Current Code
-- Assumes package is already defined.
local IFoo = package:CreateInterface("IFoo", {
  GetText   = {type = "function", returns = "string"},
  GetNumber = {type = "function", returns = "number"}
  Print     = {type = "function" }
}

--[[
Intended to be an interface "default" function. Maybe I did something wrong,
but I was unable to do something like:
function IFoo:Print(data) print(self:GetText() .. self:GetNumber()) end
--]]
function IFoo.Print(obj)
   print(obj:GetText() .. obj:GetNumber())
end

-- "abstract" base class and constructor definition
local CAbstractFoo = package:CreateClass("CAbstractFoo", nil, IFoo)
package:DefineParams("number")
function CAbstractFoo:__Construct(data, number)
  data.number = number
  self:CheckNotAbstract()
end

-- A function used to somewhat enforce the abstract nature of the class.
package:DefineVirtual()
function CAbstractFoo:CheckNotAbstract()
  error("This class is abstract and should not be instantiated!")
end

-- Base implementation to return common state
package:DefineReturns("number")
function CAbstractFoo:GetNumber(data)
  return data.number
end

-- "abstract" method that I would have left out in the base class were it
-- possible
package:DefineVirtual()
package:DefineReturns("string")
function CAbstractFoo:GetText()
  error("This function is abstract, and should not be called!")
end

-- Print implementation using the interface default method.
function CAbstractFoo:Print()
  IFoo.Print(self)
end

-- Concrete class and constructor definition
local CConcreteFoo = package:CreateClass("CConcreteFoo", CAbstractFoo)
package:DefineParams("string", "number")
function CConcreteFoo:__Construct(data, text, number)
  self:Super(number)
  data.number = number
end

-- Implementation to shadow base class to avoid "abstract" error.
function CConcreteFoo:CheckNotAbstract()
  -- Do nothing dummy function
end

-- Implementation to shadow base class to avoid "abstract" error.
package:DefineReturns("string")
function CConcreteFoo:GetText(data)
  return data.text
end

There ends up being a lot of boilerplate code for things that could be implemented as interface default methods. If the library supported it, maybe the code in my example would look something like this?

Code with Suggested Features
-- Assumes package is already defined.
local IFoo = package:CreateInterface("IFoo", {
  GetText   = {type = "function", returns = "string"},
  GetNumber = {type = "function", returns = "number"}
  Print     = {type = "function" }
}

--[[
Something like this could be used to define an interface method that doesn't
know about any object state other than that defined by the interface itself.
--]]
package:DefineDefault()
function IFoo:Print()
   print(self:GetText() .. self:GetNumber())

   --[[
   Behavior like these should result in an error however. When the scope of
   self is the interface, giving access to methods from child classes
   amounts to reflection. Also, allowing direct modification of an object's
   properties that aren't exposed by the interface's definition would be
   asking for coupling issues galore in client code down the road.
   I've seen some gross things done in C++ with stateful pure virtual
   classes and it makes me wince ๐Ÿ˜….

   if self:GetName then print(self:GetName()) end
   self.sideEffect = true

   --]]
end

--[[
Something like this could be used to mark a class as abstract, and if that
class implements any interfaces, the framework would not treat missing
interface functions as errors. Called right before the creation of the class,
it would accept a table of abstract function definitions that must also be
implemented by non-abstract children in addition to any unimplemented
interfaces.
--]]
package:DefineAbstract({
  GetName = {returns = "string"}
  DoubleNumberAndAdd = {params = "number", returns ="number" }
}

--[[
Something like this could be used to ensure that only classes in the same
package can declare the protected class as a parent. For example, calling
CreateClass("CConcreteFoo2", CAbstractFoo) from a different package would
result in an error from the framework.
--]]
package:DefinePackageVisibility()

--[[
Create the abstract class, and no abstract instantiation check is required
by client code. Attempting to call CAbstractFoo(0) would result in an error
from the framework.
--]]
local CAbstractFoo = package:CreateClass("CAbstractFoo", nil, IFoo)
package:DefineParams("number")
function CAbstractFoo:__Construct(data, number)
  data.number = number
end

--[[
Something like this could be allowed to provide a default implementation for
DoubleNumberAndAdd, but still require that children implement it. Children may
call it explicitly like any other parent method however.
--]]
function CAbstractFoo:DoubleNumberAndAdd(number)
  return (self:GetNumber() * 2) + number
end

--[[
Something like this would be used to override the default implementation of
the interface, giving more visibility into the object's state. I've used
self.Interfaces as an example of how it might be accessed (similar to calling)
parent methods.
--]]
function CAbstractFoo:Print(data)
  self.Interfaces:Print()
  print(self:GetName())
end

-- Base implementation to return common state
package:DefineReturns("number")
function CAbstractFoo:GetNumber(data)
  return data.number
end

--[[
Something like this could be the mechanism for defining protected functions.
Just like functions defined on the Private table, they would not be visible
outside the scope of the current class, with the exception that child classes
would be able to call them using data:Call(). These methods could also be
allowed to have package:DefinesVirtual() to allow a child to override the
method.
--]]
package:DefineReturns("number")
function CAbstractFoo.Protected:GetHalfNumber()
  return self:GetNumber() / 2
end

-- Concrete class definition
local CConcreteFoo = package:CreateClass("CConcreteFoo", CAbstractFoo)
local fooInstance = CFooConcrete("test", 0)

-- Concrete class constructor
package:DefineParams("string", "number")
function CConcreteFoo:__Construct(data, text, number)
  self:Super(number)
  data.text = text
end

-- GetText required implementation from interface
function CConcreteFoo:GetText(data)
  return data.text
end

-- GetName required implementation from abstract class
function CConcreteFoo:GetName(data)
  return "childUsingProtected:" .. data:Call("GetHalfNumber")
end

I'm still getting the hang of Lua in general, so hopefully things make sense!

Trying to get a plugin started.

Hey man,

Great job on the library. I am liking what I am seeing, only If I could get the project started that would be great.

I am trying to build an addon for my guild. I had a small addon back in the day, when retail was a big thing (around WOTLK). But since I have fallen out of favor with Lua. I mostly dabble in TypeScript and C# now.

I am trying to get an addon setup. But I am getting errors.

I can't seem to import LibMayronObjects and LibMayronDB.

I changed the Interface Version in both .toc files (as you said in your guides) to 11304 (thats what I get by running /run print((select(4, GetBuildInfo()))); in WoW Classic).

But I am getting the following error from WoW Classic:

Message: Interface\AddOns\HarmonyAntiDC\Library\LibMayronDB\LibMayronDB.toc(1): error: not well-formed (invalid token)
Time: Thu Apr  2 18:14:35 2020
Count: 3

and

Message: (null)
Time: Thu Apr  2 18:14:35 2020
Count: 3

I tried to use one of your "test" classes in my plugin .lua. But as I said I get the error up top.

Any way you can help me get everything setup so I can try out the framework?

My plugintest.toc:


##Interface: 11304
##Title: plugintest
##Author: steviss
##Notes: Test addon.
##Version: 1.0

plugintest.lua

#Myron Objects
Library\LibMayronObjects\LibMayronObjects.lua
Library\LibMayronObjects\LibMayronObjects.xml
Library\LibMayronObjects\LibStub.lua
Library\LibMayronObjects\Attributes\InCombatAttribute.lua
Library\LibMayronObjects\Objects\FrameWrapper.lua
Library\LibMayronObjects\Objects\LinkedList.lua
Library\LibMayronObjects\Objects\List.lua
Library\LibMayronObjects\Objects\Map.lua
Library\LibMayronObjects\Objects\Stack.lua

# Myron DB
Library\LibMayronDB\LibMayronDB.lua
Library\LibMayronDB\LibMayronDB.toc
Library\LibMayronDB\LibMayronObjects.lua
Library\LibMayronDB\LibStub.lua

My plugintest.lua file:


-- luacheck: ignore self 143 631
local lib = _G.LibStub:GetLibrary("LibMayronObjects");

local function HelloWorld_Test1() -- luacheck: ignore
    print("HelloWorld_Test1 Started");

    local TestPackage = lib:CreatePackage("HelloWorld_Test1", "Test");

    local HelloWorld = TestPackage:CreateClass("HelloWorld");

    function HelloWorld:Print(private, msg)
        assert(msg == "My 2nd Message");
        assert(private.secret == "This is a secret!");
    end

    function HelloWorld:__Construct(private, msg)
        private.secret = "This is a secret!";
        assert(msg == "My 1st Message");
        assert(self ~= HelloWorld);
    end

    function HelloWorld:__Destruct()
        --print("Instance Destroyed"); -- works!
    end

    local instance = HelloWorld("My 1st Message");
    instance:Print("My 2nd Message");

    local HelloWorld2 = lib:Import("Test.HelloWorld_Test1.HelloWorld");
    assert(HelloWorld == HelloWorld2);

    local className = instance:GetObjectType();
    assert(className == "HelloWorld", className);

    instance:Destroy();

    print("HelloWorld_Test1 Successful!");
end

  • Just to add that the Libraries are in the folders I put in the path.

If you can help me get started that would be great.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.