Simplify matrix.eventable for the common use cases

This removes the support for passing values to eventable.functions() and
eventable.object() which are bound to be passed to handlers. On top of
simplifying the code overall, this also avoids having three different
implementations of the fire() function.

In the existing code, the only case in which a handler argument is fixed
is for objects which pass themselves. This use case is covered by
eventable.object(), so the removed code was not realy ever used.
This commit is contained in:
Adrian Perez de Castro
2016-07-03 22:21:33 +03:00
parent 72060d8a32
commit 4e9899dbb5

View File

@@ -8,6 +8,7 @@
local _select, _pack, _unpack = select, table.pack, table.unpack or unpack local _select, _pack, _unpack = select, table.pack, table.unpack or unpack
if not _pack then if not _pack then
-- Provide a table.pack() implementation for Lua 5.1 and LuaJIT.
_pack = function (...) _pack = function (...)
local n = _select("#", ...) local n = _select("#", ...)
local r = { n = n } local r = { n = n }
@@ -18,28 +19,15 @@ if not _pack then
end end
end end
local function _expack (args, ...)
local r = { n = args.n }
local n = _select("#", ...)
for i = 1, args.n do
r[i] = args[i]
end
for i = 1, n do
r[r.n + i] = _select(i, ...)
end
r.n = r.n + n
return _unpack(r)
end
local log = (function () local log = (function ()
local env_value = os.getenv("MATRIX_EVENTABLE_DEBUG_LOG") local env_value = os.getenv("MATRIX_EVENTABLE_DEBUG_LOG")
if env_value and #env_value > 0 and env_value ~= "0" then if env_value and #env_value > 0 and env_value ~= "0" then
local out, _tostring = io.stderr, tostring local out, _tostring = io.stderr, tostring
return function (...) return function (...)
out:write("[eventable]") out:write("[eventable]")
local args = _pack(...) local n = _select("#", ...)
for i = 1, args.n do for i = 1, n do
out:write(" " .. _tostring(args[i])) out:write(" " .. _tostring(_select(i, ...)))
end end
out:write("\n") out:write("\n")
out:flush() out:flush()
@@ -49,100 +37,66 @@ local log = (function ()
end end
end)() end)()
local function eventable_functions (...) local function do_hook(event_map, event, handler)
local event_map = {} log("hook:", event, handler)
if not handler then
local hook = function (event, handler) event_map[event] = nil
log("hook:", event, handler)
if not handler then
event_map[event] = nil
else
if not event_map[event] then
event_map[event] = {}
end
local handlers = event_map[event]
handlers[#handlers + 1] = handler
end
end
local unhook = function (event, handler)
log("unhook:", event, handler)
local old_handlers = event_map[event]
if old_handlers then
local handlers = {}
for i = 1, #old_handlers do
local h = old_handlers[i]
if h ~= handler then
handlers[#handlers + 1] = h
end
end
event_map[event] = handlers
end
end
local fire
local nargs = _select("#", ...)
if nargs == 0 then
-- Simplest version, no arguments.
fire = function (event, ...)
log("fire: " .. event .. ":", ...)
local handlers = event_map[event]
if handlers then
for i = 1, #handlers do
local ret = _pack(handlers[i](...))
if ret.n > 0 then
return _unpack(ret)
end
end
end
end
elseif nargs == 1 then
-- Common single-argument case: optimized.
local arg = _select(1, ...)
fire = function (event, ...)
log("fire: " .. event .. ":", arg, ...)
local handlers = event_map[event]
if handlers then
for i = 1, #handlers do
local ret = _pack(handlers[i](arg, ...))
if ret.n > 0 then
return _unpack(ret)
end
end
end
end
else else
-- Generic multi-argument case. if not event_map[event] then
local args = _pack(...) event_map[event] = {}
fire = function (event, ...)
log("fire: " .. event .. ":", _expack(args, ...))
local handlers = event_map[event]
if handlers then
for i = 1, #handlers do
local ret = _pack(handlers[i](_expack(args, ...)))
if ret.n > 0 then
return _unpack(ret)
end
end
end
end end
local handlers = event_map[event]
handlers[#handlers + 1] = handler
end end
return fire, hook, unhook
end end
local function eventable_object(obj) local function do_unhook(event_map, event, handler)
local fire, hook, unhook = eventable_functions() log("unhook:", event, handler)
function obj:fire(name, ...) local old_handlers = event_map[event]
return fire(name, self, ...) if old_handlers then
local handlers = {}
for i = 1, #old_handlers do
local h = old_handlers[i]
if h ~= handler then
handlers[#handlers + 1] = h
end
end
event_map[event] = handlers
end
end
local function do_fire(event_map, event, ...)
log("fire: " .. event .. ":", ...)
local handlers = event_map[event]
if handlers then
for i = 1, #handlers do
local ret = _pack(handlers[i](...))
if ret.n > 0 then
return _unpack(ret)
end
end
end
end
local function eventable_functions (event_map)
if not event_map then event_map = {} end
return function (e, ...) return do_fire(event_map, e, ...) end,
function (e, h) return do_hook(event_map, e, h) end,
function (e, h) return do_unhook(event_map, e, h) end
end
local function eventable_object(obj, event_map)
if not obj then obj = {} end
if not event_map then event_map = {} end
function obj:fire(e, ...)
return do_fire(event_map, e, self, ...)
end end
function obj:hook(...) function obj:hook(...)
hook(...) do_hook(event_map, ...)
return self -- Allow chaining return self -- Allow chaining
end end
function obj:unhook(...) function obj:unhook(...)
unhook(...) do_unhook(event_map, ...)
return self -- Allow chaining return self -- Allow chaining
end end
return obj return obj