Jump to content
Sign in to follow this  
Socket

[Function] Class v2.3.0

Recommended Posts

Socket    0
Socket

A função Class, é uma função que cria uma metaclasse automaticamente, é uma função para uso de scripters no mínimo intermediários ou que conhecem o POO em lua, quer dizer, a simulação de POO em lua.

 

[spoiler=Class]

function Class(name)
   return function(attr)
       function newTable(list)
           local result = {}

           for i, v in pairs(list) do
               if (type(v) == "table") then
                   result[i] = newTable(v)
               else
                   result[i] = v
               end
           end

           return result
       end

       local function setProxy(proxy, index, value)
           getmetatable(proxy)[index] = value
       end

       local function getProxy(proxy, index)
           return getmetatable(proxy)[index]
       end

       _G[name] = setmetatable({}, {__call = function(self, ...)
                                               local result = newproxy(true)

                                               _attr = newTable(attr)

                                               local call = _attr

                                               local ncall = {
                                                               public = {},
                                                               private = {}
                                               }

                                               if (call.public) then
                                                   ncall.public = call.public
                                                   call.public = nil
                                               end

                                               if (call.private) then
                                                   ncall.private = call.private
                                                   call.private = nil
                                               end

                                               for i, v in pairs(call) do
                                                   ncall.public[i] = v
                                               end

                                               setProxy(result, "call", ncall)

                                               local call = getProxy(result, "call")

                                               function setEnv(value, call)
                                                   if (type(value) == "function") then
                                                       local fenv  = getfenv(value)
                                                       local nfenv = {}

                                                       for i, v in pairs(fenv) do
                                                           nfenv[i] = v
                                                       end

                                                       setmetatable(
                                                           nfenv,

                                                           {
                                                               __index = function(self, key)
                                                                   if (key == "this") then
                                                                       return result
                                                                   end

                                                                   return call["private"][key] or call["public"][key]
                                                               end,

                                                               __newindex = function(self, key, value)
                                                                   if (call["private"][key]) then
                                                                       call["private"][key] = value
                                                                   else
                                                                       call["public"][key] = value
                                                                   end
                                                               end
                                                           }
                                                       )

                                                       setfenv(value, nfenv)
                                                   end
                                               end

                                               for i, v in pairs(call["private"]) do
                                                   setEnv(v, call)
                                               end

                                               for i, v in pairs(call["public"]) do
                                                   setEnv(v, call)
                                               end

                                               local events = {
                                                               "__newindex",
                                                               "__gc", "__mode", "__eq",
                                                               "__add", "__sub", "__mul", "__div", "__mod",
                                                               "__pow", "__unm", "__len", "__lt", "__le",
                                                               "__concat", "__call", "__tostring"
                                               }

                                               local _M = {
                                                           __index = function(table, key)
                                                                   if ((key == "private") or (key == "public")) then
                                                                       return nil
                                                                   end

                                                                   local call = getProxy(table, "call")
                                                                   local value = call["public"][key]

                                                                   if (type(value) == "function") then
                                                                       setEnv(value, call)

                                                                       return function(self, ...)
                                                                           local n = (self == table) and 2 or 1
                                                                           return value(select(n, unpack{self, ...}))
                                                                       end
                                                                   else

                                                                       local f = function(table, key)
                                                                           local callback = rawget(call["private"] or { }, "__index")

                                                                           if not (type(callback) == "function") then
                                                                               return nil
                                                                           end

                                                                           return callback(key)
                                                                       end

                                                                       return value or f(table, key)
                                                                   end
                                                           end,

                                                           __newindex = function(table, key, value)
                                                               local call = getProxy(table, "call")
                                                               call[key] = value
                                                               setProxy(table, "call", call)
                                                           end
                                               }

                                               if (rawget(call["public"], "~" .. name)) then
                                                   _M["__gc"] = rawget(call["public"], "~" .. name)
                                               end

                                               for i, event in ipairs(events) do
                                                   if (rawget(call["private"], event)) then
                                                       local callback = rawget(call["private"], event)

                                                       if (type(callback) == "function") then
                                                           _M[event] = function(self, ...) return callback(...) end
                                                       end
                                                   end
                                               end

                                               for i, event in pairs(_M) do
                                                   setProxy(result, i, event)
                                               end

                                               if (result[name]) then
                                                   local __init = result[name](...)

                                                   if (__init == false) then
                                                       return nil
                                                   end
                                               end

                                               return result
                                           end
                               }
       )

   end
end

 

 

 

  • Definição

 

Class(string)(table)

Exemplo, criando a classe Integer:

 

Class "Integer" {}

Para quem não entendeu a chamada da função, aquilo é o mesmo que fazer:

 

Class("Integer")({})

  • Criação de Objeto

 

Ao criar uma classe, a função automaticamente criará uma função com o nome da classe, que ao ser chamada criará o novo objeto. Caso exista um método com o mesmo nome da classe, esse método será criado para fazer a operação de criação de novo objeto. Lembrando que caso esse método retorne false, a criação de novo objeto é suspensa e é retornado nil.

 

 

 

  • Atribuição de métodos e atributos

 

