diff options
author | Daniel Silverstone <daniel.silverstone@codethink.co.uk> | 2017-05-13 13:59:27 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2017-06-17 15:03:28 +0100 |
commit | 3b377ffac94c109a9a8c73412dedf9035f539b0f (patch) | |
tree | e8b3fbe18648430efc0c0d55e2cd7ca025063aed | |
parent | ea637c6dbc4d50239e0d5b7b57b08a724d3bb5e3 (diff) | |
download | gitano-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.lua | 101 |
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, +} |