├── index.js ├── package.json ├── README.md ├── LICENSE └── test └── index.js /index.js: -------------------------------------------------------------------------------- 1 | function wrap (fn, hook) { 2 | return function () { 3 | return hook.call(this, fn, [].slice.call(arguments)) 4 | } 5 | } 6 | 7 | module.exports = function hookable(fn) { 8 | 9 | function hooked () { 10 | return fn.apply(this, [].slice.call(arguments)) 11 | } 12 | 13 | hooked.hook = function (hook) { 14 | fn = wrap(fn, hook) 15 | return this 16 | } 17 | 18 | return hooked 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hoox", 3 | "description": "simplest functional AOP style hook helper", 4 | "version": "0.0.1", 5 | "homepage": "https://github.com/dominictarr/hoox", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/dominictarr/hoox.git" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "tape": "^4.0.0" 13 | }, 14 | "scripts": { 15 | "prepublish": "npm ls && npm test", 16 | "test": "set -e; for t in test/*.js; do node $t; done" 17 | }, 18 | "author": "Dominic Tarr (http://dominictarr.com)", 19 | "license": "MIT" 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hoox 2 | 3 | hook around a function to alter input and output. 4 | 5 | Very simple. only 20 lines. 6 | The example below is longer than the code. 7 | 8 | ## Example 9 | 10 | ``` js 11 | //take an innocent function 12 | function plus (a, b) { 13 | return a + b 14 | } 15 | 16 | //and add hooks to it. 17 | plus = Hoox(plus) 18 | 19 | //now you can control input and output 20 | plus.hook(function (fn, args) { 21 | 22 | var value = fn.apply(null, args.map(Math.round)) 23 | 24 | return Math.max(value, 0) 25 | }) 26 | 27 | console.log(plus(1,3)) 28 | // 4 29 | 30 | console.log(plus(0.8, -5)) 31 | // 0 32 | 33 | console.log(plus(0.9, 0.9)) 34 | // 2 35 | 36 | ``` 37 | 38 | in Aspect Oriented Programming, this function would be called 39 | an _around_ hook. I have not implemented pre, and post hooks yet, 40 | because this is currently sufficent for my purposes. 41 | 42 | ## License 43 | 44 | MIT 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Dominic Tarr 4 | 5 | Permission is hereby granted, free of charge, 6 | to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to 8 | deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom 12 | the Software is furnished to do so, 13 | subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 22 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var tape = require('tape') 4 | var Hoox = require('../') 5 | 6 | function hello (name) { 7 | return 'Hello, '+name+'.' 8 | } 9 | 10 | function post(fn, args) { 11 | var s = fn.apply(this, args) 12 | return s.replace('.', '!!!') 13 | } 14 | 15 | 16 | function pre (fn, args) { 17 | return fn(args[0].toUpperCase()) 18 | } 19 | 20 | //hello = Hoox(hello).hook(pre).hook(post) 21 | console.log(hello('foo')) 22 | 23 | 24 | tape('simple', function (t) { 25 | t.equal(hello('foo'), 'Hello, foo.') 26 | hello2 = Hoox(hello) 27 | t.equal(hello2('foo'), 'Hello, foo.') 28 | hello2.hook(post) 29 | t.equal(hello2('foo'), 'Hello, foo!!!') 30 | 31 | t.equal(Hoox(hello).hook(pre)('foo'), 'Hello, FOO.') 32 | t.equal(Hoox(hello).hook(post).hook(pre)('foo'), 'Hello, FOO!!!') 33 | t.equal(Hoox(hello).hook(pre).hook(post)('foo'), 'Hello, FOO!!!') 34 | 35 | t.end() 36 | }) 37 | 38 | 39 | function async (n, cb) { 40 | cb(null, n + 1) 41 | } 42 | 43 | function alwaysAsync(fn, args) { 44 | var sync = true 45 | fn(args[0], function (err, value) { 46 | if(sync) process.nextTick(function () { 47 | args[1](err, value, false) 48 | }) 49 | else 50 | args[1](err, value, true) 51 | }) 52 | sync = false 53 | } 54 | 55 | function double (fn, args) { 56 | return fn(args[0]*2, args[1]) 57 | } 58 | 59 | function precheck (fn, args) { 60 | setTimeout(function () { 61 | fn.apply(null, args) 62 | }) 63 | } 64 | 65 | tape('callback', function (t) { 66 | var n = 3 67 | 68 | Hoox(async) 69 | (1, function (_, v) { 70 | t.equal(v, 2) 71 | next() 72 | }) 73 | 74 | Hoox(async).hook(alwaysAsync).hook(double) 75 | (3, function (_, v, async) { 76 | t.equal(v, 7) 77 | t.notOk(async) 78 | next() 79 | }) 80 | 81 | Hoox(async).hook(precheck).hook(alwaysAsync) 82 | (7, function (_, v, async) { 83 | t.equal(v, 8) 84 | t.ok(async) 85 | next() 86 | }) 87 | 88 | function next () { 89 | if(--n) return 90 | t.end() 91 | } 92 | }) 93 | 94 | 95 | 96 | tape('left to right, async', function (t) { 97 | var a, b, c 98 | Hoox(async).hook(function (fn, args) { 99 | a = true 100 | fn(args[0], function (_, v) { 101 | t.equal(v, 4) 102 | args[1](_, v * 2) 103 | }) 104 | }) 105 | (3, function (_, v) { 106 | 107 | t.equal(v, 8) 108 | t.end() 109 | }) 110 | 111 | }) 112 | 113 | 114 | tape('check a thing, maybe return something different, else change result', function (t) { 115 | 116 | var h = Hoox(function (a) { 117 | return a * 100 118 | }).hook(function (fn, args) { 119 | var a = args[0] 120 | 121 | if(isNaN(a)) return 0 122 | 123 | return ~~fn(a) 124 | }) 125 | 126 | t.equal(h(1/0), 0) 127 | t.equal(h(0.5), 50) 128 | 129 | t.end() 130 | 131 | }) 132 | --------------------------------------------------------------------------------