created the Node pseudo-class

This commit is contained in:
Enrique García 2011-10-30 17:50:46 +01:00
parent c5e741e884
commit 1aa51a9ac5

View File

@ -16,59 +16,80 @@ local function copy(t)
end end
-- private node-exclusive functions -- private node-exclusive functions
local function findOrCreateChildNode(node, key)
node.children[key] = node.children[key] or { callbacks = {}, children = {} } local Node = {
return node.children[key] _nodesById = setmetatable({}, {__mode="k"})
}
function Node:new()
return setmetatable( { callbacks = {}, children = {} }, { __index = Node } )
end end
local function findOrCreateDescendantNode(node, keys) function Node:findById(id)
return self._nodesById[id]
end
function Node:findOrCreateChild(key)
self.children[key] = self.children[key] or Node:new()
return self.children[key]
end
function Node:findOrCreateDescendant(keys)
local node = self
for i=1, #keys do for i=1, #keys do
node = findOrCreateChildNode(node, keys[i]) node = node:findOrCreateChild(keys[i])
end end
return node return node
end end
local function executeNodeCallbacks(node, params) function Node:executeCallbacks(params)
local counter = 0 local counter = 0
for _,callback in pairs(node.callbacks) do for _,callback in pairs(self.callbacks) do
callback(unpack(params)) callback(unpack(params))
counter = counter + 1 counter = counter + 1
end end
return counter return counter
end end
local function executeAllCallbacks(node, params) function Node:executeAllCallbacks(params)
local counter = executeNodeCallbacks(node, params) local counter = self:executeCallbacks(params)
for _,child in pairs(node.children) do for _,child in pairs(self.children) do
counter = counter + executeAllCallbacks(child, params) counter = counter + child:executeAllCallbacks(params)
end end
return counter return counter
end end
local function executeEventCallbacks(node, event) function Node:executeEventCallbacks(event)
local params = copy(event) local params = copy(event)
local counter = executeNodeCallbacks(node, params) local counter = self:executeCallbacks(params)
local node = self
for i=1, #event do for i=1, #event do
node = node.children[event[i]] node = node.children[event[i]]
if not node then break end if not node then break end
table.remove(params, 1) table.remove(params, 1)
counter = counter + executeNodeCallbacks(node, params) counter = counter + node:executeCallbacks(params)
end end
return counter return counter
end end
local function removeCallbackFromNode(node, id) function Node:removeCallback(id)
if not node then return false end self.callbacks[id] = nil
node.callbacks[id] = nil Node._nodesById[id] = nil
return true end
function Node:addCallback(callback)
local id = {}
self.callbacks[id] = callback
Node._nodesById[id] = self
return id
end end
-- beholder private functions -- beholder private functions
local function checkSelf(self, methodName) local function checkSelf(self, methodName)
assert(type(self)=="table" and self._root and self._nodesById, "Use beholder:" .. methodName .. " instead of beholder." .. methodName) assert(type(self)=="table" and self._root, "Use beholder:" .. methodName .. " instead of beholder." .. methodName)
end end
local function extractEventAndCallbackFromParams(params) local function extractEventAndCallbackFromParams(params)
@ -78,19 +99,7 @@ local function extractEventAndCallbackFromParams(params)
end end
local function initialize(self) local function initialize(self)
self._root = { callbacks={}, children={} } self._root = Node:new()
self._nodesById = setmetatable({}, {__mode="k"})
end
local function findNodeById(self, id)
return self._nodesById[id]
end
local function addCallbackToNode(self, node, callback)
local id = {}
node.callbacks[id] = callback
self._nodesById[id] = node
return id
end end
------ Public interface ------ Public interface
@ -100,22 +109,25 @@ local beholder = {}
function beholder:observe(...) function beholder:observe(...)
checkSelf(self, 'observe') checkSelf(self, 'observe')
local event, callback = extractEventAndCallbackFromParams({...}) local event, callback = extractEventAndCallbackFromParams({...})
return addCallbackToNode(self, findOrCreateDescendantNode(self._root, event), callback) return self._root:findOrCreateDescendant(event):addCallback(callback)
end end
function beholder:stopObserving(id) function beholder:stopObserving(id)
checkSelf(self, 'stopObserving') checkSelf(self, 'stopObserving')
return removeCallbackFromNode(findNodeById(self, id), id) local node = Node:findById(id)
if not node then return false end
node:removeCallback(id)
return true
end end
function beholder:trigger(...) function beholder:trigger(...)
checkSelf(self, 'trigger') checkSelf(self, 'trigger')
return falseIfZero( executeEventCallbacks(self._root, {...}) ) return falseIfZero( self._root:executeEventCallbacks({...}) )
end end
function beholder:triggerAll(...) function beholder:triggerAll(...)
checkSelf(self, 'triggerAll') checkSelf(self, 'triggerAll')
return falseIfZero( executeAllCallbacks(self._root, {...}) ) return falseIfZero( self._root:executeAllCallbacks({...}) )
end end
function beholder:reset() function beholder:reset()