mirror of
https://github.com/kikito/middleclass.git
synced 2024-10-05 23:24:17 +00:00
moved mixins out of middleclass, and into PÄSSION
This commit is contained in:
parent
3d4cc7b5b8
commit
9fd4ccee72
@ -1,172 +0,0 @@
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Beholder.lua
|
||||
-- Enrique García ( enrique.garcia.cota [AT] gmail [DOT] com ) - 4 Mar 2010
|
||||
-- Small framework for event observers
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
assert(Object~=nil and class~=nil, 'MiddleClass not detected. Please require it before using Callbacks')
|
||||
assert(Sender~=nil, 'The Beholder module requires the Sender module in order to work. Please require Sender before requiring Beholder')
|
||||
|
||||
|
||||
--[[ Usage:
|
||||
|
||||
require 'middleclass.mixins.Beholder' -- or 'middleclass.init'
|
||||
|
||||
MyClass = class('MyClass')
|
||||
MyClass:includes(Beholder)
|
||||
function MyClass:foo(x,y) ... end
|
||||
|
||||
local obj = MyClass:new()
|
||||
|
||||
-- when the 'newgame' event is fired, call method foo with parameters 100 and 200
|
||||
obj:observe('newgame', 'foo', 100, 200)
|
||||
|
||||
-- you can add more than one callbacks to the same event:
|
||||
obj:observe('newgame', 'foo', 300, 400)
|
||||
|
||||
-- alternatively, use a function
|
||||
obj:observe('endgame', function(myself) myself.blah = 0 end)
|
||||
|
||||
-- trigger the event:
|
||||
Beholder.trigger('newgame')
|
||||
|
||||
-- stop observing an event:
|
||||
obj:stopObserving('newgame')
|
||||
|
||||
|
||||
]]
|
||||
|
||||
--------------------------------
|
||||
-- PRIVATE NODE CLASS
|
||||
--------------------------------
|
||||
|
||||
local Node = class('Node')
|
||||
|
||||
function Node:initialize()
|
||||
super.initialize(self)
|
||||
self.children = {}
|
||||
self.objects=setmetatable({}, {__mode='k'})
|
||||
end
|
||||
|
||||
function Node:getOrCreateChild(key)
|
||||
local child = self.children[key]
|
||||
if child == nil then
|
||||
child = Node:new()
|
||||
child.parent = self
|
||||
self.children[key] = child
|
||||
end
|
||||
return child
|
||||
end
|
||||
|
||||
function Node:getOrCreateDescendant(key)
|
||||
if type(key) ~= 'table' then return self:getOrCreateChild(key) end
|
||||
local node = self
|
||||
for _,v in ipairs(key) do node = node:getOrCreateChild(v) end
|
||||
return node
|
||||
end
|
||||
|
||||
function Node:getDescendant(key)
|
||||
if type(key) ~= 'table' then return self.children[key] end
|
||||
local node = self
|
||||
for _,v in ipairs(key) do
|
||||
node = node.children[v]
|
||||
if node == nil then return nil end
|
||||
end
|
||||
return node
|
||||
end
|
||||
|
||||
function Node:getOrRegisterObject(object)
|
||||
self.objects[object] = self.objects[object] or {}
|
||||
return self.objects[object]
|
||||
end
|
||||
|
||||
function Node:addAction(object, method, ...)
|
||||
local actions = self:getOrRegisterObject(object)
|
||||
table.insert(actions, { method = method, params = {...} })
|
||||
end
|
||||
|
||||
function Node:removeAction(object, method)
|
||||
if method == nil then self.objects[object] = nil end
|
||||
local actions = self.objects[object]
|
||||
if actions==nil then return end
|
||||
|
||||
local index = 1
|
||||
for i,v in ipairs(actions) do
|
||||
if v == method then index = i break end
|
||||
end
|
||||
|
||||
if(index~=nil) then table.remove(actions, index) end
|
||||
end
|
||||
|
||||
|
||||
-- Private variable storing the list of event callbacks that can be used
|
||||
--[[ structure:
|
||||
_root = { -- root node
|
||||
children =
|
||||
'a' = { -- root->a node
|
||||
children = {
|
||||
'b' = { -- root->a->b node
|
||||
children = {},
|
||||
objects = { -- list of objects registered on node root->a->b
|
||||
obj1 = { -- list of actions to perform on object1
|
||||
{ method = 'method1', params = {} },
|
||||
{ method = 'method2', params = {1,2}}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
objects = {} -- node root->a does not have any object registered
|
||||
}
|
||||
'b' = { -- root->b node
|
||||
children = {}, -- no children nor objects
|
||||
objects = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]
|
||||
local _root = Node:new()
|
||||
|
||||
-- The Beholder module
|
||||
Beholder = {}
|
||||
|
||||
function Beholder:observe(eventId, methodOrName, ...)
|
||||
|
||||
assert(self~=nil, "self is nil. invoke object:observe instead of object.observe")
|
||||
assert(eventId~=nil, "eventId can not be nil")
|
||||
local t = type(methodOrName)
|
||||
assert(t=='string' or t=='function', 'methodOrName must be a function or string')
|
||||
|
||||
local node = _root:getOrCreateDescendant(eventId)
|
||||
|
||||
node:addAction(self, methodOrName, ...)
|
||||
end
|
||||
|
||||
function Beholder:stopObserving(eventId, methodOrName)
|
||||
local node = _root:getDescendant(eventId)
|
||||
if node==nil then return end
|
||||
node:removeAction(self, methodOrName)
|
||||
end
|
||||
|
||||
|
||||
--[[ Triggers events
|
||||
Usage:
|
||||
Beholder.trigger('passion.update', dt)
|
||||
All objects that are "observing" passion.update events will get their associated actions called.
|
||||
]]
|
||||
|
||||
function Beholder.trigger(eventId, ...)
|
||||
|
||||
local node = _root:getDescendant(eventId)
|
||||
if node==nil then return end
|
||||
|
||||
for object,actions in pairs(node.objects) do
|
||||
for _,action in ipairs(actions) do
|
||||
local params = {}
|
||||
for k,v in ipairs(action.params) do params[k] = v end
|
||||
for _,v in ipairs({...}) do table.insert(params, v) end
|
||||
|
||||
Sender.send(object, action.method, unpack(params))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,221 +0,0 @@
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Callbacks.lua
|
||||
-- Enrique García ( enrique.garcia.cota [AT] gmail [DOT] com )
|
||||
-- Mixin that adds callbacks support (i.e. beforeXXX or afterYYY) to classes)
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
assert(Object~=nil and class~=nil, 'MiddleClass not detected. Please require it before using Callbacks')
|
||||
assert(Sender~=nil, 'The Callbacks module requires the Sender module in order to work. Please require Sender before requiring Callbacks')
|
||||
|
||||
--[[ Usage:
|
||||
|
||||
MyClass = class('MyClass')
|
||||
MyClass:include(Callbacks)
|
||||
|
||||
MyClass:addCallbacksAround('foo') -- this defines methods 'beforeFoo' and 'afterFoo'
|
||||
|
||||
MyClass:beforeFoo('bar') -- can use either method names or functions
|
||||
MyClass:afterFoo(function() print('baz') end)
|
||||
|
||||
function MyClass:foo() print 'foo' end
|
||||
function MyClass:bar() print 'bar' end
|
||||
|
||||
local obj = MyClass:new()
|
||||
|
||||
obj:foo() -- prints 'bar foo baz'
|
||||
]]
|
||||
|
||||
--------------------------------
|
||||
-- PRIVATE STUFF
|
||||
--------------------------------
|
||||
|
||||
--[[ holds all the callbacks entries.
|
||||
callback entries are just lists of methods to be called before / after some other method is called
|
||||
|
||||
_callbackEntries = {
|
||||
Actor = {
|
||||
beforeUpdate = { methods = {m1, m2, m3 } }, -- m1, m2, m3 & m4 can be method names or functions
|
||||
afterUpdate = { methods = { 'm4' } },
|
||||
update = {
|
||||
before = 'beforeUpdate',
|
||||
after = 'afterUpdate'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
]]
|
||||
local _callbackEntries = setmetatable({}, {__mode = "k"}) -- weak table
|
||||
|
||||
-- cache for not re-creating methods every time they are needed
|
||||
local _methodCache = setmetatable({}, {__mode = "k"})
|
||||
|
||||
-- private class methods
|
||||
|
||||
local _getCallbackEntry
|
||||
local function _getCallbackEntry(theClass, callbackName)
|
||||
if theClass == nil or callbackName == nil then return nil end
|
||||
if _callbackEntries[theClass] ~= nil and _callbackEntries[theClass][callbackName] ~= nil then
|
||||
return _callbackEntries[theClass][callbackName]
|
||||
end
|
||||
return _getCallbackEntry(theClass.superclass, callbackName)
|
||||
end
|
||||
|
||||
-- creates one of the "level 2" entries on callbacks, like beforeUpdate or afterupdate, above
|
||||
local function _getOrCreateCallbackEntry(theClass, callbackName)
|
||||
if not theClass or not callbackName then return {} end
|
||||
_callbackEntries[theClass] = _callbackEntries[theClass] or setmetatable({}, {__mode = "k"})
|
||||
local classEntries = _callbackEntries[theClass]
|
||||
classEntries[callbackName] = classEntries[callbackName] or setmetatable({ methods={} }, {__mode = "k"})
|
||||
|
||||
return classEntries[callbackName]
|
||||
end
|
||||
|
||||
-- returns all the methods that should be called when a callback is invoked, including superclasses
|
||||
local function _getCallbackEntryChainMethods(theClass, callbackName)
|
||||
if theClass==nil then return {} end
|
||||
local methods = _getOrCreateCallbackEntry(theClass, callbackName).methods
|
||||
local superMethods = _getCallbackEntryChainMethods(theClass.superclass, callbackName)
|
||||
|
||||
local result = {}
|
||||
for i,method in ipairs(methods) do result[i]=method end
|
||||
for _,method in ipairs(superMethods) do table.insert(result, method) end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- defines a callback method. These methods are used to add "methods" to the callback.
|
||||
-- for example, after calling _defineCallbackMethod(Actor, 'afterUpdate') you can then do
|
||||
-- Actor:afterUpdate('removeFromList', 'dance', function(actor) actor:doSomething() end)
|
||||
local function _defineCallbackMethod(theClass, callbackName)
|
||||
if callbackName == nil then return nil end
|
||||
|
||||
assert(rawget(theClass.__classDict,callbackName)==nil, "Could not define " .. theClass.name .. '.' .. callbackName .. ": already defined")
|
||||
|
||||
theClass[callbackName] = function(theClass, ...)
|
||||
local methods = {...}
|
||||
local existingMethods = _getOrCreateCallbackEntry(theClass, callbackName).methods
|
||||
for _,method in ipairs(methods) do
|
||||
table.insert(existingMethods, method)
|
||||
end
|
||||
end
|
||||
|
||||
_getOrCreateCallbackEntry(theClass, callbackName)
|
||||
|
||||
return theClass[callbackName]
|
||||
end
|
||||
|
||||
-- private instance methods
|
||||
|
||||
-- given a callback entry, obtain all the methods that must be called for that callback and execute them
|
||||
local function _runCallbackChain(object, entry, before_or_after)
|
||||
if entry == nil then return true end
|
||||
callbackName = entry[before_or_after]
|
||||
if callbackName==nil then return true end
|
||||
local methods = _getCallbackEntryChainMethods(object.class, callbackName)
|
||||
for _,method in ipairs(methods) do
|
||||
if Sender.send(object, method) == false then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- given a class and a method, this returns a new version of that method that invokes callbacks
|
||||
-- uses a cache for not calculating the methods every time
|
||||
function _getChainedMethod(theClass, methodName, method)
|
||||
local entry = _getCallbackEntry(theClass, methodName)
|
||||
|
||||
if(entry==nil) then return method end
|
||||
|
||||
_methodCache[theClass] = _methodCache[theClass] or setmetatable({}, {__mode = "k"})
|
||||
local classCache = _methodCache[theClass]
|
||||
|
||||
local chainedMethod = classCache[methodName]
|
||||
|
||||
if chainedMethod == nil then
|
||||
chainedMethod = function(self, ...)
|
||||
if _runCallbackChain(self, entry, 'before') == false then return false end
|
||||
local result = method(self, ...)
|
||||
if _runCallbackChain(self, entry, 'after') == false then return false end
|
||||
return result
|
||||
end
|
||||
classCache[methodName] = chainedMethod
|
||||
end
|
||||
|
||||
return chainedMethod
|
||||
end
|
||||
|
||||
-- helper function used by addCallbacksBefore, after and around
|
||||
function _addCallbacks(theClass, before_or_after, methodName, callbackMethodName)
|
||||
assert(type(methodName)=='string', 'methodName must be a string')
|
||||
assert(before_or_after == 'before' or before_or_after == 'after', 'Parameter must be "before" or "after"')
|
||||
|
||||
local entry = _getOrCreateCallbackEntry(theClass, methodName)
|
||||
|
||||
assert(entry[before_or_after] == nil, 'The "' .. tostring(before_or_after) .. '" callback is already defined as "' .. tostring(entry[before_or_after]) .. '". Use that callback method instead or adding a new one' )
|
||||
callbackMethodName = callbackMethodName or before_or_after .. methodName:gsub("^%l", string.upper)
|
||||
|
||||
_defineCallbackMethod(theClass, callbackMethodName)
|
||||
|
||||
entry[before_or_after]= callbackMethodName
|
||||
end
|
||||
|
||||
--------------------------------
|
||||
-- PUBLIC STUFF
|
||||
--------------------------------
|
||||
|
||||
Callbacks = {}
|
||||
|
||||
function Callbacks:included(theClass)
|
||||
|
||||
if includes(Callbacks, theClass) then return end
|
||||
|
||||
-- Modify the instances __index metamethod so it adds callback chains to methods with callback entries
|
||||
|
||||
local oldNew = theClass.new
|
||||
|
||||
theClass.new = function(theClass, ...)
|
||||
local instance = oldNew(theClass, ...)
|
||||
|
||||
local prevIndex = getmetatable(instance).__index
|
||||
local tIndex = type(prevIndex)
|
||||
|
||||
setmetatable(instance, {
|
||||
__index = function(instance, methodName)
|
||||
local method
|
||||
|
||||
if tIndex == 'table' then method = prevIndex[methodName]
|
||||
elseif tIndex == 'function' then method = prevIndex(instance, methodName)
|
||||
end
|
||||
|
||||
if type(method) ~= 'function' then return method end
|
||||
|
||||
return _getChainedMethod(theClass, methodName, method)
|
||||
end
|
||||
})
|
||||
|
||||
-- special treatment for afterInitialize callbacks
|
||||
local entry = _getCallbackEntry(theClass, 'initialize')
|
||||
if _runCallbackChain(instance, entry, 'after') == false then return false end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- usage: Actor:addCallbacksBefore('update')
|
||||
-- callbackMethodName is optional, defaulting to 'beforeUpdate'
|
||||
function Callbacks.addCallbacksBefore(theClass, methodName, callbackMethodName)
|
||||
_addCallbacks(theClass, 'before', methodName, callbackMethodName)
|
||||
end
|
||||
|
||||
-- usage: Actor:addCallbacksAfter('initialize')
|
||||
-- callbackMethodName is optional, defaulting to 'afterInitialize'
|
||||
function Callbacks.addCallbacksAfter(theClass, methodName, callbackMethodName)
|
||||
_addCallbacks(theClass, 'after', methodName, callbackMethodName)
|
||||
end
|
||||
|
||||
-- usage: Actor:addCallbackAround('update')
|
||||
-- before & afterCallbackMethodName are optional, defaulting to 'beforeUpdate' and 'afterUpdate'
|
||||
function Callbacks.addCallbacksAround(theClass, methodName, beforeCallbackMethodName, afterCallbackMethodName)
|
||||
_addCallbacks(theClass, 'before', methodName, beforeCallbackMethodName)
|
||||
_addCallbacks(theClass, 'after', methodName, afterCallbackMethodName)
|
||||
end
|
@ -1,38 +0,0 @@
|
||||
-----------------------------------------------------------------------------------
|
||||
-- GetterSetter.lua
|
||||
-- Enrique García ( enrique.garcia.cota [AT] gmail [DOT] com ) - 11 Aug 2010
|
||||
-- Small mixin for classes with getters and setters
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
--[[ Usage:
|
||||
|
||||
require 'middleclass.mixins.GetterSetter' -- or 'middleclass.init'
|
||||
|
||||
MyClass = class('MyClass')
|
||||
MyClass:include(GetterSetter)
|
||||
|
||||
MyClass:getter('name', 'pete') -- default value
|
||||
MyClass:setter('age')
|
||||
MyClass:getterSetter('color', 'blue') -- default value
|
||||
|
||||
]]
|
||||
|
||||
assert(Object~=nil and class~=nil, 'MiddleClass not detected. Please require it before using GetterSetter')
|
||||
|
||||
GetterSetter = {}
|
||||
|
||||
function GetterSetter.getterFor(theClass, attr) return 'get' .. attr:gsub("^%l", string.upper) end
|
||||
function GetterSetter.setterFor(theClass, attr) return 'set' .. attr:gsub("^%l", string.upper) end
|
||||
function GetterSetter.getter(theClass, attributeName, defaultValue)
|
||||
theClass[theClass:getterFor(attributeName)] = function(self)
|
||||
if(self[attributeName]~=nil) then return self[attributeName] end
|
||||
return defaultValue
|
||||
end
|
||||
end
|
||||
function GetterSetter.setter(theClass, attributeName)
|
||||
theClass[theClass:setterFor(attributeName)] = function(self, value) self[attributeName] = value end
|
||||
end
|
||||
function GetterSetter.getterSetter(theClass, attributeName, defaultValue)
|
||||
theClass:getter(attributeName, defaultValue)
|
||||
theClass:setter(attributeName)
|
||||
end
|
@ -1,38 +0,0 @@
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Sender.lua
|
||||
-- Enrique García ( enrique.garcia.cota [AT] gmail [DOT] com ) - 4 Mar 2010
|
||||
-- Helper function that simplifies method invocation via method names or functions
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
--[[ Usage:
|
||||
|
||||
require 'middleclass.mixins.Sender' -- or 'middleclass.init'
|
||||
|
||||
MyClass = class('MyClass')
|
||||
MyClass:includes(Sender)
|
||||
function MyClass:foo(x,y) print('foo executed with params', x, y) end
|
||||
|
||||
local obj = MyClass:new()
|
||||
|
||||
obj:send('foo', 1,2) -- foo executed with params 1 2
|
||||
obj:send( function(self, x, y)
|
||||
print('nameless function executed with params', x, y)
|
||||
, 3, 4) -- nameless function executed with params 3, 4
|
||||
|
||||
Note that the function first parameter will allways be self
|
||||
]]
|
||||
|
||||
assert(Object~=nil and class~=nil, 'MiddleClass not detected. Please require it before using Beholder')
|
||||
|
||||
Sender = {
|
||||
|
||||
send = function(self, methodOrName, ...)
|
||||
local method = methodOrName
|
||||
if(type(methodOrName)=='string') then method = self[methodOrName] end
|
||||
assert(type(method)=='function', 'Sender:send requires a function or function name')
|
||||
return method(self, ...)
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,77 +0,0 @@
|
||||
require('middleclass.init')
|
||||
|
||||
context( 'Beholder', function()
|
||||
|
||||
context('When included by a class', function()
|
||||
|
||||
local MyClass = class('MyClass')
|
||||
|
||||
function MyClass:initialize()
|
||||
super.initialize(self)
|
||||
self.counter = 0
|
||||
end
|
||||
|
||||
function MyClass:count(increment)
|
||||
self.counter = self.counter + increment
|
||||
end
|
||||
|
||||
function MyClass:count2(increment)
|
||||
self.counter = self.counter + increment
|
||||
end
|
||||
|
||||
test('Should not throw errors', function()
|
||||
assert_not_error(function() MyClass:include(Beholder) end)
|
||||
end)
|
||||
|
||||
context('When starting observing', function()
|
||||
|
||||
test('It should allow calling of methods by name, with parameters', function()
|
||||
local obj = MyClass:new()
|
||||
obj:observe('event1', 'count', 1)
|
||||
Beholder.trigger('event1')
|
||||
assert_equal(obj.counter, 1)
|
||||
end)
|
||||
|
||||
test('It should allow calling of methods by function, with parameters', function()
|
||||
local obj = MyClass:new()
|
||||
obj:observe('event2', function(myself, increment) myself:count(increment) end, 1)
|
||||
Beholder.trigger('event2')
|
||||
assert_equal(obj.counter, 1)
|
||||
end)
|
||||
|
||||
test('It should allow chaining of calls', function()
|
||||
local obj = MyClass:new()
|
||||
obj:observe('event3', 'count', 1)
|
||||
obj:observe('event3', 'count', 1)
|
||||
Beholder.trigger('event3')
|
||||
assert_equal(obj.counter, 2)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
context('When stopping observing', function()
|
||||
|
||||
test('It should allow completely stopping observing one event', function()
|
||||
local obj = MyClass:new()
|
||||
obj:observe('event4', 'count', 1)
|
||||
Beholder.trigger('event4')
|
||||
obj:stopObserving('event4')
|
||||
Beholder.trigger('event4')
|
||||
assert_equal(obj.counter, 1)
|
||||
end)
|
||||
|
||||
test('It should allow stopping observing individual actions on one event', function()
|
||||
local obj = MyClass:new()
|
||||
obj:observe('event5', 'count', 1)
|
||||
obj:observe('event5', 'count2', 1)
|
||||
Beholder.trigger('event5')
|
||||
obj:stopObserving('event5', 'count')
|
||||
Beholder.trigger('event5')
|
||||
assert_equal(obj.counter, 3)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
@ -1,104 +0,0 @@
|
||||
require('middleclass.init')
|
||||
|
||||
context( 'Callbacks', function()
|
||||
local A
|
||||
|
||||
before(function()
|
||||
A = class('A')
|
||||
function A:initialize()
|
||||
super.initialize(self)
|
||||
self.calls = {}
|
||||
end
|
||||
end)
|
||||
|
||||
local function defineRegularMethods(theClass)
|
||||
function theClass:foo() table.insert(self.calls, 'foo') end
|
||||
function theClass:bar() table.insert(self.calls, 'bar') end
|
||||
function theClass:baz() table.insert(self.calls, 'baz') end
|
||||
end
|
||||
|
||||
local function addCallbacks(theClass)
|
||||
theClass:include(Callbacks)
|
||||
theClass:addCallbacksAround('bar')
|
||||
theClass:beforeBar('foo')
|
||||
theClass:afterBar( function(myself) myself:baz() end )
|
||||
end
|
||||
|
||||
local function testInstance(theClass)
|
||||
local obj = theClass:new()
|
||||
obj:bar()
|
||||
|
||||
assert_equal(obj.calls[1], 'foo')
|
||||
assert_equal(obj.calls[2], 'bar')
|
||||
assert_equal(obj.calls[3], 'baz')
|
||||
end
|
||||
|
||||
test('Should work when declared before the methods', function()
|
||||
addCallbacks(A)
|
||||
defineRegularMethods(A)
|
||||
testInstance(A)
|
||||
end)
|
||||
|
||||
test('Should work when declared after the methods', function()
|
||||
defineRegularMethods(A)
|
||||
addCallbacks(A)
|
||||
testInstance(A)
|
||||
end)
|
||||
|
||||
context('When subclassing', function()
|
||||
local B
|
||||
before(function()
|
||||
B = class('B', A)
|
||||
end)
|
||||
|
||||
test('The subclass should include Callbacks', function()
|
||||
A:include(Callbacks)
|
||||
assert_true(includes(Callbacks, B))
|
||||
end)
|
||||
|
||||
test('Callbacks in subclasses should work on inherited methods, even if declared before', function()
|
||||
addCallbacks(B)
|
||||
defineRegularMethods(A)
|
||||
testInstance(B)
|
||||
end)
|
||||
|
||||
test('Callbacks in subclasses should work on inherited methods when declared after', function()
|
||||
defineRegularMethods(A)
|
||||
addCallbacks(B)
|
||||
testInstance(B)
|
||||
end)
|
||||
|
||||
test('Callbacks should be conserved in subclasses', function()
|
||||
addCallbacks(A)
|
||||
defineRegularMethods(A)
|
||||
testInstance(B)
|
||||
end)
|
||||
|
||||
test('Callbacks in subclasses can be used as well as in superclasses', function()
|
||||
addCallbacks(A)
|
||||
defineRegularMethods(A)
|
||||
addCallbacks(B)
|
||||
local obj = B:new()
|
||||
obj:bar()
|
||||
|
||||
assert_equal(obj.calls[1], 'foo')
|
||||
assert_equal(obj.calls[2], 'foo')
|
||||
assert_equal(obj.calls[3], 'bar')
|
||||
assert_equal(obj.calls[4], 'baz')
|
||||
assert_equal(obj.calls[5], 'baz')
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
context('When creating an instance', function()
|
||||
test('afterInitialize should be called', function()
|
||||
defineRegularMethods(A)
|
||||
A:include(Callbacks)
|
||||
A:addCallbacksAfter('initialize')
|
||||
A:afterInitialize('foo')
|
||||
assert_equal(A:new().calls[1], 'foo')
|
||||
end)
|
||||
end)
|
||||
|
||||
|
||||
end)
|
@ -1,38 +0,0 @@
|
||||
require('middleclass.init')
|
||||
|
||||
context( 'GetterSetter', function()
|
||||
|
||||
context('When included by a class', function()
|
||||
|
||||
local MyClass = class('MyClass')
|
||||
|
||||
test('Should not throw errors', function()
|
||||
assert_not_error(function() MyClass:include(GetterSetter) end)
|
||||
end)
|
||||
|
||||
test('It should include the 3 main methods on the class', function()
|
||||
MyClass:getter('name', 'pete')
|
||||
MyClass:setter('age')
|
||||
MyClass:getterSetter('color', 'blue')
|
||||
|
||||
local obj = MyClass:new()
|
||||
assert_equal(obj:getName(), 'pete')
|
||||
obj.name = 'john'
|
||||
assert_equal(obj:getName(), 'john')
|
||||
|
||||
obj:setAge(14)
|
||||
assert_equal(obj.age, 14)
|
||||
|
||||
assert_equal(obj:getColor(), 'blue')
|
||||
obj:setColor('fucsia')
|
||||
assert_equal(obj:getColor(), 'fucsia')
|
||||
end)
|
||||
|
||||
test('It should include the 2 secondary methods on the class', function()
|
||||
assert_equal(MyClass:getterFor('language'), 'getLanguage')
|
||||
assert_equal(MyClass:setterFor('language'), 'setLanguage')
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
end)
|
@ -1,32 +0,0 @@
|
||||
require('middleclass.init')
|
||||
|
||||
context( 'Sender', function()
|
||||
|
||||
local MyClass = class('MyClass')
|
||||
MyClass:include(Sender)
|
||||
function MyClass:foo(x,y) return 'foo ' .. tostring(x) .. ', ' .. tostring(y) end
|
||||
function MyClass:testSelf() return instanceOf(MyClass, self) end
|
||||
|
||||
local obj = MyClass:new()
|
||||
|
||||
test('It should work with method names', function()
|
||||
assert_equal(obj:send('foo', 1, 2), 'foo 1, 2')
|
||||
end)
|
||||
|
||||
test('It should work with implicit functions', function()
|
||||
assert_equal(
|
||||
obj:send(
|
||||
function(self, x, y) return 'bar '.. tostring(x) .. ', ' .. tostring(y) end,
|
||||
3,
|
||||
4
|
||||
),
|
||||
'bar 3, 4'
|
||||
)
|
||||
end)
|
||||
|
||||
test('It should use self as implicit parameter in all cases', function()
|
||||
assert_true(obj:send('testSelf'))
|
||||
assert_true(obj:send(MyClass.testSelf))
|
||||
end)
|
||||
|
||||
end)
|
Loading…
Reference in New Issue
Block a user