From 709c5a3411b6f8e2e9fee6cc5d5726ef0177c6ab Mon Sep 17 00:00:00 2001 From: Sean Massa Date: Fri, 30 Jan 2015 10:44:34 -0600 Subject: [PATCH] allow bond to restore after binding twice to the same property --- .gitignore | 2 ++ bond.coffee | 48 +++++++++++++++++++++++++++++++++++++++++----- lib/bond.js | 54 +++++++++++++++++++++++++++++++++++++++++++--------- package.json | 2 +- test.coffee | 16 ++++++++++++++++ 5 files changed, 107 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 3c3629e..29d6828 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +npm-debug.log + diff --git a/bond.coffee b/bond.coffee index 96b845a..e52b5f1 100644 --- a/bond.coffee +++ b/bond.coffee @@ -71,6 +71,44 @@ nextTick = do -> setTimeout(fn, 0) + + + +_registry = [] +_find = (obj) -> + for store in _registry + if store.obj == obj + return store + + store = + obj: obj + props: {} + _registry.push(store) + store + +registry = + set: (obj, prop, value, newValue) -> + store = _find(obj) + # ignore if it looks like we're + # bonding multiple times + if !store.props[prop]? + store.props[prop] = value + + get: (obj, prop) -> + _find(obj).props[prop] + + restore: (obj, prop) -> + obj[prop] = _find(obj).props[prop] + + restoreAll: -> + for store in _registry + for prop, value of store.props + store.obj[prop] = value + + _registry = [] + + + allStubs = [] registered = false registerCleanupHook = -> @@ -80,9 +118,7 @@ registerCleanupHook = -> throw new Error('bond.cleanup must be specified if your test runner does not use afterEach or testDone') after -> - for stubRestore in allStubs - stubRestore() - allStubs = [] + registry.restoreAll() registered = true @@ -93,9 +129,10 @@ bond = (obj, property) -> previous = obj[property] registerRestore = -> - allStubs.push restore + registry.set obj, property, previous + restore = -> - obj[property] = previous + registry.restore(obj, property) to = (newValue) -> registerRestore() @@ -121,6 +158,7 @@ bond = (obj, property) -> callback(returnValues...) through = -> + registerRestore() obj[property] = createThroughSpy(previous, this) obj[property] diff --git a/lib/bond.js b/lib/bond.js index ed65e36..320bdfb 100644 --- a/lib/bond.js +++ b/lib/bond.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 2.0.0-beta8 void function () { - var allStubs, arrayEqual, bond, createAnonymousSpy, createReturnSpy, createThroughSpy, enhanceSpy, isFunction, nextTick, registerCleanupHook, registered; + var _find, _registry, allStubs, arrayEqual, bond, createAnonymousSpy, createReturnSpy, createThroughSpy, enhanceSpy, isFunction, nextTick, registerCleanupHook, registered, registry; isFunction = function (obj) { return typeof obj === 'function'; }; @@ -87,6 +87,46 @@ void function () { return setTimeout(fn, 0); }; }(); + _registry = []; + _find = function (obj) { + var store; + for (var i$ = 0, length$ = _registry.length; i$ < length$; ++i$) { + store = _registry[i$]; + if (store.obj === obj) + return store; + } + store = { + obj: obj, + props: {} + }; + _registry.push(store); + return store; + }; + registry = { + set: function (obj, prop, value, newValue) { + var store; + store = _find(obj); + if (!(null != store.props[prop])) + return store.props[prop] = value; + }, + get: function (obj, prop) { + return _find(obj).props[prop]; + }, + restore: function (obj, prop) { + return obj[prop] = _find(obj).props[prop]; + }, + restoreAll: function () { + var prop, store, value; + for (var i$ = 0, length$ = _registry.length; i$ < length$; ++i$) { + store = _registry[i$]; + for (prop in store.props) { + value = store.props[prop]; + store.obj[prop] = value; + } + } + return _registry = []; + } + }; allStubs = []; registered = false; registerCleanupHook = function () { @@ -97,12 +137,7 @@ void function () { throw new Error('bond.cleanup must be specified if your test runner does not use afterEach or testDone'); }; after(function () { - var stubRestore; - for (var i$ = 0, length$ = allStubs.length; i$ < length$; ++i$) { - stubRestore = allStubs[i$]; - stubRestore(); - } - return allStubs = []; + return registry.restoreAll(); }); return registered = true; }; @@ -113,10 +148,10 @@ void function () { return createAnonymousSpy(); previous = obj[property]; registerRestore = function () { - return allStubs.push(restore); + return registry.set(obj, property, previous); }; restore = function () { - return obj[property] = previous; + return registry.restore(obj, property); }; to = function (newValue) { registerRestore(); @@ -153,6 +188,7 @@ void function () { }); }; through = function () { + registerRestore(); obj[property] = createThroughSpy(previous, this); return obj[property]; }; diff --git a/package.json b/package.json index 11f23fd..0579837 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "author": "Sean Massa ", "scripts": { "compile": "./node_modules/.bin/coffee --js lib/bond.js", - "test": "./node_modules/.bin/mocha --compilers coffee:coffee-script-redux/register --reporter spec --colors test.coffee" + "test": "npm run compile && ./node_modules/.bin/mocha --compilers coffee:coffee-script-redux/register --reporter spec --colors test.coffee" }, "devDependencies": { "mocha": "~1.6.0", diff --git a/test.coffee b/test.coffee index c79cad0..bb4565f 100644 --- a/test.coffee +++ b/test.coffee @@ -5,6 +5,8 @@ describe 'bond', -> math = PI: Math.PI + zero: 0 + abs: Math.abs add: (a, b) -> @@ -42,6 +44,20 @@ describe 'bond', -> expect api.restore describe 'to', -> + describe 'can replace earlier bound values', -> + # these tests must be run in this specific order; + # do not bond math.zero in any other test + # because a failure here will cause test suite pollution + it 'setup', -> + bond(math, 'zero').to 3.14 + bond(math, 'zero').to 12 + + equal math.zero, 12 + + it 'test', -> + # test that the old replacements have been cleared away + equal math.zero, 0 + describe 'non function values', -> it 'replaces values', -> bond(math, 'PI').to 3.14