Nessa versão, você não precisa definir uma variavel, para agir como o self, como no c++, você apenas chama o atributo ou o método. Vale lembrar que isso só é valido dentro de métodos, fora dos mesmos, isso não é possível.

 

Agora, na versão 2.3, você pode usar duas tabelas especiais, a private, e a public. Atributos e métodos definidos dentro de private, só podem ser acessados dentro de métodos da própria classe, agora, atributos e métodos definidos em public, são acessados internamente e externamente. Atributos e métodos definidos fora de private, e de public são considerados publicos automaticamente.

 

Vale ressaltar que uma variável em especial, this, retorna o objeto criado. Útil para definir variáveis externas contendo o objeto.

 

 

 

  • Chamadas de métodos e atributos

 

Nessa versão da Class, é possível chamar métodos utilizando os operadores ponto (.), e dois-pontos (:). Atributos só podem ser chamados utilizando o operador ponto (.)

 

 

 

  • Definição de metamétodos

 

Na atual versão de Class, metamétodos devem ser definidos como private. Todos os metamétodos podem ser definidos em Class, diferentemente da simulação de programação orientada a objetos de lua, que não aceitam alguns metamétodos, como os de comparação: __len (#), __lt (<) e __le (<=), exceto no caso de você criar o objeto utilizando a API C

Uma alternativa para o metamétodo __gc, é o método (~ + nome da classe), por exemplo ~Num, nesse caso, ~Num, deve ser definido como public. Para acessar o objeto pelo metamétodo utilize this

 

 

 

  • Exemplo

 

Classe Num,com os métodos Num (construtor) e ~Num (destrutor):

 

[spoiler=Num]

 

 

  • Definição da Classe

 

 

Class "Num" {
   private = {
           n = 0 -- declarando `n` como private
   },

   public = {
           ["Num"] = function(s)         -- método construtor
               if (type(s) ~= "number") then
                   return false
               else
                   n = s
               end
           end,

           ["~Num"] = function(t)     -- método destrutor
               t = nil
               collectgarbage()
           end,

           ["get"] = function()         -- método `get` declarado como public
               return n                -- acessando `n` internamente
           end,

           ["set"] = function(new)     -- método `set` declarado como public
               n = new                    -- editando `n` internamente
           end,

           ["add"] = function(va)        -- método `add` declarado como public
               set(get() + va)            -- chamando métodos internamente
           end
   },

   ["sub"] = function(va) -- método `sub` é considerado como public, pois está "solto"
           add(-va)        -- chamando método internamente
   end
}

  • Criação do Objeto

 

 

Number = Num(2)    -- definindo Num como um novo objeto, obs: método construtor `Num` é chamado

Number:add(5) -- método chamado utilizando (

Number.sub(2) -- método chamado utilizando (.)

print(Number.get()) -- método chamado utilizando ., retorna 5 pois (2) + 5 - 2 = 5

print(Number.n) -- atributo chamado utilizando (.) , `n` é protect, por isso retorna nil

 

 

 

Atenciosamente, Socket.

Edited by Socket

Share this post


Link to post
Share on other sites
Conde2    0
Conde2

Muito bom cara nem sabia que dava para criar um jeito de usar essas methods em uma metatable vazia.

Você usou uma outra função pra edita-lá né xD

E adicionar os methods....

 

 

Muito foda mesmo =)

Ei posta um changelog da V1.0 pra 2.0

Share this post


Link to post
Share on other sites
Socket    0
Socket

Eu utilizei uma userdata com metatable vazia, chamando a função newproxy(true)

 

Assim da para utilizar todos aqueles metamétodos.

 

E vo pensar no caso do changelog :P

Share this post


Link to post
Share on other sites
Er4gon II    0
Er4gon II
Muito bom cara nem sabia que dava para criar um jeito de usar essas methods em uma metatable vazia.

Você usou uma outra função pra edita-lá né xD

E adicionar os methods....

 

 

Muito foda mesmo =)

Ei posta um changelog da V1.0 pra 2.0

 

 

kkk tbm nao ^^

Share this post


Link to post
Share on other sites
Mock    32
Mock

graças a min vc vc soube do newproxy ;D

sabe que da pra por newproxy(false) tb né?

Share this post


Link to post
Share on other sites
Socket    0
Socket

Não dá não Mock:

 

newproxy([bool])
newproxy([userdata])

 

Se for uma userdata, ele cria uma userdata com a mesma metatable da userdata dada à função.

 

Se for false/nil, ele cria uma userdata sem metatable, se for true ele cria uma userdata com metatable {}.

 

Foi assim que eu editei a metatable do objeto, se cria uma userdata sem metatable, creio que não tem utilidade nenhuma.

Edited by Mickfern

Share this post


Link to post
Share on other sites
Gpwjhlkdcf    21
Gpwjhlkdcf

:palm: não adiantou falar pra não fazer isso ai do private e public né

Share this post


Link to post
Share on other sites
Dartier    0
Dartier

mt f0da cara

mas até agora eu to tentando entende isso. icon_lol.gif

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×