-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathApply.lua
132 lines (95 loc) · 3.81 KB
/
Apply.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
-----------------------------------------------------------------------------------
-- Apply.lua
-- Enrique García ( enrique.garcia.cota [AT] gmail [DOT] com ) - 4 Mar 2010
-- Makes possible to treat all instances of a class
-----------------------------------------------------------------------------------
assert(Object~=nil and class~=nil, 'MiddleClass not detected. Please require it before using Apply')
assert(Invoker~=nil, 'The Apply module requires the Invoker module in order to work. Please require Invoker before requiring Apply')
--[[ Usage:
require 'middleclass' -- or similar
require 'middleclass-extras.init' -- or 'middleclass-extras'
MyClass = class('MyClass')
MyClass:include(Apply)
function MyClass:initialize()
self.counter = 0
end -- the instance will be automatically added to the list here (after initialize)
function MyClass:count() self.counter = self.counter + 1 end
local obj1 = MyClass:new()
MyClass:apply('count')
local obj2 = MyClass:new()
MyClass:apply('count')
print(obj1.counter, obj2.counter) -- prints 2 1
-- instances will be automatically removed from the list after invoking destroy (obj1:destroy() or obj2:destroy())
]]
--------------------------------
-- PRIVATE STUFF
--------------------------------
-- Creates the list of instances for a class
local function _modifyClass(theClass)
theClass._instances = setmetatable({}, {__mode = "kv"})
end
-- subclasses should also have the _istances list
local function _modifySubclassMethod(theClass)
local prevSubclass = theClass.subclass
theClass.subclass = function(aClass, ...)
local theSubClass = prevSubclass(aClass, ...)
_modifyClass(theSubClass)
return theSubClass
end
end
-- Adds an instance to the "list of instances" of its class
local function _add(theClass, instance)
if not includes(Apply, theClass) then return end
theClass._instances[instance] = instance
_add(theClass.superclass, instance)
end
-- Removes from the "list of instances"
local function _remove(theClass, instance)
if not includes(Apply, theClass) then return end
_remove(theClass.superclass, instance)
theClass._instances[instance] = nil
end
local function _copyTable(t)
local copy,i = {},1
for _,item in pairs(t) do
copy[i] = item
i = i + 1
end
return copy
end
--------------------------------
-- PUBLIC STUFF
--------------------------------
-- The Apply module
Apply = {}
-- Applies some method to all the instances of this class, including subclasses
function Apply.apply(theClass, methodOrName, ...)
return Apply.applySorted(theClass, nil, methodOrName, ... )
end
-- Applies some method to all the instances of this class, including subclasses
-- Notes:
-- * sortFunc can be provided as a meaning of sorting (table.sort will be used). Can be nil (no order)
-- * a copy of the instances table is always made so calling removeFromApply is safe inside apply
function Apply.applySorted(theClass, sortFunc, methodOrName, ...)
-- this copy is needed in case the invoked function results in an item deletion
local instances = _copyTable(theClass._instances)
if type(sortFunc)=='function' then
table.sort(instances, sortFunc)
end
for _,instance in ipairs(instances) do
if Invoker.invoke(instance, methodOrName, ...) == false then return false end
end
return true
end
--------------------------------
-- INCLUDED
--------------------------------
-- modifies the class that includes this module. For internal use only.
function Apply:included(theClass)
if includes(Apply, theClass) then return end
theClass:include(Callbacks)
theClass:before('initialize', function(instance) _add(instance.class, instance) end)
theClass:after('destroy', function(instance) _remove(instance.class, instance) end)
_modifyClass(theClass)
_modifySubclassMethod(theClass)
end