summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <daniel.silverstone@codethink.co.uk>2017-05-13 13:59:27 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2017-06-17 15:03:28 +0100
commit3b377ffac94c109a9a8c73412dedf9035f539b0f (patch)
treee8b3fbe18648430efc0c0d55e2cd7ca025063aed
parentea637c6dbc4d50239e0d5b7b57b08a724d3bb5e3 (diff)
downloadgitano-3b377ffac94c109a9a8c73412dedf9035f539b0f.tar.gz
Add gitano.hooks module with basic functionality
The gitano.hooks module is intended to support a variety of hooks, both those defined by Gitano itself; and those added by plugins. Hooks are meant as a means to propagate information and also to permit alteration of arguments before work is done.
-rw-r--r--lib/gitano/hooks.lua101
1 files changed, 101 insertions, 0 deletions
diff --git a/lib/gitano/hooks.lua b/lib/gitano/hooks.lua
new file mode 100644
index 0000000..0de2325
--- /dev/null
+++ b/lib/gitano/hooks.lua
@@ -0,0 +1,101 @@
+-- gitano.hooks
+--
+-- Hook management routines for Gitano
+--
+-- Copyright 2017 Daniel Silverstone <dsilvers@digital-scurf.org>
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+-- 1. Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+-- 2. Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in the
+-- documentation and/or other materials provided with the distribution.
+-- 3. Neither the name of the author nor the names of their contributors
+-- may be used to endorse or promote products derived from this software
+-- without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+-- ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+-- SUCH DAMAGE.
+--
+--
+--
+
+local hooks = {}
+
+local function _get_hook(hookname)
+ local ret = hooks[hookname] or {}
+ hooks[hookname] = ret
+ return ret
+end
+
+local function _sort(hooktab)
+ table.sort(hooktab, function(a,b) return a[1] < b[1] end)
+end
+
+local function add_to_hook(hookname, priority, func)
+ assert(hookname, "Cannot add to a nil hook")
+ assert(type(priority) == "number", "Cannot use a non-numerical priority")
+ assert(type(func) == "function", "Cannot use a non-function hook func")
+ local h = _get_hook(hookname)
+ h[#h+1] = {priority, func}
+end
+
+local function _allbutone(_, ...)
+ return ...
+end
+
+local function run_hook(hookname, ...)
+ assert(hookname, "Cannot run a nil hook")
+ local h = _get_hook(hookname)
+ _sort(h)
+ local args = {...}
+ for _, entry in ipairs(h) do
+ local result = { entry[2](unpack(args)) }
+ if result[1] == nil then
+ return unpack(result)
+ elseif type(result[1]) ~= "string" then
+ return nil, "Bad results", unpack(result)
+ elseif result[1] == "stop" then
+ return _allbutone(unpack(result))
+ elseif result[1] == "update" then
+ args = {_allbutone(unpack(result))}
+ elseif result[1] == "continue" then
+ -- Nothing to do
+ else
+ return nil, "Bad results", unpack(result)
+ end
+ end
+ return unpack(args)
+end
+
+-- Hook functions take the form:
+-- action, ... = hookfunc(...)
+-- where the ... is chained through, and returned verbatim at
+-- the end.
+-- action can be nil (on error) or else one of:
+-- continue --> call the next hook function if there is one (not chaining ...)
+-- update --> as for 'continue' but chaining the ...
+-- stop --> stop now and return the rest of the results.
+
+-- Wherever Gitano registers a hook for something, the hook priority
+-- of zero will be Gitano's action. So if you want to alter what is
+-- passed to Gitano's default behaviour, register with a negative value
+-- and if you want to just do more afterwards, register with a positive
+-- value
+
+return {
+ add = add_to_hook,
+ run = run_hook,
+}