Ir para conteúdo
Entre para seguir isso  
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.

Editado por Socket

Compartilhar este post


Link para o post
Compartilhar em outros 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

Compartilhar este post


Link para o post
Compartilhar em outros 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

Compartilhar este post


Link para o post
Compartilhar em outros 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 ^^

Compartilhar este post


Link para o post
Compartilhar em outros sites
Mock    32
Mock

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

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

Compartilhar este post


Link para o post
Compartilhar em outros 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.

Editado por Mickfern

Compartilhar este post


Link para o post
Compartilhar em outros sites
Gpwjhlkdcf    21
Gpwjhlkdcf

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

Compartilhar este post


Link para o post
Compartilhar em outros sites
Dartier    0
Dartier

mt f0da cara

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

Compartilhar este post


Link para o post
Compartilhar em outros sites
Visitante
Este tópico está impedido de receber novos posts.
Entre para seguir isso  

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.

×