Socket 0 #1 Posted August 18, 2010 (edited) 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 September 10, 2010 by Socket Share this post Link to post Share on other sites
Conde2 0 #2 Posted August 18, 2010 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 #3 Posted August 18, 2010 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 Share this post Link to post Share on other sites
Er4gon II 0 #4 Posted August 18, 2010 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 #5 Posted August 19, 2010 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 #6 Posted August 19, 2010 (edited) 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 January 23, 2011 by Mickfern Share this post Link to post Share on other sites
Gpwjhlkdcf 21 #7 Posted September 10, 2010 :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 #8 Posted September 13, 2010 mt f0da cara mas até agora eu to tentando entende isso. Share this post Link to post Share on other sites