From e14ee5b6b592fa971b64ab0eddb882990189c599 Mon Sep 17 00:00:00 2001 From: Kofi Appiah Date: Mon, 17 Nov 2014 11:43:58 -0600 Subject: [PATCH 01/55] exchange cs (for csr) and lodash (for underscore) - also updated other libraries --- Makefile | 17 +- lib/backend.js | 90 ++++++++--- lib/backends/memcached.js | 137 ++++++++++------ lib/backends/memory.js | 144 +++++++++++------ lib/backends/noop.js | 83 +++++++--- lib/cache.js | 323 +++++++++++++++++++++----------------- lib/cached.js | 126 ++++++++++----- package.json | 12 +- src/cache.coffee | 2 +- src/cached.coffee | 2 +- test/cache.coffee | 2 +- test/mocha.opts | 3 + 12 files changed, 596 insertions(+), 345 deletions(-) create mode 100644 test/mocha.opts diff --git a/Makefile b/Makefile index 76a3bc6..7de55b0 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,21 @@ - -SRC = $(shell find src -name "*.coffee" -type f | sort) -LIB = $(SRC:src/%.coffee=lib/%.js) - -COFFEE=node_modules/.bin/coffee --js -MOCHA=node_modules/.bin/mocha --recursive --compilers coffee:coffee-script-redux/register -u tdd --timeout 6000 +COFFEE=node_modules/.bin/coffee +MOCHA=node_modules/.bin/mocha all: clean setup test check-checkout-clean -build: $(LIB) +build: + $(COFFEE) -cbo lib src @./node_modules/.bin/npub prep lib prepublish: ./node_modules/.bin/npub prep -lib/%.js: src/%.coffee - dirname "$@" | xargs mkdir -p - $(COFFEE) <"$<" >"$@" - clean: rm -rf lib rm -rf node_modules test: build - $(MOCHA) -R spec test/*.coffee + $(MOCHA) release: all git push --tags origin HEAD:master diff --git a/lib/backend.js b/lib/backend.js index e8ff473..992c1a4 100644 --- a/lib/backend.js +++ b/lib/backend.js @@ -30,29 +30,67 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Generated by CoffeeScript 2.0.0-beta7 -void function () { - var backend, typeMap; - backend = module.exports = {}; - typeMap = {}; - backend.addType = function (type, klass) { - return typeMap[type] = klass; - }; - backend.create = function (options) { - var klass, type; - if (null != options) - options; - else - options = {}; - if ('function' === typeof options.get && 'function' === typeof options.set) - return options; - type = null != options.type ? options.type : 'noop'; - klass = typeMap[type]; - if (!(null != klass)) - throw new Error('' + type + ' is not a supported cache backend type'); - return new klass(options); - }; - backend.addType('noop', require('./backends/noop')); - backend.addType('memory', require('./backends/memory')); - backend.addType('memcached', require('./backends/memcached')); -}.call(this); +// Generated by CoffeeScript 1.8.0 + +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +var backend, typeMap; + +backend = module.exports = {}; + +typeMap = {}; + +backend.addType = function(type, klass) { + return typeMap[type] = klass; +}; + +backend.create = function(options) { + var klass, type, _ref; + if (options == null) { + options = {}; + } + if ('function' === typeof options.get && 'function' === typeof options.set) { + return options; + } + type = (_ref = options.type) != null ? _ref : 'noop'; + klass = typeMap[type]; + if (klass == null) { + throw new Error("" + type + " is not a supported cache backend type"); + } + return new klass(options); +}; + +backend.addType('noop', require("./backends/noop")); + +backend.addType('memory', require("./backends/memory")); + +backend.addType('memcached', require("./backends/memcached")); diff --git a/lib/backends/memcached.js b/lib/backends/memcached.js index e642b74..5be1b38 100644 --- a/lib/backends/memcached.js +++ b/lib/backends/memcached.js @@ -30,53 +30,96 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Generated by CoffeeScript 2.0.0-beta7 -void function () { - var Memcached, MemcachedBackend; - Memcached = require('memcached'); - MemcachedBackend = function () { - var description; - description = 'Uses anything supporting the memcache protocol'; - function MemcachedBackend(options) { - var hosts; - this.type = 'memcached'; - if (null != options.client) { - this.client = options.client; +// Generated by CoffeeScript 1.8.0 + +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +var Memcached, MemcachedBackend; + +Memcached = require('memcached'); + +MemcachedBackend = (function() { + var description; + + description = "Uses anything supporting the memcache protocol"; + + function MemcachedBackend(options) { + var hosts, _ref; + this.type = 'memcached'; + if (options.client != null) { + this.client = options.client; + } else { + hosts = (_ref = options.hosts) != null ? _ref : '127.0.0.1:11211'; + this.client = new Memcached(hosts, options); + } + } + + MemcachedBackend.prototype.get = function(key, callback) { + return this.client.get(key, function(err, answer) { + if (answer === false) { + answer = null; + } + if (err != null) { + return callback(err); + } else { + return callback(null, answer); + } + }); + }; + + MemcachedBackend.prototype.set = function(key, value, options, callback) { + return this.client.set(key, value, options.expire, function(err, ok) { + if (err != null) { + return callback(err); } else { - hosts = null != options.hosts ? options.hosts : '127.0.0.1:11211'; - this.client = new Memcached(hosts, options); + return callback(null, value); } + }); + }; + + MemcachedBackend.prototype.unset = function(key, callback) { + delete this.cache[key]; + if (callback != null) { + callback(null); } - MemcachedBackend.prototype.get = function (key, callback) { - return this.client.get(key, function (err, answer) { - if (answer === false) - answer = null; - if (null != err) { - return callback(err); - } else { - return callback(null, answer); - } - }); - }; - MemcachedBackend.prototype.set = function (key, value, options, callback) { - return this.client.set(key, value, options.expire, function (err, ok) { - if (null != err) { - return callback(err); - } else { - return callback(null, value); - } - }); - }; - MemcachedBackend.prototype.unset = function (key, callback) { - delete this.cache[key]; - if (null != callback) - callback(null); - return null; - }; - MemcachedBackend.prototype.end = function () { - return this.client.end(); - }; - return MemcachedBackend; - }(); - module.exports = MemcachedBackend; -}.call(this); + return null; + }; + + MemcachedBackend.prototype.end = function() { + return this.client.end(); + }; + + return MemcachedBackend; + +})(); + +module.exports = MemcachedBackend; diff --git a/lib/backends/memory.js b/lib/backends/memory.js index f7f06bc..50001d3 100644 --- a/lib/backends/memory.js +++ b/lib/backends/memory.js @@ -30,53 +30,101 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Generated by CoffeeScript 2.0.0-beta7 -void function () { - var MemoryBackend; - MemoryBackend = function () { - var description; - description = 'Stores everything just in memory'; - function MemoryBackend() { - this.cache = {}; - this.type = 'memory'; - } - MemoryBackend.prototype.get = function (key, callback) { - if (this.isExpired(null != this.cache[key] ? this.cache[key].e : void 0)) - delete this.cache[key]; - if (null != callback) - callback(null, null != (null != this.cache[key] ? this.cache[key].d : void 0) ? null != this.cache[key] ? this.cache[key].d : void 0 : null); - return null; - }; - MemoryBackend.prototype.expiresAt = function (seconds) { - if (seconds === 0) { - return 0; - } else { - return new Date().getTime() + parseInt(seconds) * 1e3; - } - }; - MemoryBackend.prototype.isExpired = function (expires) { - if (!(null != expires)) - return false; - if (expires === 0) - return false; - return new Date().getTime() > new Date(expires).getTime(); - }; - MemoryBackend.prototype.set = function (key, value, options, callback) { - this.cache[key] = { - d: value, - e: this.expiresAt(options.expire) - }; - if (null != callback) - callback(null, value); - return null; - }; - MemoryBackend.prototype.unset = function (key, callback) { +// Generated by CoffeeScript 1.8.0 + +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +var MemoryBackend; + +MemoryBackend = (function() { + var description; + + description = "Stores everything just in memory"; + + function MemoryBackend() { + this.cache = {}; + this.type = 'memory'; + } + + MemoryBackend.prototype.get = function(key, callback) { + var _ref, _ref1, _ref2; + if (this.isExpired((_ref = this.cache[key]) != null ? _ref.e : void 0)) { delete this.cache[key]; - if (null != callback) - callback(null); - return null; + } + if (callback != null) { + callback(null, (_ref1 = (_ref2 = this.cache[key]) != null ? _ref2.d : void 0) != null ? _ref1 : null); + } + return null; + }; + + MemoryBackend.prototype.expiresAt = function(seconds) { + if (seconds === 0) { + return 0; + } else { + return (new Date()).getTime() + (parseInt(seconds) * 1000); + } + }; + + MemoryBackend.prototype.isExpired = function(expires) { + if (expires == null) { + return false; + } + if (expires === 0) { + return false; + } + return (new Date()).getTime() > (new Date(expires)).getTime(); + }; + + MemoryBackend.prototype.set = function(key, value, options, callback) { + this.cache[key] = { + d: value, + e: this.expiresAt(options.expire) }; - return MemoryBackend; - }(); - module.exports = MemoryBackend; -}.call(this); + if (callback != null) { + callback(null, value); + } + return null; + }; + + MemoryBackend.prototype.unset = function(key, callback) { + delete this.cache[key]; + if (callback != null) { + callback(null); + } + return null; + }; + + return MemoryBackend; + +})(); + +module.exports = MemoryBackend; diff --git a/lib/backends/noop.js b/lib/backends/noop.js index c0cbde1..80ad739 100644 --- a/lib/backends/noop.js +++ b/lib/backends/noop.js @@ -30,25 +30,64 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Generated by CoffeeScript 2.0.0-beta7 -void function () { - var NoopBackend; - NoopBackend = function () { - var description; - description = 'Simple backend doing nothing'; - function NoopBackend() { - this.type = 'noop'; - } - NoopBackend.prototype.get = function (key, callback) { - return callback(null, null); - }; - NoopBackend.prototype.set = function (key, value, options, callback) { - return callback(null, value); - }; - NoopBackend.prototype.unset = function (key, callback) { - return callback(null); - }; - return NoopBackend; - }(); - module.exports = NoopBackend; -}.call(this); +// Generated by CoffeeScript 1.8.0 + +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +var NoopBackend; + +NoopBackend = (function() { + var description; + + description = "Simple backend doing nothing"; + + function NoopBackend() { + this.type = 'noop'; + } + + NoopBackend.prototype.get = function(key, callback) { + return callback(null, null); + }; + + NoopBackend.prototype.set = function(key, value, options, callback) { + return callback(null, value); + }; + + NoopBackend.prototype.unset = function(key, callback) { + return callback(null); + }; + + return NoopBackend; + +})(); + +module.exports = NoopBackend; diff --git a/lib/cache.js b/lib/cache.js index 657d7d3..a5f50f1 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -30,153 +30,194 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Generated by CoffeeScript 2.0.0-beta7 -void function () { - var Backend, Cache, expiresAt, extend, isExpired, optionalOpts, Q, toPromise; - extend = require('underscore').extend; - Q = require('q'); - Backend = require('./backend'); - toPromise = function (val) { - if ('function' === typeof val) { - return Q(val()); - } else { - return Q(val); - } +// Generated by CoffeeScript 1.8.0 + +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +var Backend, Cache, Q, expiresAt, extend, isExpired, optionalOpts, toPromise; + +extend = require('lodash').extend; + +Q = require('q'); + +Backend = require('./backend'); + +toPromise = function(val) { + if ('function' === typeof val) { + return Q(val()); + } else { + return Q(val); + } +}; + +expiresAt = function(seconds) { + if (seconds === 0) { + return 0; + } else { + return Date.now() + parseInt(seconds, 10) * 1000; + } +}; + +isExpired = function(expires) { + if (expires === 0) { + return false; + } + return Date.now() > new Date(expires).getTime(); +}; + +optionalOpts = function(opts, cb) { + if ((cb == null) && 'function' === typeof opts) { + return { + cb: opts, + opts: null + }; + } else { + return { + cb: cb, + opts: opts + }; + } +}; + +Cache = (function() { + function Cache(_arg) { + var backend, defaults, name; + backend = _arg.backend, defaults = _arg.defaults, name = _arg.name; + this.defaults = { + freshFor: 0, + expire: 0 + }; + this.name = name || 'default'; + this.prefix = "" + this.name + ":"; + this.staleOrPending = {}; + this.setDefaults(defaults); + this.setBackend(backend); + } + + Cache.prototype.applyPrefix = function(key) { + return "" + this.prefix + key; + }; + + Cache.prototype.setDefaults = function(defaults) { + return this.defaults = this.prepareOptions(defaults); + }; + + Cache.prototype.setBackend = function(backendOptions) { + backendOptions = 'string' === typeof backendOptions ? { + type: backendOptions + } : backendOptions != null ? backendOptions : {}; + this.end(); + return this.backend = Backend.create(backendOptions); }; - expiresAt = function (seconds) { - if (seconds === 0) { - return 0; - } else { - return Date.now() + parseInt(seconds, 10) * 1e3; + + Cache.prototype.end = function() { + var _ref; + if (((_ref = this.backend) != null ? _ref.end : void 0) != null) { + return this.backend.end(); } }; - isExpired = function (expires) { - if (expires === 0) - return false; - return Date.now() > new Date(expires).getTime(); + + Cache.prototype.prepareOptions = function(options) { + return extend({}, this.defaults, options); }; - optionalOpts = function (opts, cb) { - if (!(null != cb) && 'function' === typeof opts) { - return { - cb: opts, - opts: null - }; - } else { - return { - cb: cb, - opts: opts + + Cache.prototype.set = function(key, val, opts, cb) { + var backend, _ref; + _ref = optionalOpts(opts, cb), cb = _ref.cb, opts = _ref.opts; + key = this.applyPrefix(key); + backend = this.backend; + opts = this.prepareOptions(opts); + return toPromise(val).then(function(resolvedValue) { + var wrappedValue; + wrappedValue = { + b: expiresAt(opts.freshFor), + d: resolvedValue }; - } + return Q.npost(backend, 'set', [key, wrappedValue, opts]); + }).nodeify(cb); }; - Cache = function () { - function Cache(param$) { - var backend, cache$, defaults, name; - { - cache$ = param$; - backend = cache$.backend; - defaults = cache$.defaults; - name = cache$.name; - } - this.defaults = { - freshFor: 0, - expire: 0 + + Cache.prototype.getWrapped = function(key) { + return Q.npost(this.backend, 'get', [key]); + }; + + Cache.prototype.get = function(rawKey, cb) { + var key; + key = this.applyPrefix(rawKey); + return this.getWrapped(key).then(function(wrappedValue) { + var _ref; + return (_ref = wrappedValue != null ? wrappedValue.d : void 0) != null ? _ref : null; + }).nodeify(cb); + }; + + Cache.prototype.getOrElse = function(rawKey, val, opts, cb) { + var handleError, key, refreshValue, verifyFreshness, _ref; + key = this.applyPrefix(rawKey); + _ref = optionalOpts(opts, cb), cb = _ref.cb, opts = _ref.opts; + opts = this.prepareOptions(opts); + refreshValue = (function(_this) { + return function() { + var generatedValue; + generatedValue = toPromise(val); + return _this.set(rawKey, generatedValue, opts).then(function(rawValue) { + var _ref1; + delete _this.staleOrPending[key]; + return (_ref1 = rawValue != null ? rawValue.d : void 0) != null ? _ref1 : null; + }, function(err) { + delete _this.staleOrPending[key]; + return generatedValue != null ? generatedValue : null; + }); }; - this.name = name || 'default'; - this.prefix = '' + this.name + ':'; - this.staleOrPending = {}; - this.setDefaults(defaults); - this.setBackend(backend); - } - Cache.prototype.applyPrefix = function (key) { - return '' + this.prefix + key; - }; - Cache.prototype.setDefaults = function (defaults) { - return this.defaults = this.prepareOptions(defaults); - }; - Cache.prototype.setBackend = function (backendOptions) { - backendOptions = 'string' === typeof backendOptions ? { type: backendOptions } : null != backendOptions ? backendOptions : {}; - this.end(); - return this.backend = Backend.create(backendOptions); - }; - Cache.prototype.end = function () { - if (null != (null != this.backend ? this.backend.end : void 0)) - return this.backend.end(); - }; - Cache.prototype.prepareOptions = function (options) { - return extend({}, this.defaults, options); - }; - Cache.prototype.set = function (key, val, opts, cb) { - var backend, cache$; - cache$ = optionalOpts(opts, cb); - cb = cache$.cb; - opts = cache$.opts; - key = this.applyPrefix(key); - backend = this.backend; - opts = this.prepareOptions(opts); - return toPromise(val).then(function (resolvedValue) { - var wrappedValue; - wrappedValue = { - b: expiresAt(opts.freshFor), - d: resolvedValue - }; - return Q.npost(backend, 'set', [ - key, - wrappedValue, - opts - ]); - }).nodeify(cb); - }; - Cache.prototype.getWrapped = function (key) { - return Q.npost(this.backend, 'get', [key]); - }; - Cache.prototype.get = function (rawKey, cb) { - var key; - key = this.applyPrefix(rawKey); - return this.getWrapped(key).then(function (wrappedValue) { - return null != (null != wrappedValue ? wrappedValue.d : void 0) ? null != wrappedValue ? wrappedValue.d : void 0 : null; - }).nodeify(cb); - }; - Cache.prototype.getOrElse = function (rawKey, val, opts, cb) { - var cache$, handleError, key, refreshValue, verifyFreshness; - key = this.applyPrefix(rawKey); - cache$ = optionalOpts(opts, cb); - cb = cache$.cb; - opts = cache$.opts; - opts = this.prepareOptions(opts); - refreshValue = function (this$) { - return function () { - var generatedValue; - generatedValue = toPromise(val); - return this$.set(rawKey, generatedValue, opts).then(function (this$1) { - return function (rawValue) { - delete this$1.staleOrPending[key]; - return null != (null != rawValue ? rawValue.d : void 0) ? null != rawValue ? rawValue.d : void 0 : null; - }; - }(this$), function (this$1) { - return function (err) { - delete this$1.staleOrPending[key]; - return null != generatedValue ? generatedValue : null; - }; - }(this$)); - }; - }(this); - verifyFreshness = function (this$) { - return function (wrappedValue) { - var expired, hit, loadingNewValue; - hit = null != wrappedValue; - expired = isExpired(null != wrappedValue ? wrappedValue.b : void 0); - loadingNewValue = null != this$.staleOrPending[key]; - if ((!hit || expired) && !loadingNewValue) - this$.staleOrPending[key] = refreshValue(); - return null != (null != wrappedValue ? wrappedValue.d : void 0) ? null != wrappedValue ? wrappedValue.d : void 0 : this$.staleOrPending[key]; - }; - }(this); - handleError = function (error) { - return null; + })(this); + verifyFreshness = (function(_this) { + return function(wrappedValue) { + var expired, hit, loadingNewValue, _ref1; + hit = wrappedValue != null; + expired = isExpired(wrappedValue != null ? wrappedValue.b : void 0); + loadingNewValue = _this.staleOrPending[key] != null; + if ((!hit || expired) && !loadingNewValue) { + _this.staleOrPending[key] = refreshValue(); + } + return (_ref1 = wrappedValue != null ? wrappedValue.d : void 0) != null ? _ref1 : _this.staleOrPending[key]; }; - return this.getWrapped(key)['catch'](handleError).then(verifyFreshness).nodeify(cb); + })(this); + handleError = function(error) { + return null; }; - return Cache; - }(); - module.exports = Cache; -}.call(this); + return this.getWrapped(key)["catch"](handleError).then(verifyFreshness).nodeify(cb); + }; + + return Cache; + +})(); + +module.exports = Cache; diff --git a/lib/cached.js b/lib/cached.js index 9db958e..84badb5 100644 --- a/lib/cached.js +++ b/lib/cached.js @@ -30,46 +30,92 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Generated by CoffeeScript 2.0.0-beta7 -void function () { - var Cache, cached, extend, namedCaches, Q; - try { - Q = require('../node_modules/q'); - Q.stopUnhandledRejectionTracking(); - } catch (e$) { - Q = require('q'); +// Generated by CoffeeScript 1.8.0 + +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +var Cache, Q, cached, extend, namedCaches; + +try { + Q = require('../node_modules/q'); + Q.stopUnhandledRejectionTracking(); +} catch (_error) { + Q = require('q'); +} + +Cache = require('./cache'); + +extend = require('lodash').extend; + +namedCaches = {}; + +cached = function(name, options) { + if (name == null) { + name = "default"; + } + if (options == null) { + options = {}; } - Cache = require('./cache'); - extend = require('underscore').extend; + options = extend({ + name: name + }, options); + return namedCaches[name] != null ? namedCaches[name] : namedCaches[name] = cached.createCache(options); +}; + +cached.createCache = function(options) { + if (options == null) { + options = {}; + } + return new Cache(options); +}; + +cached.dropNamedCaches = function() { namedCaches = {}; - cached = function (name, options) { - if (null == name) - name = 'default'; - if (null == options) - options = {}; - options = extend({ name: name }, options); - return null != namedCaches[name] ? namedCaches[name] : namedCaches[name] = cached.createCache(options); - }; - cached.createCache = function (options) { - if (null == options) - options = {}; - return new Cache(options); - }; - cached.dropNamedCaches = function () { - namedCaches = {}; - return cached; - }; - cached.dropNamedCache = function (name) { - delete namedCaches[name]; - return cached; - }; - cached.knownCaches = function () { - return Object.keys(namedCaches); - }; - cached.deferred = function (fn) { - return function () { - return Q.nfcall(fn); - }; + return cached; +}; + +cached.dropNamedCache = function(name) { + delete namedCaches[name]; + return cached; +}; + +cached.knownCaches = function() { + return Object.keys(namedCaches); +}; + +cached.deferred = function(fn) { + return function() { + return Q.nfcall(fn); }; - module.exports = cached; -}.call(this); +}; + +module.exports = cached; diff --git a/package.json b/package.json index 3eae46c..72b7490 100644 --- a/package.json +++ b/package.json @@ -28,15 +28,15 @@ } }, "dependencies": { - "underscore": "~1.4.4", - "q": "~0.9.7", - "memcached": "2.0.0" + "lodash": "^2.4.1", + "memcached": "^2.0.0", + "q": "~0.9.7" }, "devDependencies": { - "bondjs": "~1.0.0", - "coffee-script-redux": "2.0.0-beta7", + "bondjs": "^1.0.0", + "coffee-script": "^1.8.0", "expect.js": "0.2.0", - "mocha": "1.7.4", + "mocha": "^2.0.1", "npub": "0.0.5" } } diff --git a/src/cache.coffee b/src/cache.coffee index 4740166..44c8dd6 100644 --- a/src/cache.coffee +++ b/src/cache.coffee @@ -30,7 +30,7 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### -{extend} = require 'underscore' +{extend} = require 'lodash' Q = require 'q' Backend = require './backend' diff --git a/src/cached.coffee b/src/cached.coffee index 7fcb5ae..98688e8 100644 --- a/src/cached.coffee +++ b/src/cached.coffee @@ -39,7 +39,7 @@ catch Cache = require './cache' -{extend} = require 'underscore' +{extend} = require 'lodash' namedCaches = {} diff --git a/test/cache.coffee b/test/cache.coffee index 27aad6a..bf119c8 100644 --- a/test/cache.coffee +++ b/test/cache.coffee @@ -3,7 +3,7 @@ expect = require 'expect.js' bond = require 'bondjs' Q = require 'q' -{defaults} = require 'underscore' +{defaults} = require 'lodash' Cache = require '../lib/cache' cached = require '../lib/cached' diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 0000000..ee852df --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,3 @@ +--recursive +--compilers coffee:coffee-script/register +--timeout 6000 From 5b8a95e954759e7cc59be7aa75cb6737dd40d454 Mon Sep 17 00:00:00 2001 From: Kofi Appiah Date: Mon, 17 Nov 2014 12:03:58 -0600 Subject: [PATCH 02/55] make node 0.8 compat - '^' -> '~' --- npm-debug.log | 690 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 10 +- 2 files changed, 695 insertions(+), 5 deletions(-) create mode 100644 npm-debug.log diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 0000000..85d896e --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,690 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/usr/local/opt/nvm/v0.10.33/bin/node', +1 verbose cli '/usr/local/opt/nvm/v0.10.33/bin/npm', +1 verbose cli 'install' ] +2 info using npm@1.4.28 +3 info using node@v0.10.33 +4 verbose node symlink /usr/local/opt/nvm/v0.10.33/bin/node +5 verbose readDependencies using package.json deps +6 verbose install where, deps [ '/Users/kofi/thePoints/node-cached', +6 verbose install [ 'lodash', +6 verbose install 'memcached', +6 verbose install 'q', +6 verbose install 'bondjs', +6 verbose install 'coffee-script', +6 verbose install 'expect.js', +6 verbose install 'mocha', +6 verbose install 'npub' ] ] +7 info preinstall cached@3.0.0 +8 verbose readDependencies using package.json deps +9 verbose cache add [ 'lodash@~2.4.1', null ] +10 verbose cache add name=undefined spec="lodash@~2.4.1" args=["lodash@~2.4.1",null] +11 verbose parsed url { protocol: null, +11 verbose parsed url slashes: null, +11 verbose parsed url auth: null, +11 verbose parsed url host: null, +11 verbose parsed url port: null, +11 verbose parsed url hostname: null, +11 verbose parsed url hash: null, +11 verbose parsed url search: null, +11 verbose parsed url query: null, +11 verbose parsed url pathname: 'lodash@~2.4.1', +11 verbose parsed url path: 'lodash@~2.4.1', +11 verbose parsed url href: 'lodash@~2.4.1' } +12 verbose cache add [ 'memcached@~2.0.0', null ] +13 verbose cache add name=undefined spec="memcached@~2.0.0" args=["memcached@~2.0.0",null] +14 verbose parsed url { protocol: null, +14 verbose parsed url slashes: null, +14 verbose parsed url auth: null, +14 verbose parsed url host: null, +14 verbose parsed url port: null, +14 verbose parsed url hostname: null, +14 verbose parsed url hash: null, +14 verbose parsed url search: null, +14 verbose parsed url query: null, +14 verbose parsed url pathname: 'memcached@~2.0.0', +14 verbose parsed url path: 'memcached@~2.0.0', +14 verbose parsed url href: 'memcached@~2.0.0' } +15 verbose cache add [ 'q@~0.9.7', null ] +16 verbose cache add name=undefined spec="q@~0.9.7" args=["q@~0.9.7",null] +17 verbose parsed url { protocol: null, +17 verbose parsed url slashes: null, +17 verbose parsed url auth: null, +17 verbose parsed url host: null, +17 verbose parsed url port: null, +17 verbose parsed url hostname: null, +17 verbose parsed url hash: null, +17 verbose parsed url search: null, +17 verbose parsed url query: null, +17 verbose parsed url pathname: 'q@~0.9.7', +17 verbose parsed url path: 'q@~0.9.7', +17 verbose parsed url href: 'q@~0.9.7' } +18 verbose cache add [ 'bondjs@~1.0.0', null ] +19 verbose cache add name=undefined spec="bondjs@~1.0.0" args=["bondjs@~1.0.0",null] +20 verbose parsed url { protocol: null, +20 verbose parsed url slashes: null, +20 verbose parsed url auth: null, +20 verbose parsed url host: null, +20 verbose parsed url port: null, +20 verbose parsed url hostname: null, +20 verbose parsed url hash: null, +20 verbose parsed url search: null, +20 verbose parsed url query: null, +20 verbose parsed url pathname: 'bondjs@~1.0.0', +20 verbose parsed url path: 'bondjs@~1.0.0', +20 verbose parsed url href: 'bondjs@~1.0.0' } +21 verbose cache add name="lodash" spec="~2.4.1" args=["lodash","~2.4.1"] +22 verbose parsed url { protocol: null, +22 verbose parsed url slashes: null, +22 verbose parsed url auth: null, +22 verbose parsed url host: null, +22 verbose parsed url port: null, +22 verbose parsed url hostname: null, +22 verbose parsed url hash: null, +22 verbose parsed url search: null, +22 verbose parsed url query: null, +22 verbose parsed url pathname: '~2.4.1', +22 verbose parsed url path: '~2.4.1', +22 verbose parsed url href: '~2.4.1' } +23 verbose addNamed [ 'lodash', '~2.4.1' ] +24 verbose addNamed [ null, '>=2.4.1-0 <2.5.0-0' ] +25 verbose cache add name="memcached" spec="~2.0.0" args=["memcached","~2.0.0"] +26 verbose parsed url { protocol: null, +26 verbose parsed url slashes: null, +26 verbose parsed url auth: null, +26 verbose parsed url host: null, +26 verbose parsed url port: null, +26 verbose parsed url hostname: null, +26 verbose parsed url hash: null, +26 verbose parsed url search: null, +26 verbose parsed url query: null, +26 verbose parsed url pathname: '~2.0.0', +26 verbose parsed url path: '~2.0.0', +26 verbose parsed url href: '~2.0.0' } +27 verbose addNamed [ 'memcached', '~2.0.0' ] +28 verbose addNamed [ null, '>=2.0.0-0 <2.1.0-0' ] +29 verbose cache add name="q" spec="~0.9.7" args=["q","~0.9.7"] +30 verbose parsed url { protocol: null, +30 verbose parsed url slashes: null, +30 verbose parsed url auth: null, +30 verbose parsed url host: null, +30 verbose parsed url port: null, +30 verbose parsed url hostname: null, +30 verbose parsed url hash: null, +30 verbose parsed url search: null, +30 verbose parsed url query: null, +30 verbose parsed url pathname: '~0.9.7', +30 verbose parsed url path: '~0.9.7', +30 verbose parsed url href: '~0.9.7' } +31 verbose addNamed [ 'q', '~0.9.7' ] +32 verbose addNamed [ null, '>=0.9.7-0 <0.10.0-0' ] +33 verbose cache add name="bondjs" spec="~1.0.0" args=["bondjs","~1.0.0"] +34 verbose parsed url { protocol: null, +34 verbose parsed url slashes: null, +34 verbose parsed url auth: null, +34 verbose parsed url host: null, +34 verbose parsed url port: null, +34 verbose parsed url hostname: null, +34 verbose parsed url hash: null, +34 verbose parsed url search: null, +34 verbose parsed url query: null, +34 verbose parsed url pathname: '~1.0.0', +34 verbose parsed url path: '~1.0.0', +34 verbose parsed url href: '~1.0.0' } +35 verbose addNamed [ 'bondjs', '~1.0.0' ] +36 verbose addNamed [ null, '>=1.0.0-0 <1.1.0-0' ] +37 verbose cache add [ 'coffee-script@~1.8.0', null ] +38 verbose cache add name=undefined spec="coffee-script@~1.8.0" args=["coffee-script@~1.8.0",null] +39 verbose parsed url { protocol: null, +39 verbose parsed url slashes: null, +39 verbose parsed url auth: null, +39 verbose parsed url host: null, +39 verbose parsed url port: null, +39 verbose parsed url hostname: null, +39 verbose parsed url hash: null, +39 verbose parsed url search: null, +39 verbose parsed url query: null, +39 verbose parsed url pathname: 'coffee-script@~1.8.0', +39 verbose parsed url path: 'coffee-script@~1.8.0', +39 verbose parsed url href: 'coffee-script@~1.8.0' } +40 verbose cache add [ 'expect.js@0.2.0', null ] +41 verbose cache add name=undefined spec="expect.js@0.2.0" args=["expect.js@0.2.0",null] +42 verbose parsed url { protocol: null, +42 verbose parsed url slashes: null, +42 verbose parsed url auth: null, +42 verbose parsed url host: null, +42 verbose parsed url port: null, +42 verbose parsed url hostname: null, +42 verbose parsed url hash: null, +42 verbose parsed url search: null, +42 verbose parsed url query: null, +42 verbose parsed url pathname: 'expect.js@0.2.0', +42 verbose parsed url path: 'expect.js@0.2.0', +42 verbose parsed url href: 'expect.js@0.2.0' } +43 verbose cache add [ 'mocha@^~2.0.1', null ] +44 verbose cache add name=undefined spec="mocha@^~2.0.1" args=["mocha@^~2.0.1",null] +45 verbose parsed url { protocol: null, +45 verbose parsed url slashes: null, +45 verbose parsed url auth: null, +45 verbose parsed url host: null, +45 verbose parsed url port: null, +45 verbose parsed url hostname: null, +45 verbose parsed url hash: null, +45 verbose parsed url search: null, +45 verbose parsed url query: null, +45 verbose parsed url pathname: 'mocha@^~2.0.1', +45 verbose parsed url path: 'mocha@^~2.0.1', +45 verbose parsed url href: 'mocha@^~2.0.1' } +46 silly lockFile 257f9ab3-lodash-2-4-1 lodash@~2.4.1 +47 verbose lock lodash@~2.4.1 /Users/kofi/.npm/257f9ab3-lodash-2-4-1.lock +48 silly lockFile dfc8f739-memcached-2-0-0 memcached@~2.0.0 +49 verbose lock memcached@~2.0.0 /Users/kofi/.npm/dfc8f739-memcached-2-0-0.lock +50 silly lockFile 9ea2316a-q-0-9-7 q@~0.9.7 +51 verbose lock q@~0.9.7 /Users/kofi/.npm/9ea2316a-q-0-9-7.lock +52 silly lockFile 4ea17dfe-bondjs-1-0-0 bondjs@~1.0.0 +53 verbose lock bondjs@~1.0.0 /Users/kofi/.npm/4ea17dfe-bondjs-1-0-0.lock +54 verbose cache add name="coffee-script" spec="~1.8.0" args=["coffee-script","~1.8.0"] +55 verbose parsed url { protocol: null, +55 verbose parsed url slashes: null, +55 verbose parsed url auth: null, +55 verbose parsed url host: null, +55 verbose parsed url port: null, +55 verbose parsed url hostname: null, +55 verbose parsed url hash: null, +55 verbose parsed url search: null, +55 verbose parsed url query: null, +55 verbose parsed url pathname: '~1.8.0', +55 verbose parsed url path: '~1.8.0', +55 verbose parsed url href: '~1.8.0' } +56 verbose addNamed [ 'coffee-script', '~1.8.0' ] +57 verbose addNamed [ null, '>=1.8.0-0 <1.9.0-0' ] +58 silly lockFile f37fc738-coffee-script-1-8-0 coffee-script@~1.8.0 +59 verbose lock coffee-script@~1.8.0 /Users/kofi/.npm/f37fc738-coffee-script-1-8-0.lock +60 verbose cache add name="expect.js" spec="0.2.0" args=["expect.js","0.2.0"] +61 verbose parsed url { protocol: null, +61 verbose parsed url slashes: null, +61 verbose parsed url auth: null, +61 verbose parsed url host: null, +61 verbose parsed url port: null, +61 verbose parsed url hostname: null, +61 verbose parsed url hash: null, +61 verbose parsed url search: null, +61 verbose parsed url query: null, +61 verbose parsed url pathname: '0.2.0', +61 verbose parsed url path: '0.2.0', +61 verbose parsed url href: '0.2.0' } +62 verbose addNamed [ 'expect.js', '0.2.0' ] +63 verbose addNamed [ '0.2.0', '0.2.0' ] +64 silly lockFile 8bd15c82-expect-js-0-2-0 expect.js@0.2.0 +65 verbose lock expect.js@0.2.0 /Users/kofi/.npm/8bd15c82-expect-js-0-2-0.lock +66 verbose cache add [ 'npub@0.0.5', null ] +67 verbose cache add name=undefined spec="npub@0.0.5" args=["npub@0.0.5",null] +68 verbose parsed url { protocol: null, +68 verbose parsed url slashes: null, +68 verbose parsed url auth: null, +68 verbose parsed url host: null, +68 verbose parsed url port: null, +68 verbose parsed url hostname: null, +68 verbose parsed url hash: null, +68 verbose parsed url search: null, +68 verbose parsed url query: null, +68 verbose parsed url pathname: 'npub@0.0.5', +68 verbose parsed url path: 'npub@0.0.5', +68 verbose parsed url href: 'npub@0.0.5' } +69 verbose cache add name="mocha" spec="^~2.0.1" args=["mocha","^~2.0.1"] +70 verbose parsed url { protocol: null, +70 verbose parsed url slashes: null, +70 verbose parsed url auth: null, +70 verbose parsed url host: null, +70 verbose parsed url port: null, +70 verbose parsed url hostname: null, +70 verbose parsed url hash: null, +70 verbose parsed url search: null, +70 verbose parsed url query: null, +70 verbose parsed url pathname: '^~2.0.1', +70 verbose parsed url path: '^~2.0.1', +70 verbose parsed url href: '^~2.0.1' } +71 verbose addNamed [ 'mocha', '^~2.0.1' ] +72 verbose addNamed [ null, null ] +73 silly lockFile b9e888b2-mocha-2-0-1 mocha@^~2.0.1 +74 verbose lock mocha@^~2.0.1 /Users/kofi/.npm/b9e888b2-mocha-2-0-1.lock +75 verbose cache add name="npub" spec="0.0.5" args=["npub","0.0.5"] +76 verbose parsed url { protocol: null, +76 verbose parsed url slashes: null, +76 verbose parsed url auth: null, +76 verbose parsed url host: null, +76 verbose parsed url port: null, +76 verbose parsed url hostname: null, +76 verbose parsed url hash: null, +76 verbose parsed url search: null, +76 verbose parsed url query: null, +76 verbose parsed url pathname: '0.0.5', +76 verbose parsed url path: '0.0.5', +76 verbose parsed url href: '0.0.5' } +77 verbose addNamed [ 'npub', '0.0.5' ] +78 verbose addNamed [ '0.0.5', '0.0.5' ] +79 silly lockFile 6aafaa92-npub-0-0-5 npub@0.0.5 +80 verbose lock npub@0.0.5 /Users/kofi/.npm/6aafaa92-npub-0-0-5.lock +81 silly addNameRange { name: 'lodash', range: '>=2.4.1-0 <2.5.0-0', hasData: false } +82 silly addNameRange { name: 'memcached', +82 silly addNameRange range: '>=2.0.0-0 <2.1.0-0', +82 silly addNameRange hasData: false } +83 silly addNameRange { name: 'q', range: '>=0.9.7-0 <0.10.0-0', hasData: false } +84 silly addNameRange { name: 'bondjs', range: '>=1.0.0-0 <1.1.0-0', hasData: false } +85 silly addNameRange { name: 'coffee-script', +85 silly addNameRange range: '>=1.8.0-0 <1.9.0-0', +85 silly addNameRange hasData: false } +86 info addNameTag [ 'mocha', '^~2.0.1' ] +87 verbose request where is /lodash +88 verbose request registry http://npm-registry.snc1/ +89 verbose request id c6cf32ce3214a251 +90 verbose url raw /lodash +91 verbose url resolving [ 'http://npm-registry.snc1/', './lodash' ] +92 verbose url resolved http://npm-registry.snc1/lodash +93 verbose request where is http://npm-registry.snc1/lodash +94 info trying registry request attempt 1 at 12:03:34 +95 http GET http://npm-registry.snc1/lodash +96 verbose request where is /memcached +97 verbose request registry http://npm-registry.snc1/ +98 verbose url raw /memcached +99 verbose url resolving [ 'http://npm-registry.snc1/', './memcached' ] +100 verbose url resolved http://npm-registry.snc1/memcached +101 verbose request where is http://npm-registry.snc1/memcached +102 info trying registry request attempt 1 at 12:03:34 +103 http GET http://npm-registry.snc1/memcached +104 verbose request where is /q +105 verbose request registry http://npm-registry.snc1/ +106 verbose url raw /q +107 verbose url resolving [ 'http://npm-registry.snc1/', './q' ] +108 verbose url resolved http://npm-registry.snc1/q +109 verbose request where is http://npm-registry.snc1/q +110 info trying registry request attempt 1 at 12:03:34 +111 http GET http://npm-registry.snc1/q +112 verbose request where is /bondjs +113 verbose request registry http://npm-registry.snc1/ +114 verbose url raw /bondjs +115 verbose url resolving [ 'http://npm-registry.snc1/', './bondjs' ] +116 verbose url resolved http://npm-registry.snc1/bondjs +117 verbose request where is http://npm-registry.snc1/bondjs +118 info trying registry request attempt 1 at 12:03:34 +119 http GET http://npm-registry.snc1/bondjs +120 verbose request where is /coffee-script +121 verbose request registry http://npm-registry.snc1/ +122 verbose url raw /coffee-script +123 verbose url resolving [ 'http://npm-registry.snc1/', './coffee-script' ] +124 verbose url resolved http://npm-registry.snc1/coffee-script +125 verbose request where is http://npm-registry.snc1/coffee-script +126 info trying registry request attempt 1 at 12:03:34 +127 http GET http://npm-registry.snc1/coffee-script +128 verbose request where is /expect.js +129 verbose request registry http://npm-registry.snc1/ +130 verbose url raw /expect.js +131 verbose url resolving [ 'http://npm-registry.snc1/', './expect.js' ] +132 verbose url resolved http://npm-registry.snc1/expect.js +133 verbose request where is http://npm-registry.snc1/expect.js +134 info trying registry request attempt 1 at 12:03:34 +135 http GET http://npm-registry.snc1/expect.js +136 verbose request where is /mocha +137 verbose request registry http://npm-registry.snc1/ +138 verbose url raw /mocha +139 verbose url resolving [ 'http://npm-registry.snc1/', './mocha' ] +140 verbose url resolved http://npm-registry.snc1/mocha +141 verbose request where is http://npm-registry.snc1/mocha +142 info trying registry request attempt 1 at 12:03:34 +143 http GET http://npm-registry.snc1/mocha +144 verbose request where is /npub +145 verbose request registry http://npm-registry.snc1/ +146 verbose url raw /npub +147 verbose url resolving [ 'http://npm-registry.snc1/', './npub' ] +148 verbose url resolved http://npm-registry.snc1/npub +149 verbose request where is http://npm-registry.snc1/npub +150 info trying registry request attempt 1 at 12:03:34 +151 http GET http://npm-registry.snc1/npub +152 http 200 http://npm-registry.snc1/bondjs +153 silly registry.get cb [ 200, +153 silly registry.get { server: 'nginx/1.5.12', +153 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +153 silly registry.get 'content-type': 'application/json', +153 silly registry.get 'transfer-encoding': 'chunked', +153 silly registry.get connection: 'keep-alive', +153 silly registry.get vary: 'Accept', +153 silly registry.get 'content-encoding': 'gzip' } ] +154 http 200 http://npm-registry.snc1/coffee-script +155 silly registry.get cb [ 200, +155 silly registry.get { server: 'nginx/1.5.12', +155 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +155 silly registry.get 'content-type': 'application/json', +155 silly registry.get 'transfer-encoding': 'chunked', +155 silly registry.get connection: 'keep-alive', +155 silly registry.get vary: 'Accept', +155 silly registry.get 'content-encoding': 'gzip' } ] +156 silly addNameRange number 2 { name: 'bondjs', range: '>=1.0.0-0 <1.1.0-0', hasData: true } +157 silly addNameRange versions [ 'bondjs', +157 silly addNameRange [ '0.0.1', +157 silly addNameRange '0.0.2', +157 silly addNameRange '0.0.3', +157 silly addNameRange '0.0.4', +157 silly addNameRange '0.0.5', +157 silly addNameRange '0.0.6', +157 silly addNameRange '0.0.7', +157 silly addNameRange '0.0.8', +157 silly addNameRange '0.0.9', +157 silly addNameRange '0.0.10', +157 silly addNameRange '0.0.11', +157 silly addNameRange '0.0.13', +157 silly addNameRange '0.0.14', +157 silly addNameRange '1.0.0', +157 silly addNameRange '1.0.1', +157 silly addNameRange '1.1.0', +157 silly addNameRange '1.1.1', +157 silly addNameRange '1.2.0', +157 silly addNameRange '1.2.1' ] ] +158 verbose addNamed [ 'bondjs', '1.0.1' ] +159 verbose addNamed [ '1.0.1', '1.0.1' ] +160 silly lockFile ca3ccbeb-bondjs-1-0-1 bondjs@1.0.1 +161 verbose lock bondjs@1.0.1 /Users/kofi/.npm/ca3ccbeb-bondjs-1-0-1.lock +162 silly addNameRange number 2 { name: 'coffee-script', +162 silly addNameRange range: '>=1.8.0-0 <1.9.0-0', +162 silly addNameRange hasData: true } +163 silly addNameRange versions [ 'coffee-script', +163 silly addNameRange [ '0.7.1', +163 silly addNameRange '0.7.2', +163 silly addNameRange '0.9.0', +163 silly addNameRange '0.9.1', +163 silly addNameRange '0.9.2', +163 silly addNameRange '0.9.3', +163 silly addNameRange '0.9.4', +163 silly addNameRange '0.9.5', +163 silly addNameRange '0.9.6', +163 silly addNameRange '1.0.0', +163 silly addNameRange '1.1.0', +163 silly addNameRange '1.1.1', +163 silly addNameRange '1.1.2', +163 silly addNameRange '1.1.3', +163 silly addNameRange '1.2.0', +163 silly addNameRange '1.3.0', +163 silly addNameRange '1.3.1', +163 silly addNameRange '1.3.2', +163 silly addNameRange '1.3.3', +163 silly addNameRange '1.4.0', +163 silly addNameRange '1.5.0', +163 silly addNameRange '1.6.0', +163 silly addNameRange '1.6.1', +163 silly addNameRange '1.6.2', +163 silly addNameRange '1.6.3', +163 silly addNameRange '1.7.0', +163 silly addNameRange '1.7.1', +163 silly addNameRange '0.7.0', +163 silly addNameRange '1.8.0', +163 silly addNameRange '1.0.1' ] ] +164 verbose addNamed [ 'coffee-script', '1.8.0' ] +165 verbose addNamed [ '1.8.0', '1.8.0' ] +166 silly lockFile d0d79082-coffee-script-1-8-0 coffee-script@1.8.0 +167 verbose lock coffee-script@1.8.0 /Users/kofi/.npm/d0d79082-coffee-script-1-8-0.lock +168 silly lockFile ca3ccbeb-bondjs-1-0-1 bondjs@1.0.1 +169 silly lockFile ca3ccbeb-bondjs-1-0-1 bondjs@1.0.1 +170 silly lockFile 4ea17dfe-bondjs-1-0-0 bondjs@~1.0.0 +171 silly lockFile 4ea17dfe-bondjs-1-0-0 bondjs@~1.0.0 +172 silly lockFile d0d79082-coffee-script-1-8-0 coffee-script@1.8.0 +173 silly lockFile d0d79082-coffee-script-1-8-0 coffee-script@1.8.0 +174 silly lockFile f37fc738-coffee-script-1-8-0 coffee-script@~1.8.0 +175 silly lockFile f37fc738-coffee-script-1-8-0 coffee-script@~1.8.0 +176 http 200 http://npm-registry.snc1/memcached +177 silly registry.get cb [ 200, +177 silly registry.get { server: 'nginx/1.5.12', +177 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +177 silly registry.get 'content-type': 'application/json', +177 silly registry.get 'transfer-encoding': 'chunked', +177 silly registry.get connection: 'keep-alive', +177 silly registry.get vary: 'Accept', +177 silly registry.get 'content-encoding': 'gzip' } ] +178 silly addNameRange number 2 { name: 'memcached', range: '>=2.0.0-0 <2.1.0-0', hasData: true } +179 silly addNameRange versions [ 'memcached', +179 silly addNameRange [ '0.0.1', +179 silly addNameRange '0.0.2', +179 silly addNameRange '0.0.3', +179 silly addNameRange '0.0.4', +179 silly addNameRange '0.0.5', +179 silly addNameRange '0.1.0', +179 silly addNameRange '0.1.1', +179 silly addNameRange '0.1.2', +179 silly addNameRange '0.1.3', +179 silly addNameRange '0.1.4', +179 silly addNameRange '0.1.5', +179 silly addNameRange '0.2.0', +179 silly addNameRange '0.0.7', +179 silly addNameRange '0.0.6', +179 silly addNameRange '0.0.8', +179 silly addNameRange '0.0.9', +179 silly addNameRange '0.0.10', +179 silly addNameRange '0.0.11', +179 silly addNameRange '0.0.12', +179 silly addNameRange '0.2.1', +179 silly addNameRange '0.2.2', +179 silly addNameRange '0.2.3', +179 silly addNameRange '0.2.4', +179 silly addNameRange '0.2.5', +179 silly addNameRange '0.2.6', +179 silly addNameRange '0.2.7', +179 silly addNameRange '0.2.8', +179 silly addNameRange '1.0.0', +179 silly addNameRange '2.0.0' ] ] +180 verbose addNamed [ 'memcached', '2.0.0' ] +181 verbose addNamed [ '2.0.0', '2.0.0' ] +182 silly lockFile 7114931d-memcached-2-0-0 memcached@2.0.0 +183 verbose lock memcached@2.0.0 /Users/kofi/.npm/7114931d-memcached-2-0-0.lock +184 silly lockFile 7114931d-memcached-2-0-0 memcached@2.0.0 +185 silly lockFile 7114931d-memcached-2-0-0 memcached@2.0.0 +186 silly lockFile dfc8f739-memcached-2-0-0 memcached@~2.0.0 +187 silly lockFile dfc8f739-memcached-2-0-0 memcached@~2.0.0 +188 http 200 http://npm-registry.snc1/lodash +189 silly registry.get cb [ 200, +189 silly registry.get { server: 'nginx/1.5.12', +189 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +189 silly registry.get 'content-type': 'application/json', +189 silly registry.get 'transfer-encoding': 'chunked', +189 silly registry.get connection: 'keep-alive', +189 silly registry.get vary: 'Accept', +189 silly registry.get 'content-encoding': 'gzip' } ] +190 http 200 http://npm-registry.snc1/npub +191 silly registry.get cb [ 200, +191 silly registry.get { server: 'nginx/1.5.12', +191 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +191 silly registry.get 'content-type': 'application/json', +191 silly registry.get 'transfer-encoding': 'chunked', +191 silly registry.get connection: 'keep-alive', +191 silly registry.get vary: 'Accept', +191 silly registry.get 'content-encoding': 'gzip' } ] +192 http 200 http://npm-registry.snc1/expect.js +193 silly registry.get cb [ 200, +193 silly registry.get { server: 'nginx/1.5.12', +193 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +193 silly registry.get 'content-type': 'application/json', +193 silly registry.get 'transfer-encoding': 'chunked', +193 silly registry.get connection: 'keep-alive', +193 silly registry.get vary: 'Accept', +193 silly registry.get 'content-encoding': 'gzip' } ] +194 silly lockFile 4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz http://npm-registry.snc1/package/npub-0.0.5.tgz +195 verbose lock http://npm-registry.snc1/package/npub-0.0.5.tgz /Users/kofi/.npm/4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz.lock +196 silly lockFile 9efb77d3-snc1-package-expect-js-0-2-0-tgz http://npm-registry.snc1/package/expect.js-0.2.0.tgz +197 verbose lock http://npm-registry.snc1/package/expect.js-0.2.0.tgz /Users/kofi/.npm/9efb77d3-snc1-package-expect-js-0-2-0-tgz.lock +198 silly addNameRange number 2 { name: 'lodash', range: '>=2.4.1-0 <2.5.0-0', hasData: true } +199 silly addNameRange versions [ 'lodash', +199 silly addNameRange [ '0.1.0', +199 silly addNameRange '0.2.0', +199 silly addNameRange '0.2.1', +199 silly addNameRange '0.2.2', +199 silly addNameRange '0.3.0', +199 silly addNameRange '0.3.1', +199 silly addNameRange '0.3.2', +199 silly addNameRange '0.4.0', +199 silly addNameRange '0.4.1', +199 silly addNameRange '0.4.2', +199 silly addNameRange '0.5.0-rc.1', +199 silly addNameRange '0.5.0', +199 silly addNameRange '0.5.1', +199 silly addNameRange '0.5.2', +199 silly addNameRange '0.6.0', +199 silly addNameRange '0.7.0', +199 silly addNameRange '0.8.0', +199 silly addNameRange '0.8.1', +199 silly addNameRange '0.8.2', +199 silly addNameRange '0.9.0', +199 silly addNameRange '0.9.2', +199 silly addNameRange '0.10.0', +199 silly addNameRange '1.0.0-rc.1', +199 silly addNameRange '1.0.0-rc.3', +199 silly addNameRange '1.0.0', +199 silly addNameRange '1.0.1', +199 silly addNameRange '1.1.0', +199 silly addNameRange '1.1.1', +199 silly addNameRange '1.2.0', +199 silly addNameRange '1.2.1', +199 silly addNameRange '1.3.0', +199 silly addNameRange '1.3.1', +199 silly addNameRange '2.0.0', +199 silly addNameRange '2.1.0', +199 silly addNameRange '2.2.1', +199 silly addNameRange '2.3.0', +199 silly addNameRange '2.4.0', +199 silly addNameRange '2.4.1', +199 silly addNameRange '2.2.0', +199 silly addNameRange '0.9.1', +199 silly addNameRange '0.6.1', +199 silly addNameRange '1.0.0-rc.2' ] ] +200 verbose addNamed [ 'lodash', '2.4.1' ] +201 verbose addNamed [ '2.4.1', '2.4.1' ] +202 silly lockFile 8502be2a-lodash-2-4-1 lodash@2.4.1 +203 verbose lock lodash@2.4.1 /Users/kofi/.npm/8502be2a-lodash-2-4-1.lock +204 verbose addRemoteTarball [ 'http://npm-registry.snc1/package/npub-0.0.5.tgz', +204 verbose addRemoteTarball '06bdb7353a6921187df5e38348da251ffa9c982e' ] +205 verbose addRemoteTarball [ 'http://npm-registry.snc1/package/expect.js-0.2.0.tgz', +205 verbose addRemoteTarball '1028533d2c1c363f74a6796ff57ec0520ded2be1' ] +206 info retry fetch attempt 1 at 12:03:35 +207 verbose fetch to= /var/folders/qp/t38wn29163504vzb96_ywv38yv8d3k/T/npm-20797-76blj77o/npm-registry.snc1/package/expect.js-0.2.0.tgz +208 http GET http://npm-registry.snc1/package/expect.js-0.2.0.tgz +209 info retry fetch attempt 1 at 12:03:35 +210 verbose fetch to= /var/folders/qp/t38wn29163504vzb96_ywv38yv8d3k/T/npm-20797-76blj77o/npm-registry.snc1/package/npub-0.0.5.tgz +211 silly lockFile 8502be2a-lodash-2-4-1 lodash@2.4.1 +212 silly lockFile 8502be2a-lodash-2-4-1 lodash@2.4.1 +213 http GET http://npm-registry.snc1/package/npub-0.0.5.tgz +214 silly lockFile 257f9ab3-lodash-2-4-1 lodash@~2.4.1 +215 silly lockFile 257f9ab3-lodash-2-4-1 lodash@~2.4.1 +216 http 200 http://npm-registry.snc1/q +217 silly registry.get cb [ 200, +217 silly registry.get { server: 'nginx/1.5.12', +217 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +217 silly registry.get 'content-type': 'application/json', +217 silly registry.get 'transfer-encoding': 'chunked', +217 silly registry.get connection: 'keep-alive', +217 silly registry.get vary: 'Accept', +217 silly registry.get 'content-encoding': 'gzip' } ] +218 silly addNameRange number 2 { name: 'q', range: '>=0.9.7-0 <0.10.0-0', hasData: true } +219 silly addNameRange versions [ 'q', +219 silly addNameRange [ '0.0.0', +219 silly addNameRange '0.0.1', +219 silly addNameRange '0.0.2', +219 silly addNameRange '0.0.3', +219 silly addNameRange '0.1.0', +219 silly addNameRange '0.1.1', +219 silly addNameRange '0.1.3', +219 silly addNameRange '0.1.4', +219 silly addNameRange '0.1.5', +219 silly addNameRange '0.1.6', +219 silly addNameRange '0.1.7', +219 silly addNameRange '0.1.8', +219 silly addNameRange '0.1.9', +219 silly addNameRange '0.2.0-rc1', +219 silly addNameRange '0.2.0', +219 silly addNameRange '0.2.1', +219 silly addNameRange '0.2.2', +219 silly addNameRange '0.2.3', +219 silly addNameRange '0.2.4', +219 silly addNameRange '0.2.5', +219 silly addNameRange '0.2.7', +219 silly addNameRange '0.2.8', +219 silly addNameRange '0.2.9', +219 silly addNameRange '0.3.0', +219 silly addNameRange '0.2.10', +219 silly addNameRange '0.4.0', +219 silly addNameRange '0.4.1', +219 silly addNameRange '0.4.2', +219 silly addNameRange '0.4.4', +219 silly addNameRange '0.5.0', +219 silly addNameRange '0.5.1', +219 silly addNameRange '0.5.3', +219 silly addNameRange '0.6.0', +219 silly addNameRange '0.7.1', +219 silly addNameRange '0.7.2', +219 silly addNameRange '0.8.0', +219 silly addNameRange '0.8.2', +219 silly addNameRange '0.8.3', +219 silly addNameRange '0.8.4', +219 silly addNameRange '0.8.5', +219 silly addNameRange '0.8.6', +219 silly addNameRange '0.8.7', +219 silly addNameRange '0.8.8', +219 silly addNameRange '0.8.9', +219 silly addNameRange '0.8.10', +219 silly addNameRange '0.8.11', +219 silly addNameRange '0.8.12', +219 silly addNameRange '0.9.0', +219 silly addNameRange '0.9.1', +219 silly addNameRange '0.9.2', +219 silly addNameRange '0.9.3', +219 silly addNameRange '0.9.4', +219 silly addNameRange '0.9.6', +219 silly addNameRange '0.9.7', +219 silly addNameRange '1.0.0', +219 silly addNameRange '1.0.1', +219 silly addNameRange '2.0.1', +219 silly addNameRange '2.0.0', +219 silly addNameRange '2.0.2', +219 silly addNameRange '0.9.5', +219 silly addNameRange '0.8.1', +219 silly addNameRange '0.1.2', +219 silly addNameRange '0.2.6', +219 silly addNameRange '0.5.2' ] ] +220 verbose addNamed [ 'q', '0.9.7' ] +221 verbose addNamed [ '0.9.7', '0.9.7' ] +222 silly lockFile cc8e51ee-q-0-9-7 q@0.9.7 +223 verbose lock q@0.9.7 /Users/kofi/.npm/cc8e51ee-q-0-9-7.lock +224 silly lockFile cc8e51ee-q-0-9-7 q@0.9.7 +225 silly lockFile cc8e51ee-q-0-9-7 q@0.9.7 +226 silly lockFile 9ea2316a-q-0-9-7 q@~0.9.7 +227 silly lockFile 9ea2316a-q-0-9-7 q@~0.9.7 +228 http 200 http://npm-registry.snc1/mocha +229 silly registry.get cb [ 200, +229 silly registry.get { server: 'nginx/1.5.12', +229 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', +229 silly registry.get 'content-type': 'application/json', +229 silly registry.get 'transfer-encoding': 'chunked', +229 silly registry.get connection: 'keep-alive', +229 silly registry.get vary: 'Accept', +229 silly registry.get 'content-encoding': 'gzip' } ] +230 silly lockFile b9e888b2-mocha-2-0-1 mocha@^~2.0.1 +231 silly lockFile b9e888b2-mocha-2-0-1 mocha@^~2.0.1 +232 http 200 http://npm-registry.snc1/package/expect.js-0.2.0.tgz +233 http 200 http://npm-registry.snc1/package/npub-0.0.5.tgz +234 silly lockFile 4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz http://npm-registry.snc1/package/npub-0.0.5.tgz +235 silly lockFile 4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz http://npm-registry.snc1/package/npub-0.0.5.tgz +236 silly lockFile 6aafaa92-npub-0-0-5 npub@0.0.5 +237 silly lockFile 6aafaa92-npub-0-0-5 npub@0.0.5 +238 silly lockFile 9efb77d3-snc1-package-expect-js-0-2-0-tgz http://npm-registry.snc1/package/expect.js-0.2.0.tgz +239 silly lockFile 9efb77d3-snc1-package-expect-js-0-2-0-tgz http://npm-registry.snc1/package/expect.js-0.2.0.tgz +240 silly lockFile 8bd15c82-expect-js-0-2-0 expect.js@0.2.0 +241 silly lockFile 8bd15c82-expect-js-0-2-0 expect.js@0.2.0 +242 error notarget No compatible version found: mocha@'^~2.0.1' +242 error notarget Valid install targets: +242 error notarget ["0.0.1-alpha1","0.0.1-alpha2","0.0.1-alpha3","0.0.1-alpha4","0.0.1-alpha5","0.0.1-alpha6","0.0.1","0.0.2","0.0.3","0.0.4","0.0.5","0.0.6","0.0.7","0.0.8","0.1.0","0.2.0","0.3.0","0.3.2","0.3.3","0.3.4","0.3.6","0.4.0","0.6.0","0.7.0","0.7.1","0.8.0","0.8.1","0.9.0","0.10.0","0.10.1","0.11.0","0.12.0","0.12.1","0.13.0","1.0.1","1.0.2","1.0.3","1.1.0","1.2.0","1.2.1","1.2.2","1.3.0","1.4.3","1.5.0","1.6.0","1.7.0","1.7.1","1.7.2","1.7.4","1.8.0","1.8.1","1.8.2","1.9.0","1.10.0","1.11.0","1.12.0","1.12.1","1.13.0","1.14.0","1.15.1","1.16.0","1.16.1","1.16.2","1.17.0","1.17.1","1.18.1","1.18.2","1.19.0","1.20.0","1.20.1","1.21.0","1.3.1","1.21.3","1.21.4","1.4.0","0.5.0","1.18.0","1.4.1","0.10.2","1.7.3","1.3.2","1.21.5","1.21.1","0.3.1","1.15.0","2.0.0","0.14.1","2.0.1","0.14.0","1.0.0","1.4.2","1.21.2"] +242 error notarget +242 error notarget This is most likely not a problem with npm itself. +242 error notarget In most cases you or one of your dependencies are requesting +242 error notarget a package version that doesn't exist. +243 error System Darwin 13.4.0 +244 error command "/usr/local/opt/nvm/v0.10.33/bin/node" "/usr/local/opt/nvm/v0.10.33/bin/npm" "install" +245 error cwd /Users/kofi/thePoints/node-cached +246 error node -v v0.10.33 +247 error npm -v 1.4.28 +248 error code ETARGET +249 verbose exit [ 1, true ] diff --git a/package.json b/package.json index 72b7490..9c20c29 100644 --- a/package.json +++ b/package.json @@ -28,15 +28,15 @@ } }, "dependencies": { - "lodash": "^2.4.1", - "memcached": "^2.0.0", + "lodash": "~2.4.1", + "memcached": "~2.0.0", "q": "~0.9.7" }, "devDependencies": { - "bondjs": "^1.0.0", - "coffee-script": "^1.8.0", + "bondjs": "~1.0.0", + "coffee-script": "~1.8.0", "expect.js": "0.2.0", - "mocha": "^2.0.1", + "mocha": "~2.0.1", "npub": "0.0.5" } } From 305a51df6ce690aed73d7ff53bfd3320f0ef4fba Mon Sep 17 00:00:00 2001 From: Kofi Appiah Date: Mon, 17 Nov 2014 12:27:34 -0600 Subject: [PATCH 03/55] PR changes (gitignore and npub) - gitignore `npm-debug.log` - add `lib` to npub ignore --- .gitignore | 1 + lib/backend.js | 32 -------------------------------- lib/backends/memcached.js | 32 -------------------------------- lib/backends/memory.js | 32 -------------------------------- lib/backends/noop.js | 32 -------------------------------- lib/cache.js | 32 -------------------------------- lib/cached.js | 32 -------------------------------- package.json | 3 ++- 8 files changed, 3 insertions(+), 193 deletions(-) diff --git a/.gitignore b/.gitignore index 3c3629e..eb03e3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +*.log diff --git a/lib/backend.js b/lib/backend.js index 992c1a4..2f35e3b 100644 --- a/lib/backend.js +++ b/lib/backend.js @@ -1,35 +1,3 @@ -/* -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -*/ - // Generated by CoffeeScript 1.8.0 /* diff --git a/lib/backends/memcached.js b/lib/backends/memcached.js index 5be1b38..c4fea37 100644 --- a/lib/backends/memcached.js +++ b/lib/backends/memcached.js @@ -1,35 +1,3 @@ -/* -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -*/ - // Generated by CoffeeScript 1.8.0 /* diff --git a/lib/backends/memory.js b/lib/backends/memory.js index 50001d3..b4de49d 100644 --- a/lib/backends/memory.js +++ b/lib/backends/memory.js @@ -1,35 +1,3 @@ -/* -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -*/ - // Generated by CoffeeScript 1.8.0 /* diff --git a/lib/backends/noop.js b/lib/backends/noop.js index 80ad739..659ee29 100644 --- a/lib/backends/noop.js +++ b/lib/backends/noop.js @@ -1,35 +1,3 @@ -/* -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -*/ - // Generated by CoffeeScript 1.8.0 /* diff --git a/lib/cache.js b/lib/cache.js index a5f50f1..1ee1dc9 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,35 +1,3 @@ -/* -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -*/ - // Generated by CoffeeScript 1.8.0 /* diff --git a/lib/cached.js b/lib/cached.js index 84badb5..4da566b 100644 --- a/lib/cached.js +++ b/lib/cached.js @@ -1,35 +1,3 @@ -/* -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -*/ - // Generated by CoffeeScript 1.8.0 /* diff --git a/package.json b/package.json index 9c20c29..93f9d3f 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "registry": "https://registry.npmjs.org", "license": { "exclude": [ + "lib", "test" ] } @@ -35,7 +36,7 @@ "devDependencies": { "bondjs": "~1.0.0", "coffee-script": "~1.8.0", - "expect.js": "0.2.0", + "expect.js": "~0.2.0", "mocha": "~2.0.1", "npub": "0.0.5" } From 3f7d9207e881c9c259a8fd9e85a34dd3e7077a1f Mon Sep 17 00:00:00 2001 From: Kofi Appiah Date: Mon, 17 Nov 2014 12:32:04 -0600 Subject: [PATCH 04/55] oops - forgot to remove --- npm-debug.log | 690 -------------------------------------------------- 1 file changed, 690 deletions(-) delete mode 100644 npm-debug.log diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index 85d896e..0000000 --- a/npm-debug.log +++ /dev/null @@ -1,690 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/usr/local/opt/nvm/v0.10.33/bin/node', -1 verbose cli '/usr/local/opt/nvm/v0.10.33/bin/npm', -1 verbose cli 'install' ] -2 info using npm@1.4.28 -3 info using node@v0.10.33 -4 verbose node symlink /usr/local/opt/nvm/v0.10.33/bin/node -5 verbose readDependencies using package.json deps -6 verbose install where, deps [ '/Users/kofi/thePoints/node-cached', -6 verbose install [ 'lodash', -6 verbose install 'memcached', -6 verbose install 'q', -6 verbose install 'bondjs', -6 verbose install 'coffee-script', -6 verbose install 'expect.js', -6 verbose install 'mocha', -6 verbose install 'npub' ] ] -7 info preinstall cached@3.0.0 -8 verbose readDependencies using package.json deps -9 verbose cache add [ 'lodash@~2.4.1', null ] -10 verbose cache add name=undefined spec="lodash@~2.4.1" args=["lodash@~2.4.1",null] -11 verbose parsed url { protocol: null, -11 verbose parsed url slashes: null, -11 verbose parsed url auth: null, -11 verbose parsed url host: null, -11 verbose parsed url port: null, -11 verbose parsed url hostname: null, -11 verbose parsed url hash: null, -11 verbose parsed url search: null, -11 verbose parsed url query: null, -11 verbose parsed url pathname: 'lodash@~2.4.1', -11 verbose parsed url path: 'lodash@~2.4.1', -11 verbose parsed url href: 'lodash@~2.4.1' } -12 verbose cache add [ 'memcached@~2.0.0', null ] -13 verbose cache add name=undefined spec="memcached@~2.0.0" args=["memcached@~2.0.0",null] -14 verbose parsed url { protocol: null, -14 verbose parsed url slashes: null, -14 verbose parsed url auth: null, -14 verbose parsed url host: null, -14 verbose parsed url port: null, -14 verbose parsed url hostname: null, -14 verbose parsed url hash: null, -14 verbose parsed url search: null, -14 verbose parsed url query: null, -14 verbose parsed url pathname: 'memcached@~2.0.0', -14 verbose parsed url path: 'memcached@~2.0.0', -14 verbose parsed url href: 'memcached@~2.0.0' } -15 verbose cache add [ 'q@~0.9.7', null ] -16 verbose cache add name=undefined spec="q@~0.9.7" args=["q@~0.9.7",null] -17 verbose parsed url { protocol: null, -17 verbose parsed url slashes: null, -17 verbose parsed url auth: null, -17 verbose parsed url host: null, -17 verbose parsed url port: null, -17 verbose parsed url hostname: null, -17 verbose parsed url hash: null, -17 verbose parsed url search: null, -17 verbose parsed url query: null, -17 verbose parsed url pathname: 'q@~0.9.7', -17 verbose parsed url path: 'q@~0.9.7', -17 verbose parsed url href: 'q@~0.9.7' } -18 verbose cache add [ 'bondjs@~1.0.0', null ] -19 verbose cache add name=undefined spec="bondjs@~1.0.0" args=["bondjs@~1.0.0",null] -20 verbose parsed url { protocol: null, -20 verbose parsed url slashes: null, -20 verbose parsed url auth: null, -20 verbose parsed url host: null, -20 verbose parsed url port: null, -20 verbose parsed url hostname: null, -20 verbose parsed url hash: null, -20 verbose parsed url search: null, -20 verbose parsed url query: null, -20 verbose parsed url pathname: 'bondjs@~1.0.0', -20 verbose parsed url path: 'bondjs@~1.0.0', -20 verbose parsed url href: 'bondjs@~1.0.0' } -21 verbose cache add name="lodash" spec="~2.4.1" args=["lodash","~2.4.1"] -22 verbose parsed url { protocol: null, -22 verbose parsed url slashes: null, -22 verbose parsed url auth: null, -22 verbose parsed url host: null, -22 verbose parsed url port: null, -22 verbose parsed url hostname: null, -22 verbose parsed url hash: null, -22 verbose parsed url search: null, -22 verbose parsed url query: null, -22 verbose parsed url pathname: '~2.4.1', -22 verbose parsed url path: '~2.4.1', -22 verbose parsed url href: '~2.4.1' } -23 verbose addNamed [ 'lodash', '~2.4.1' ] -24 verbose addNamed [ null, '>=2.4.1-0 <2.5.0-0' ] -25 verbose cache add name="memcached" spec="~2.0.0" args=["memcached","~2.0.0"] -26 verbose parsed url { protocol: null, -26 verbose parsed url slashes: null, -26 verbose parsed url auth: null, -26 verbose parsed url host: null, -26 verbose parsed url port: null, -26 verbose parsed url hostname: null, -26 verbose parsed url hash: null, -26 verbose parsed url search: null, -26 verbose parsed url query: null, -26 verbose parsed url pathname: '~2.0.0', -26 verbose parsed url path: '~2.0.0', -26 verbose parsed url href: '~2.0.0' } -27 verbose addNamed [ 'memcached', '~2.0.0' ] -28 verbose addNamed [ null, '>=2.0.0-0 <2.1.0-0' ] -29 verbose cache add name="q" spec="~0.9.7" args=["q","~0.9.7"] -30 verbose parsed url { protocol: null, -30 verbose parsed url slashes: null, -30 verbose parsed url auth: null, -30 verbose parsed url host: null, -30 verbose parsed url port: null, -30 verbose parsed url hostname: null, -30 verbose parsed url hash: null, -30 verbose parsed url search: null, -30 verbose parsed url query: null, -30 verbose parsed url pathname: '~0.9.7', -30 verbose parsed url path: '~0.9.7', -30 verbose parsed url href: '~0.9.7' } -31 verbose addNamed [ 'q', '~0.9.7' ] -32 verbose addNamed [ null, '>=0.9.7-0 <0.10.0-0' ] -33 verbose cache add name="bondjs" spec="~1.0.0" args=["bondjs","~1.0.0"] -34 verbose parsed url { protocol: null, -34 verbose parsed url slashes: null, -34 verbose parsed url auth: null, -34 verbose parsed url host: null, -34 verbose parsed url port: null, -34 verbose parsed url hostname: null, -34 verbose parsed url hash: null, -34 verbose parsed url search: null, -34 verbose parsed url query: null, -34 verbose parsed url pathname: '~1.0.0', -34 verbose parsed url path: '~1.0.0', -34 verbose parsed url href: '~1.0.0' } -35 verbose addNamed [ 'bondjs', '~1.0.0' ] -36 verbose addNamed [ null, '>=1.0.0-0 <1.1.0-0' ] -37 verbose cache add [ 'coffee-script@~1.8.0', null ] -38 verbose cache add name=undefined spec="coffee-script@~1.8.0" args=["coffee-script@~1.8.0",null] -39 verbose parsed url { protocol: null, -39 verbose parsed url slashes: null, -39 verbose parsed url auth: null, -39 verbose parsed url host: null, -39 verbose parsed url port: null, -39 verbose parsed url hostname: null, -39 verbose parsed url hash: null, -39 verbose parsed url search: null, -39 verbose parsed url query: null, -39 verbose parsed url pathname: 'coffee-script@~1.8.0', -39 verbose parsed url path: 'coffee-script@~1.8.0', -39 verbose parsed url href: 'coffee-script@~1.8.0' } -40 verbose cache add [ 'expect.js@0.2.0', null ] -41 verbose cache add name=undefined spec="expect.js@0.2.0" args=["expect.js@0.2.0",null] -42 verbose parsed url { protocol: null, -42 verbose parsed url slashes: null, -42 verbose parsed url auth: null, -42 verbose parsed url host: null, -42 verbose parsed url port: null, -42 verbose parsed url hostname: null, -42 verbose parsed url hash: null, -42 verbose parsed url search: null, -42 verbose parsed url query: null, -42 verbose parsed url pathname: 'expect.js@0.2.0', -42 verbose parsed url path: 'expect.js@0.2.0', -42 verbose parsed url href: 'expect.js@0.2.0' } -43 verbose cache add [ 'mocha@^~2.0.1', null ] -44 verbose cache add name=undefined spec="mocha@^~2.0.1" args=["mocha@^~2.0.1",null] -45 verbose parsed url { protocol: null, -45 verbose parsed url slashes: null, -45 verbose parsed url auth: null, -45 verbose parsed url host: null, -45 verbose parsed url port: null, -45 verbose parsed url hostname: null, -45 verbose parsed url hash: null, -45 verbose parsed url search: null, -45 verbose parsed url query: null, -45 verbose parsed url pathname: 'mocha@^~2.0.1', -45 verbose parsed url path: 'mocha@^~2.0.1', -45 verbose parsed url href: 'mocha@^~2.0.1' } -46 silly lockFile 257f9ab3-lodash-2-4-1 lodash@~2.4.1 -47 verbose lock lodash@~2.4.1 /Users/kofi/.npm/257f9ab3-lodash-2-4-1.lock -48 silly lockFile dfc8f739-memcached-2-0-0 memcached@~2.0.0 -49 verbose lock memcached@~2.0.0 /Users/kofi/.npm/dfc8f739-memcached-2-0-0.lock -50 silly lockFile 9ea2316a-q-0-9-7 q@~0.9.7 -51 verbose lock q@~0.9.7 /Users/kofi/.npm/9ea2316a-q-0-9-7.lock -52 silly lockFile 4ea17dfe-bondjs-1-0-0 bondjs@~1.0.0 -53 verbose lock bondjs@~1.0.0 /Users/kofi/.npm/4ea17dfe-bondjs-1-0-0.lock -54 verbose cache add name="coffee-script" spec="~1.8.0" args=["coffee-script","~1.8.0"] -55 verbose parsed url { protocol: null, -55 verbose parsed url slashes: null, -55 verbose parsed url auth: null, -55 verbose parsed url host: null, -55 verbose parsed url port: null, -55 verbose parsed url hostname: null, -55 verbose parsed url hash: null, -55 verbose parsed url search: null, -55 verbose parsed url query: null, -55 verbose parsed url pathname: '~1.8.0', -55 verbose parsed url path: '~1.8.0', -55 verbose parsed url href: '~1.8.0' } -56 verbose addNamed [ 'coffee-script', '~1.8.0' ] -57 verbose addNamed [ null, '>=1.8.0-0 <1.9.0-0' ] -58 silly lockFile f37fc738-coffee-script-1-8-0 coffee-script@~1.8.0 -59 verbose lock coffee-script@~1.8.0 /Users/kofi/.npm/f37fc738-coffee-script-1-8-0.lock -60 verbose cache add name="expect.js" spec="0.2.0" args=["expect.js","0.2.0"] -61 verbose parsed url { protocol: null, -61 verbose parsed url slashes: null, -61 verbose parsed url auth: null, -61 verbose parsed url host: null, -61 verbose parsed url port: null, -61 verbose parsed url hostname: null, -61 verbose parsed url hash: null, -61 verbose parsed url search: null, -61 verbose parsed url query: null, -61 verbose parsed url pathname: '0.2.0', -61 verbose parsed url path: '0.2.0', -61 verbose parsed url href: '0.2.0' } -62 verbose addNamed [ 'expect.js', '0.2.0' ] -63 verbose addNamed [ '0.2.0', '0.2.0' ] -64 silly lockFile 8bd15c82-expect-js-0-2-0 expect.js@0.2.0 -65 verbose lock expect.js@0.2.0 /Users/kofi/.npm/8bd15c82-expect-js-0-2-0.lock -66 verbose cache add [ 'npub@0.0.5', null ] -67 verbose cache add name=undefined spec="npub@0.0.5" args=["npub@0.0.5",null] -68 verbose parsed url { protocol: null, -68 verbose parsed url slashes: null, -68 verbose parsed url auth: null, -68 verbose parsed url host: null, -68 verbose parsed url port: null, -68 verbose parsed url hostname: null, -68 verbose parsed url hash: null, -68 verbose parsed url search: null, -68 verbose parsed url query: null, -68 verbose parsed url pathname: 'npub@0.0.5', -68 verbose parsed url path: 'npub@0.0.5', -68 verbose parsed url href: 'npub@0.0.5' } -69 verbose cache add name="mocha" spec="^~2.0.1" args=["mocha","^~2.0.1"] -70 verbose parsed url { protocol: null, -70 verbose parsed url slashes: null, -70 verbose parsed url auth: null, -70 verbose parsed url host: null, -70 verbose parsed url port: null, -70 verbose parsed url hostname: null, -70 verbose parsed url hash: null, -70 verbose parsed url search: null, -70 verbose parsed url query: null, -70 verbose parsed url pathname: '^~2.0.1', -70 verbose parsed url path: '^~2.0.1', -70 verbose parsed url href: '^~2.0.1' } -71 verbose addNamed [ 'mocha', '^~2.0.1' ] -72 verbose addNamed [ null, null ] -73 silly lockFile b9e888b2-mocha-2-0-1 mocha@^~2.0.1 -74 verbose lock mocha@^~2.0.1 /Users/kofi/.npm/b9e888b2-mocha-2-0-1.lock -75 verbose cache add name="npub" spec="0.0.5" args=["npub","0.0.5"] -76 verbose parsed url { protocol: null, -76 verbose parsed url slashes: null, -76 verbose parsed url auth: null, -76 verbose parsed url host: null, -76 verbose parsed url port: null, -76 verbose parsed url hostname: null, -76 verbose parsed url hash: null, -76 verbose parsed url search: null, -76 verbose parsed url query: null, -76 verbose parsed url pathname: '0.0.5', -76 verbose parsed url path: '0.0.5', -76 verbose parsed url href: '0.0.5' } -77 verbose addNamed [ 'npub', '0.0.5' ] -78 verbose addNamed [ '0.0.5', '0.0.5' ] -79 silly lockFile 6aafaa92-npub-0-0-5 npub@0.0.5 -80 verbose lock npub@0.0.5 /Users/kofi/.npm/6aafaa92-npub-0-0-5.lock -81 silly addNameRange { name: 'lodash', range: '>=2.4.1-0 <2.5.0-0', hasData: false } -82 silly addNameRange { name: 'memcached', -82 silly addNameRange range: '>=2.0.0-0 <2.1.0-0', -82 silly addNameRange hasData: false } -83 silly addNameRange { name: 'q', range: '>=0.9.7-0 <0.10.0-0', hasData: false } -84 silly addNameRange { name: 'bondjs', range: '>=1.0.0-0 <1.1.0-0', hasData: false } -85 silly addNameRange { name: 'coffee-script', -85 silly addNameRange range: '>=1.8.0-0 <1.9.0-0', -85 silly addNameRange hasData: false } -86 info addNameTag [ 'mocha', '^~2.0.1' ] -87 verbose request where is /lodash -88 verbose request registry http://npm-registry.snc1/ -89 verbose request id c6cf32ce3214a251 -90 verbose url raw /lodash -91 verbose url resolving [ 'http://npm-registry.snc1/', './lodash' ] -92 verbose url resolved http://npm-registry.snc1/lodash -93 verbose request where is http://npm-registry.snc1/lodash -94 info trying registry request attempt 1 at 12:03:34 -95 http GET http://npm-registry.snc1/lodash -96 verbose request where is /memcached -97 verbose request registry http://npm-registry.snc1/ -98 verbose url raw /memcached -99 verbose url resolving [ 'http://npm-registry.snc1/', './memcached' ] -100 verbose url resolved http://npm-registry.snc1/memcached -101 verbose request where is http://npm-registry.snc1/memcached -102 info trying registry request attempt 1 at 12:03:34 -103 http GET http://npm-registry.snc1/memcached -104 verbose request where is /q -105 verbose request registry http://npm-registry.snc1/ -106 verbose url raw /q -107 verbose url resolving [ 'http://npm-registry.snc1/', './q' ] -108 verbose url resolved http://npm-registry.snc1/q -109 verbose request where is http://npm-registry.snc1/q -110 info trying registry request attempt 1 at 12:03:34 -111 http GET http://npm-registry.snc1/q -112 verbose request where is /bondjs -113 verbose request registry http://npm-registry.snc1/ -114 verbose url raw /bondjs -115 verbose url resolving [ 'http://npm-registry.snc1/', './bondjs' ] -116 verbose url resolved http://npm-registry.snc1/bondjs -117 verbose request where is http://npm-registry.snc1/bondjs -118 info trying registry request attempt 1 at 12:03:34 -119 http GET http://npm-registry.snc1/bondjs -120 verbose request where is /coffee-script -121 verbose request registry http://npm-registry.snc1/ -122 verbose url raw /coffee-script -123 verbose url resolving [ 'http://npm-registry.snc1/', './coffee-script' ] -124 verbose url resolved http://npm-registry.snc1/coffee-script -125 verbose request where is http://npm-registry.snc1/coffee-script -126 info trying registry request attempt 1 at 12:03:34 -127 http GET http://npm-registry.snc1/coffee-script -128 verbose request where is /expect.js -129 verbose request registry http://npm-registry.snc1/ -130 verbose url raw /expect.js -131 verbose url resolving [ 'http://npm-registry.snc1/', './expect.js' ] -132 verbose url resolved http://npm-registry.snc1/expect.js -133 verbose request where is http://npm-registry.snc1/expect.js -134 info trying registry request attempt 1 at 12:03:34 -135 http GET http://npm-registry.snc1/expect.js -136 verbose request where is /mocha -137 verbose request registry http://npm-registry.snc1/ -138 verbose url raw /mocha -139 verbose url resolving [ 'http://npm-registry.snc1/', './mocha' ] -140 verbose url resolved http://npm-registry.snc1/mocha -141 verbose request where is http://npm-registry.snc1/mocha -142 info trying registry request attempt 1 at 12:03:34 -143 http GET http://npm-registry.snc1/mocha -144 verbose request where is /npub -145 verbose request registry http://npm-registry.snc1/ -146 verbose url raw /npub -147 verbose url resolving [ 'http://npm-registry.snc1/', './npub' ] -148 verbose url resolved http://npm-registry.snc1/npub -149 verbose request where is http://npm-registry.snc1/npub -150 info trying registry request attempt 1 at 12:03:34 -151 http GET http://npm-registry.snc1/npub -152 http 200 http://npm-registry.snc1/bondjs -153 silly registry.get cb [ 200, -153 silly registry.get { server: 'nginx/1.5.12', -153 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -153 silly registry.get 'content-type': 'application/json', -153 silly registry.get 'transfer-encoding': 'chunked', -153 silly registry.get connection: 'keep-alive', -153 silly registry.get vary: 'Accept', -153 silly registry.get 'content-encoding': 'gzip' } ] -154 http 200 http://npm-registry.snc1/coffee-script -155 silly registry.get cb [ 200, -155 silly registry.get { server: 'nginx/1.5.12', -155 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -155 silly registry.get 'content-type': 'application/json', -155 silly registry.get 'transfer-encoding': 'chunked', -155 silly registry.get connection: 'keep-alive', -155 silly registry.get vary: 'Accept', -155 silly registry.get 'content-encoding': 'gzip' } ] -156 silly addNameRange number 2 { name: 'bondjs', range: '>=1.0.0-0 <1.1.0-0', hasData: true } -157 silly addNameRange versions [ 'bondjs', -157 silly addNameRange [ '0.0.1', -157 silly addNameRange '0.0.2', -157 silly addNameRange '0.0.3', -157 silly addNameRange '0.0.4', -157 silly addNameRange '0.0.5', -157 silly addNameRange '0.0.6', -157 silly addNameRange '0.0.7', -157 silly addNameRange '0.0.8', -157 silly addNameRange '0.0.9', -157 silly addNameRange '0.0.10', -157 silly addNameRange '0.0.11', -157 silly addNameRange '0.0.13', -157 silly addNameRange '0.0.14', -157 silly addNameRange '1.0.0', -157 silly addNameRange '1.0.1', -157 silly addNameRange '1.1.0', -157 silly addNameRange '1.1.1', -157 silly addNameRange '1.2.0', -157 silly addNameRange '1.2.1' ] ] -158 verbose addNamed [ 'bondjs', '1.0.1' ] -159 verbose addNamed [ '1.0.1', '1.0.1' ] -160 silly lockFile ca3ccbeb-bondjs-1-0-1 bondjs@1.0.1 -161 verbose lock bondjs@1.0.1 /Users/kofi/.npm/ca3ccbeb-bondjs-1-0-1.lock -162 silly addNameRange number 2 { name: 'coffee-script', -162 silly addNameRange range: '>=1.8.0-0 <1.9.0-0', -162 silly addNameRange hasData: true } -163 silly addNameRange versions [ 'coffee-script', -163 silly addNameRange [ '0.7.1', -163 silly addNameRange '0.7.2', -163 silly addNameRange '0.9.0', -163 silly addNameRange '0.9.1', -163 silly addNameRange '0.9.2', -163 silly addNameRange '0.9.3', -163 silly addNameRange '0.9.4', -163 silly addNameRange '0.9.5', -163 silly addNameRange '0.9.6', -163 silly addNameRange '1.0.0', -163 silly addNameRange '1.1.0', -163 silly addNameRange '1.1.1', -163 silly addNameRange '1.1.2', -163 silly addNameRange '1.1.3', -163 silly addNameRange '1.2.0', -163 silly addNameRange '1.3.0', -163 silly addNameRange '1.3.1', -163 silly addNameRange '1.3.2', -163 silly addNameRange '1.3.3', -163 silly addNameRange '1.4.0', -163 silly addNameRange '1.5.0', -163 silly addNameRange '1.6.0', -163 silly addNameRange '1.6.1', -163 silly addNameRange '1.6.2', -163 silly addNameRange '1.6.3', -163 silly addNameRange '1.7.0', -163 silly addNameRange '1.7.1', -163 silly addNameRange '0.7.0', -163 silly addNameRange '1.8.0', -163 silly addNameRange '1.0.1' ] ] -164 verbose addNamed [ 'coffee-script', '1.8.0' ] -165 verbose addNamed [ '1.8.0', '1.8.0' ] -166 silly lockFile d0d79082-coffee-script-1-8-0 coffee-script@1.8.0 -167 verbose lock coffee-script@1.8.0 /Users/kofi/.npm/d0d79082-coffee-script-1-8-0.lock -168 silly lockFile ca3ccbeb-bondjs-1-0-1 bondjs@1.0.1 -169 silly lockFile ca3ccbeb-bondjs-1-0-1 bondjs@1.0.1 -170 silly lockFile 4ea17dfe-bondjs-1-0-0 bondjs@~1.0.0 -171 silly lockFile 4ea17dfe-bondjs-1-0-0 bondjs@~1.0.0 -172 silly lockFile d0d79082-coffee-script-1-8-0 coffee-script@1.8.0 -173 silly lockFile d0d79082-coffee-script-1-8-0 coffee-script@1.8.0 -174 silly lockFile f37fc738-coffee-script-1-8-0 coffee-script@~1.8.0 -175 silly lockFile f37fc738-coffee-script-1-8-0 coffee-script@~1.8.0 -176 http 200 http://npm-registry.snc1/memcached -177 silly registry.get cb [ 200, -177 silly registry.get { server: 'nginx/1.5.12', -177 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -177 silly registry.get 'content-type': 'application/json', -177 silly registry.get 'transfer-encoding': 'chunked', -177 silly registry.get connection: 'keep-alive', -177 silly registry.get vary: 'Accept', -177 silly registry.get 'content-encoding': 'gzip' } ] -178 silly addNameRange number 2 { name: 'memcached', range: '>=2.0.0-0 <2.1.0-0', hasData: true } -179 silly addNameRange versions [ 'memcached', -179 silly addNameRange [ '0.0.1', -179 silly addNameRange '0.0.2', -179 silly addNameRange '0.0.3', -179 silly addNameRange '0.0.4', -179 silly addNameRange '0.0.5', -179 silly addNameRange '0.1.0', -179 silly addNameRange '0.1.1', -179 silly addNameRange '0.1.2', -179 silly addNameRange '0.1.3', -179 silly addNameRange '0.1.4', -179 silly addNameRange '0.1.5', -179 silly addNameRange '0.2.0', -179 silly addNameRange '0.0.7', -179 silly addNameRange '0.0.6', -179 silly addNameRange '0.0.8', -179 silly addNameRange '0.0.9', -179 silly addNameRange '0.0.10', -179 silly addNameRange '0.0.11', -179 silly addNameRange '0.0.12', -179 silly addNameRange '0.2.1', -179 silly addNameRange '0.2.2', -179 silly addNameRange '0.2.3', -179 silly addNameRange '0.2.4', -179 silly addNameRange '0.2.5', -179 silly addNameRange '0.2.6', -179 silly addNameRange '0.2.7', -179 silly addNameRange '0.2.8', -179 silly addNameRange '1.0.0', -179 silly addNameRange '2.0.0' ] ] -180 verbose addNamed [ 'memcached', '2.0.0' ] -181 verbose addNamed [ '2.0.0', '2.0.0' ] -182 silly lockFile 7114931d-memcached-2-0-0 memcached@2.0.0 -183 verbose lock memcached@2.0.0 /Users/kofi/.npm/7114931d-memcached-2-0-0.lock -184 silly lockFile 7114931d-memcached-2-0-0 memcached@2.0.0 -185 silly lockFile 7114931d-memcached-2-0-0 memcached@2.0.0 -186 silly lockFile dfc8f739-memcached-2-0-0 memcached@~2.0.0 -187 silly lockFile dfc8f739-memcached-2-0-0 memcached@~2.0.0 -188 http 200 http://npm-registry.snc1/lodash -189 silly registry.get cb [ 200, -189 silly registry.get { server: 'nginx/1.5.12', -189 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -189 silly registry.get 'content-type': 'application/json', -189 silly registry.get 'transfer-encoding': 'chunked', -189 silly registry.get connection: 'keep-alive', -189 silly registry.get vary: 'Accept', -189 silly registry.get 'content-encoding': 'gzip' } ] -190 http 200 http://npm-registry.snc1/npub -191 silly registry.get cb [ 200, -191 silly registry.get { server: 'nginx/1.5.12', -191 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -191 silly registry.get 'content-type': 'application/json', -191 silly registry.get 'transfer-encoding': 'chunked', -191 silly registry.get connection: 'keep-alive', -191 silly registry.get vary: 'Accept', -191 silly registry.get 'content-encoding': 'gzip' } ] -192 http 200 http://npm-registry.snc1/expect.js -193 silly registry.get cb [ 200, -193 silly registry.get { server: 'nginx/1.5.12', -193 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -193 silly registry.get 'content-type': 'application/json', -193 silly registry.get 'transfer-encoding': 'chunked', -193 silly registry.get connection: 'keep-alive', -193 silly registry.get vary: 'Accept', -193 silly registry.get 'content-encoding': 'gzip' } ] -194 silly lockFile 4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz http://npm-registry.snc1/package/npub-0.0.5.tgz -195 verbose lock http://npm-registry.snc1/package/npub-0.0.5.tgz /Users/kofi/.npm/4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz.lock -196 silly lockFile 9efb77d3-snc1-package-expect-js-0-2-0-tgz http://npm-registry.snc1/package/expect.js-0.2.0.tgz -197 verbose lock http://npm-registry.snc1/package/expect.js-0.2.0.tgz /Users/kofi/.npm/9efb77d3-snc1-package-expect-js-0-2-0-tgz.lock -198 silly addNameRange number 2 { name: 'lodash', range: '>=2.4.1-0 <2.5.0-0', hasData: true } -199 silly addNameRange versions [ 'lodash', -199 silly addNameRange [ '0.1.0', -199 silly addNameRange '0.2.0', -199 silly addNameRange '0.2.1', -199 silly addNameRange '0.2.2', -199 silly addNameRange '0.3.0', -199 silly addNameRange '0.3.1', -199 silly addNameRange '0.3.2', -199 silly addNameRange '0.4.0', -199 silly addNameRange '0.4.1', -199 silly addNameRange '0.4.2', -199 silly addNameRange '0.5.0-rc.1', -199 silly addNameRange '0.5.0', -199 silly addNameRange '0.5.1', -199 silly addNameRange '0.5.2', -199 silly addNameRange '0.6.0', -199 silly addNameRange '0.7.0', -199 silly addNameRange '0.8.0', -199 silly addNameRange '0.8.1', -199 silly addNameRange '0.8.2', -199 silly addNameRange '0.9.0', -199 silly addNameRange '0.9.2', -199 silly addNameRange '0.10.0', -199 silly addNameRange '1.0.0-rc.1', -199 silly addNameRange '1.0.0-rc.3', -199 silly addNameRange '1.0.0', -199 silly addNameRange '1.0.1', -199 silly addNameRange '1.1.0', -199 silly addNameRange '1.1.1', -199 silly addNameRange '1.2.0', -199 silly addNameRange '1.2.1', -199 silly addNameRange '1.3.0', -199 silly addNameRange '1.3.1', -199 silly addNameRange '2.0.0', -199 silly addNameRange '2.1.0', -199 silly addNameRange '2.2.1', -199 silly addNameRange '2.3.0', -199 silly addNameRange '2.4.0', -199 silly addNameRange '2.4.1', -199 silly addNameRange '2.2.0', -199 silly addNameRange '0.9.1', -199 silly addNameRange '0.6.1', -199 silly addNameRange '1.0.0-rc.2' ] ] -200 verbose addNamed [ 'lodash', '2.4.1' ] -201 verbose addNamed [ '2.4.1', '2.4.1' ] -202 silly lockFile 8502be2a-lodash-2-4-1 lodash@2.4.1 -203 verbose lock lodash@2.4.1 /Users/kofi/.npm/8502be2a-lodash-2-4-1.lock -204 verbose addRemoteTarball [ 'http://npm-registry.snc1/package/npub-0.0.5.tgz', -204 verbose addRemoteTarball '06bdb7353a6921187df5e38348da251ffa9c982e' ] -205 verbose addRemoteTarball [ 'http://npm-registry.snc1/package/expect.js-0.2.0.tgz', -205 verbose addRemoteTarball '1028533d2c1c363f74a6796ff57ec0520ded2be1' ] -206 info retry fetch attempt 1 at 12:03:35 -207 verbose fetch to= /var/folders/qp/t38wn29163504vzb96_ywv38yv8d3k/T/npm-20797-76blj77o/npm-registry.snc1/package/expect.js-0.2.0.tgz -208 http GET http://npm-registry.snc1/package/expect.js-0.2.0.tgz -209 info retry fetch attempt 1 at 12:03:35 -210 verbose fetch to= /var/folders/qp/t38wn29163504vzb96_ywv38yv8d3k/T/npm-20797-76blj77o/npm-registry.snc1/package/npub-0.0.5.tgz -211 silly lockFile 8502be2a-lodash-2-4-1 lodash@2.4.1 -212 silly lockFile 8502be2a-lodash-2-4-1 lodash@2.4.1 -213 http GET http://npm-registry.snc1/package/npub-0.0.5.tgz -214 silly lockFile 257f9ab3-lodash-2-4-1 lodash@~2.4.1 -215 silly lockFile 257f9ab3-lodash-2-4-1 lodash@~2.4.1 -216 http 200 http://npm-registry.snc1/q -217 silly registry.get cb [ 200, -217 silly registry.get { server: 'nginx/1.5.12', -217 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -217 silly registry.get 'content-type': 'application/json', -217 silly registry.get 'transfer-encoding': 'chunked', -217 silly registry.get connection: 'keep-alive', -217 silly registry.get vary: 'Accept', -217 silly registry.get 'content-encoding': 'gzip' } ] -218 silly addNameRange number 2 { name: 'q', range: '>=0.9.7-0 <0.10.0-0', hasData: true } -219 silly addNameRange versions [ 'q', -219 silly addNameRange [ '0.0.0', -219 silly addNameRange '0.0.1', -219 silly addNameRange '0.0.2', -219 silly addNameRange '0.0.3', -219 silly addNameRange '0.1.0', -219 silly addNameRange '0.1.1', -219 silly addNameRange '0.1.3', -219 silly addNameRange '0.1.4', -219 silly addNameRange '0.1.5', -219 silly addNameRange '0.1.6', -219 silly addNameRange '0.1.7', -219 silly addNameRange '0.1.8', -219 silly addNameRange '0.1.9', -219 silly addNameRange '0.2.0-rc1', -219 silly addNameRange '0.2.0', -219 silly addNameRange '0.2.1', -219 silly addNameRange '0.2.2', -219 silly addNameRange '0.2.3', -219 silly addNameRange '0.2.4', -219 silly addNameRange '0.2.5', -219 silly addNameRange '0.2.7', -219 silly addNameRange '0.2.8', -219 silly addNameRange '0.2.9', -219 silly addNameRange '0.3.0', -219 silly addNameRange '0.2.10', -219 silly addNameRange '0.4.0', -219 silly addNameRange '0.4.1', -219 silly addNameRange '0.4.2', -219 silly addNameRange '0.4.4', -219 silly addNameRange '0.5.0', -219 silly addNameRange '0.5.1', -219 silly addNameRange '0.5.3', -219 silly addNameRange '0.6.0', -219 silly addNameRange '0.7.1', -219 silly addNameRange '0.7.2', -219 silly addNameRange '0.8.0', -219 silly addNameRange '0.8.2', -219 silly addNameRange '0.8.3', -219 silly addNameRange '0.8.4', -219 silly addNameRange '0.8.5', -219 silly addNameRange '0.8.6', -219 silly addNameRange '0.8.7', -219 silly addNameRange '0.8.8', -219 silly addNameRange '0.8.9', -219 silly addNameRange '0.8.10', -219 silly addNameRange '0.8.11', -219 silly addNameRange '0.8.12', -219 silly addNameRange '0.9.0', -219 silly addNameRange '0.9.1', -219 silly addNameRange '0.9.2', -219 silly addNameRange '0.9.3', -219 silly addNameRange '0.9.4', -219 silly addNameRange '0.9.6', -219 silly addNameRange '0.9.7', -219 silly addNameRange '1.0.0', -219 silly addNameRange '1.0.1', -219 silly addNameRange '2.0.1', -219 silly addNameRange '2.0.0', -219 silly addNameRange '2.0.2', -219 silly addNameRange '0.9.5', -219 silly addNameRange '0.8.1', -219 silly addNameRange '0.1.2', -219 silly addNameRange '0.2.6', -219 silly addNameRange '0.5.2' ] ] -220 verbose addNamed [ 'q', '0.9.7' ] -221 verbose addNamed [ '0.9.7', '0.9.7' ] -222 silly lockFile cc8e51ee-q-0-9-7 q@0.9.7 -223 verbose lock q@0.9.7 /Users/kofi/.npm/cc8e51ee-q-0-9-7.lock -224 silly lockFile cc8e51ee-q-0-9-7 q@0.9.7 -225 silly lockFile cc8e51ee-q-0-9-7 q@0.9.7 -226 silly lockFile 9ea2316a-q-0-9-7 q@~0.9.7 -227 silly lockFile 9ea2316a-q-0-9-7 q@~0.9.7 -228 http 200 http://npm-registry.snc1/mocha -229 silly registry.get cb [ 200, -229 silly registry.get { server: 'nginx/1.5.12', -229 silly registry.get date: 'Mon, 17 Nov 2014 18:03:35 GMT', -229 silly registry.get 'content-type': 'application/json', -229 silly registry.get 'transfer-encoding': 'chunked', -229 silly registry.get connection: 'keep-alive', -229 silly registry.get vary: 'Accept', -229 silly registry.get 'content-encoding': 'gzip' } ] -230 silly lockFile b9e888b2-mocha-2-0-1 mocha@^~2.0.1 -231 silly lockFile b9e888b2-mocha-2-0-1 mocha@^~2.0.1 -232 http 200 http://npm-registry.snc1/package/expect.js-0.2.0.tgz -233 http 200 http://npm-registry.snc1/package/npub-0.0.5.tgz -234 silly lockFile 4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz http://npm-registry.snc1/package/npub-0.0.5.tgz -235 silly lockFile 4d4ab7ed-stry-snc1-package-npub-0-0-5-tgz http://npm-registry.snc1/package/npub-0.0.5.tgz -236 silly lockFile 6aafaa92-npub-0-0-5 npub@0.0.5 -237 silly lockFile 6aafaa92-npub-0-0-5 npub@0.0.5 -238 silly lockFile 9efb77d3-snc1-package-expect-js-0-2-0-tgz http://npm-registry.snc1/package/expect.js-0.2.0.tgz -239 silly lockFile 9efb77d3-snc1-package-expect-js-0-2-0-tgz http://npm-registry.snc1/package/expect.js-0.2.0.tgz -240 silly lockFile 8bd15c82-expect-js-0-2-0 expect.js@0.2.0 -241 silly lockFile 8bd15c82-expect-js-0-2-0 expect.js@0.2.0 -242 error notarget No compatible version found: mocha@'^~2.0.1' -242 error notarget Valid install targets: -242 error notarget ["0.0.1-alpha1","0.0.1-alpha2","0.0.1-alpha3","0.0.1-alpha4","0.0.1-alpha5","0.0.1-alpha6","0.0.1","0.0.2","0.0.3","0.0.4","0.0.5","0.0.6","0.0.7","0.0.8","0.1.0","0.2.0","0.3.0","0.3.2","0.3.3","0.3.4","0.3.6","0.4.0","0.6.0","0.7.0","0.7.1","0.8.0","0.8.1","0.9.0","0.10.0","0.10.1","0.11.0","0.12.0","0.12.1","0.13.0","1.0.1","1.0.2","1.0.3","1.1.0","1.2.0","1.2.1","1.2.2","1.3.0","1.4.3","1.5.0","1.6.0","1.7.0","1.7.1","1.7.2","1.7.4","1.8.0","1.8.1","1.8.2","1.9.0","1.10.0","1.11.0","1.12.0","1.12.1","1.13.0","1.14.0","1.15.1","1.16.0","1.16.1","1.16.2","1.17.0","1.17.1","1.18.1","1.18.2","1.19.0","1.20.0","1.20.1","1.21.0","1.3.1","1.21.3","1.21.4","1.4.0","0.5.0","1.18.0","1.4.1","0.10.2","1.7.3","1.3.2","1.21.5","1.21.1","0.3.1","1.15.0","2.0.0","0.14.1","2.0.1","0.14.0","1.0.0","1.4.2","1.21.2"] -242 error notarget -242 error notarget This is most likely not a problem with npm itself. -242 error notarget In most cases you or one of your dependencies are requesting -242 error notarget a package version that doesn't exist. -243 error System Darwin 13.4.0 -244 error command "/usr/local/opt/nvm/v0.10.33/bin/node" "/usr/local/opt/nvm/v0.10.33/bin/npm" "install" -245 error cwd /Users/kofi/thePoints/node-cached -246 error node -v v0.10.33 -247 error npm -v 1.4.28 -248 error code ETARGET -249 verbose exit [ 1, true ] From e41ec339fe68b973020fe4926d68eda705b6385d Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Mon, 17 Nov 2014 10:59:25 -0800 Subject: [PATCH 05/55] Changelog for 3.0.1 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5aad14..67ced2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +v3.0.1 +------ +* exchange cs (for csr) and lodash (for underscore) - @Kofia5 #8 + v3.0.0 ------ Upgrading to this version changes the key hashing. From 906af066490705c775441d4590b448c033f4f4f5 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Mon, 17 Nov 2014 10:59:28 -0800 Subject: [PATCH 06/55] 3.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93f9d3f..bb108b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cached", - "version": "3.0.0", + "version": "3.0.1", "description": "Simple access to a cache", "main": "lib/cached.js", "keywords": [ From 1c80f853a0c65965f86acfde1ae3992193e3c6bf Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Mon, 9 Feb 2015 13:26:28 -0800 Subject: [PATCH 07/55] Bringing this package into the future --- .travis.yml | 4 +- Makefile | 29 +---- examples/cached-usage.coffee | 32 +++++ examples/memcached.coffee | 32 +++++ examples/memory.coffee | 32 +++++ lib/backend.js | 21 ++-- lib/backends/memcached.js | 41 +++---- lib/backends/memory.js | 30 ++--- lib/backends/noop.js | 19 +-- lib/cache.js | 32 ++--- lib/cached.js | 24 ++-- package.json | 22 ++-- scripts/release.coffee | 26 ----- src/backend.coffee | 15 ++- src/backends/memcached.coffee | 26 +++-- src/backends/memory.coffee | 21 ++-- src/backends/noop.coffee | 8 +- src/cache.coffee | 32 ++--- src/cached.coffee | 19 +-- test/cache.coffee | 212 +++++++++++++++++++--------------- test/cached.coffee | 20 ++-- test/prefix.coffee | 20 ++-- 22 files changed, 395 insertions(+), 322 deletions(-) delete mode 100755 scripts/release.coffee diff --git a/.travis.yml b/.travis.yml index e3447bf..58c62fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - "0.8" - "0.10" - - "0.11" + - "0.12" + - "iojs" services: memcached diff --git a/Makefile b/Makefile index 7de55b0..c2850de 100644 --- a/Makefile +++ b/Makefile @@ -1,29 +1,10 @@ -COFFEE=node_modules/.bin/coffee -MOCHA=node_modules/.bin/mocha +.PHONY: clean setup -all: clean setup test check-checkout-clean - -build: - $(COFFEE) -cbo lib src - @./node_modules/.bin/npub prep lib - -prepublish: - ./node_modules/.bin/npub prep +setup: + npm install clean: - rm -rf lib rm -rf node_modules -test: build - $(MOCHA) - -release: all - git push --tags origin HEAD:master - npm publish - -setup: - npm install - -# This will fail if there are unstaged changes in the checkout -check-checkout-clean: - git diff --exit-code +release-%: clean setup + ./node_modules/.bin/npub publish $(subst release-,,$@) diff --git a/examples/cached-usage.coffee b/examples/cached-usage.coffee index 59484af..a47321f 100644 --- a/examples/cached-usage.coffee +++ b/examples/cached-usage.coffee @@ -1,3 +1,35 @@ +### +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. +### + # 1. Create a named cache # Once created, you can retrieve the same cache-instance later by # just calling `cached "divisions"` without any additional arguments. diff --git a/examples/memcached.coffee b/examples/memcached.coffee index 5028800..cfa77c4 100644 --- a/examples/memcached.coffee +++ b/examples/memcached.coffee @@ -1,3 +1,35 @@ +### +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. +### + cached = require '..' diff --git a/examples/memory.coffee b/examples/memory.coffee index 70d52ce..f577327 100644 --- a/examples/memory.coffee +++ b/examples/memory.coffee @@ -1,3 +1,35 @@ +### +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. +### + cached = require '..' diff --git a/lib/backend.js b/lib/backend.js index 2f35e3b..83d8831 100644 --- a/lib/backend.js +++ b/lib/backend.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.9.0 /* Copyright (c) 2014, Groupon, Inc. @@ -31,17 +31,16 @@ 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. */ -var backend, typeMap; +'use strict'; +var typeMap; -backend = module.exports = {}; +typeMap = Object.create(null); -typeMap = {}; - -backend.addType = function(type, klass) { +exports.addType = function(type, klass) { return typeMap[type] = klass; }; -backend.create = function(options) { +exports.create = function(options) { var klass, type, _ref; if (options == null) { options = {}; @@ -52,13 +51,13 @@ backend.create = function(options) { type = (_ref = options.type) != null ? _ref : 'noop'; klass = typeMap[type]; if (klass == null) { - throw new Error("" + type + " is not a supported cache backend type"); + throw new Error(type + " is not a supported cache backend type"); } return new klass(options); }; -backend.addType('noop', require("./backends/noop")); +exports.addType('noop', require("./backends/noop")); -backend.addType('memory', require("./backends/memory")); +exports.addType('memory', require("./backends/memory")); -backend.addType('memcached', require("./backends/memcached")); +exports.addType('memcached', require("./backends/memcached")); diff --git a/lib/backends/memcached.js b/lib/backends/memcached.js index c4fea37..90147d9 100644 --- a/lib/backends/memcached.js +++ b/lib/backends/memcached.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.9.0 /* Copyright (c) 2014, Groupon, Inc. @@ -31,10 +31,13 @@ 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. */ -var Memcached, MemcachedBackend; +'use strict'; +var Memcached, MemcachedBackend, promisify; Memcached = require('memcached'); +promisify = require('bluebird').promisify; + MemcachedBackend = (function() { var description; @@ -49,37 +52,31 @@ MemcachedBackend = (function() { hosts = (_ref = options.hosts) != null ? _ref : '127.0.0.1:11211'; this.client = new Memcached(hosts, options); } + this._clientGet = promisify(this.client.get, this.client); + this._clientSet = promisify(this.client.set, this.client); + this._clientDel = promisify(this.client.del, this.client); } - MemcachedBackend.prototype.get = function(key, callback) { - return this.client.get(key, function(err, answer) { + MemcachedBackend.prototype.get = function(key) { + return this._clientGet(key).then(function(answer) { if (answer === false) { - answer = null; - } - if (err != null) { - return callback(err); + return null; } else { - return callback(null, answer); + return answer; } }); }; - MemcachedBackend.prototype.set = function(key, value, options, callback) { - return this.client.set(key, value, options.expire, function(err, ok) { - if (err != null) { - return callback(err); - } else { - return callback(null, value); - } + MemcachedBackend.prototype.set = function(key, value, options) { + return this._clientSet(key, value, options.expire).then(function() { + return value; }); }; - MemcachedBackend.prototype.unset = function(key, callback) { - delete this.cache[key]; - if (callback != null) { - callback(null); - } - return null; + MemcachedBackend.prototype.unset = function(key) { + return this._clientDel(key).then(function() { + return void 0; + }); }; MemcachedBackend.prototype.end = function() { diff --git a/lib/backends/memory.js b/lib/backends/memory.js index b4de49d..8de4ab7 100644 --- a/lib/backends/memory.js +++ b/lib/backends/memory.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.9.0 /* Copyright (c) 2014, Groupon, Inc. @@ -31,7 +31,10 @@ 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. */ -var MemoryBackend; +'use strict'; +var MemoryBackend, Promise; + +Promise = require('bluebird'); MemoryBackend = (function() { var description; @@ -39,19 +42,16 @@ MemoryBackend = (function() { description = "Stores everything just in memory"; function MemoryBackend() { - this.cache = {}; + this.cache = Object.create(null); this.type = 'memory'; } - MemoryBackend.prototype.get = function(key, callback) { + MemoryBackend.prototype.get = function(key) { var _ref, _ref1, _ref2; if (this.isExpired((_ref = this.cache[key]) != null ? _ref.e : void 0)) { delete this.cache[key]; } - if (callback != null) { - callback(null, (_ref1 = (_ref2 = this.cache[key]) != null ? _ref2.d : void 0) != null ? _ref1 : null); - } - return null; + return Promise.resolve((_ref1 = (_ref2 = this.cache[key]) != null ? _ref2.d : void 0) != null ? _ref1 : null); }; MemoryBackend.prototype.expiresAt = function(seconds) { @@ -72,23 +72,17 @@ MemoryBackend = (function() { return (new Date()).getTime() > (new Date(expires)).getTime(); }; - MemoryBackend.prototype.set = function(key, value, options, callback) { + MemoryBackend.prototype.set = function(key, value, options) { this.cache[key] = { d: value, e: this.expiresAt(options.expire) }; - if (callback != null) { - callback(null, value); - } - return null; + return Promise.resolve(value); }; - MemoryBackend.prototype.unset = function(key, callback) { + MemoryBackend.prototype.unset = function(key) { delete this.cache[key]; - if (callback != null) { - callback(null); - } - return null; + return Promise.resolve(); }; return MemoryBackend; diff --git a/lib/backends/noop.js b/lib/backends/noop.js index 659ee29..dcc4158 100644 --- a/lib/backends/noop.js +++ b/lib/backends/noop.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.9.0 /* Copyright (c) 2014, Groupon, Inc. @@ -31,7 +31,10 @@ 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. */ -var NoopBackend; +'use strict'; +var NoopBackend, Promise; + +Promise = require('bluebird'); NoopBackend = (function() { var description; @@ -42,16 +45,16 @@ NoopBackend = (function() { this.type = 'noop'; } - NoopBackend.prototype.get = function(key, callback) { - return callback(null, null); + NoopBackend.prototype.get = function(key) { + return Promise.resolve(null); }; - NoopBackend.prototype.set = function(key, value, options, callback) { - return callback(null, value); + NoopBackend.prototype.set = function(key, value) { + return Promise.resolve(value); }; - NoopBackend.prototype.unset = function(key, callback) { - return callback(null); + NoopBackend.prototype.unset = function(key) { + return Promise.resolve(); }; return NoopBackend; diff --git a/lib/cache.js b/lib/cache.js index 1ee1dc9..a1987fc 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.9.0 /* Copyright (c) 2014, Groupon, Inc. @@ -31,19 +31,20 @@ 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. */ -var Backend, Cache, Q, expiresAt, extend, isExpired, optionalOpts, toPromise; +'use strict'; +var Backend, Cache, Promise, expiresAt, extend, isExpired, optionalOpts, toPromise; extend = require('lodash').extend; -Q = require('q'); +Promise = require('bluebird'); Backend = require('./backend'); toPromise = function(val) { if ('function' === typeof val) { - return Q(val()); + return Promise.resolve(val()); } else { - return Q(val); + return Promise.resolve(val); } }; @@ -85,7 +86,7 @@ Cache = (function() { expire: 0 }; this.name = name || 'default'; - this.prefix = "" + this.name + ":"; + this.prefix = this.name + ":"; this.staleOrPending = {}; this.setDefaults(defaults); this.setBackend(backend); @@ -119,23 +120,22 @@ Cache = (function() { }; Cache.prototype.set = function(key, val, opts, cb) { - var backend, _ref; + var _ref; _ref = optionalOpts(opts, cb), cb = _ref.cb, opts = _ref.opts; key = this.applyPrefix(key); - backend = this.backend; opts = this.prepareOptions(opts); - return toPromise(val).then(function(resolvedValue) { - var wrappedValue; - wrappedValue = { - b: expiresAt(opts.freshFor), - d: resolvedValue + return toPromise(val).then((function(_this) { + return function(resolvedValue) { + return _this.backend.set(key, { + b: expiresAt(opts.freshFor), + d: resolvedValue + }, opts); }; - return Q.npost(backend, 'set', [key, wrappedValue, opts]); - }).nodeify(cb); + })(this)).nodeify(cb); }; Cache.prototype.getWrapped = function(key) { - return Q.npost(this.backend, 'get', [key]); + return this.backend.get(key); }; Cache.prototype.get = function(rawKey, cb) { diff --git a/lib/cached.js b/lib/cached.js index 4da566b..c26f25f 100644 --- a/lib/cached.js +++ b/lib/cached.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.9.0 /* Copyright (c) 2014, Groupon, Inc. @@ -31,20 +31,16 @@ 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. */ -var Cache, Q, cached, extend, namedCaches; +'use strict'; +var Cache, Promise, cached, extend, namedCaches; -try { - Q = require('../node_modules/q'); - Q.stopUnhandledRejectionTracking(); -} catch (_error) { - Q = require('q'); -} - -Cache = require('./cache'); +Promise = require('bluebird'); extend = require('lodash').extend; -namedCaches = {}; +Cache = require('./cache'); + +namedCaches = Object.create(null); cached = function(name, options) { if (name == null) { @@ -67,7 +63,7 @@ cached.createCache = function(options) { }; cached.dropNamedCaches = function() { - namedCaches = {}; + namedCaches = Object.create(null); return cached; }; @@ -81,9 +77,7 @@ cached.knownCaches = function() { }; cached.deferred = function(fn) { - return function() { - return Q.nfcall(fn); - }; + return Promise.promisify(fn); }; module.exports = cached; diff --git a/package.json b/package.json index bb108b2..7504419 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,12 @@ "cache" ], "scripts": { - "test": "make test" + "build": "coffee -cbo lib src", + "watch": "coffee -wcbo lib src", + "prepublish": "rm -rf lib && npm run build", + "pretest": "npm run build", + "test": "mocha", + "posttest": "npub verify" }, "repository": { "type": "git", @@ -29,15 +34,14 @@ } }, "dependencies": { - "lodash": "~2.4.1", - "memcached": "~2.0.0", - "q": "~0.9.7" + "bluebird": "^2.9.7", + "lodash": "^3.1.0", + "memcached": "^2.1.0" }, "devDependencies": { - "bondjs": "~1.0.0", - "coffee-script": "~1.8.0", - "expect.js": "~0.2.0", - "mocha": "~2.0.1", - "npub": "0.0.5" + "assertive": "^1.4.1", + "coffee-script": "^1.9.0", + "mocha": "^2.0.1", + "npub": "~0.5.1" } } diff --git a/scripts/release.coffee b/scripts/release.coffee deleted file mode 100755 index 5437772..0000000 --- a/scripts/release.coffee +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env coffee -{exec} = require 'child_process' -moduleInfo = require '../package.json' - -versionTag = 'v' + moduleInfo.version - -console.log "Releasing #{moduleInfo.name} #{versionTag}\n" - -findTagCmd = "git tag | grep #{versionTag}" -exec findTagCmd, (err, stdout, stderr) -> - if not err? - throw new Error("Version #{versionTag} already exists") - - # push to default remote - pushToRemoteCmd = "git push" - console.log '* Pushing latest changes...' - exec pushToRemoteCmd, (err, stdout, stderr) -> - if err? - throw new Error("Could not push. Do you have a default remote?") - - console.log '* Tag version and push tags...' - makeTagCmd = "git tag #{versionTag} && git push --tags" - exec makeTagCmd, (err) -> - if err? - throw new Error("Failed to tag & push to remote") - console.log "\n=> Published version #{versionTag}\n" diff --git a/src/backend.coffee b/src/backend.coffee index d261896..97468cd 100644 --- a/src/backend.coffee +++ b/src/backend.coffee @@ -29,13 +29,12 @@ 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. ### +'use strict' +typeMap = Object.create null -backend = module.exports = {} -typeMap = {} +exports.addType = (type, klass) -> typeMap[type] = klass -backend.addType = (type, klass) -> typeMap[type] = klass - -backend.create = (options) -> +exports.create = (options) -> options ?= {} # make the whole thing idempotent @@ -47,6 +46,6 @@ backend.create = (options) -> throw new Error("#{type} is not a supported cache backend type") unless klass? new klass(options) -backend.addType 'noop', require("./backends/noop") -backend.addType 'memory', require("./backends/memory") -backend.addType 'memcached', require("./backends/memcached") +exports.addType 'noop', require("./backends/noop") +exports.addType 'memory', require("./backends/memory") +exports.addType 'memcached', require("./backends/memcached") diff --git a/src/backends/memcached.coffee b/src/backends/memcached.coffee index 077ae4e..697fa82 100644 --- a/src/backends/memcached.coffee +++ b/src/backends/memcached.coffee @@ -29,8 +29,9 @@ 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. ### - +'use strict' Memcached = require 'memcached' +{promisify} = require 'bluebird' class MemcachedBackend description = "Uses anything supporting the memcache protocol" @@ -44,19 +45,20 @@ class MemcachedBackend hosts = options.hosts ? '127.0.0.1:11211' @client = new Memcached hosts, options - get: (key, callback) -> - @client.get key, (err, answer) -> - answer = null if answer == false - if err? then callback(err) else callback(null, answer) + @_clientGet = promisify @client.get, @client + @_clientSet = promisify @client.set, @client + @_clientDel = promisify @client.del, @client + + get: (key) -> + @_clientGet(key).then (answer) -> + if answer == false then null + else answer - set: (key, value, options, callback) -> - @client.set key, value, options.expire, (err, ok) -> - if err? then callback(err) else callback(null, value) + set: (key, value, options) -> + @_clientSet(key, value, options.expire).then -> value - unset: (key, callback) -> - delete @cache[key] - callback(null) if callback? - null + unset: (key) -> + @_clientDel(key).then -> undefined end: -> @client.end() diff --git a/src/backends/memory.coffee b/src/backends/memory.coffee index d6d6451..2e65524 100644 --- a/src/backends/memory.coffee +++ b/src/backends/memory.coffee @@ -29,18 +29,21 @@ 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. ### +'use strict' +Promise = require 'bluebird' class MemoryBackend description = "Stores everything just in memory" - constructor: -> @cache = {}; @type = 'memory' + constructor: -> + @cache = Object.create null + @type = 'memory' - get: (key, callback) -> + get: (key) -> if @isExpired(@cache[key]?.e) delete @cache[key] # make sure it does not exist - callback(null, @cache[key]?.d ? null) if callback? - null + Promise.resolve(@cache[key]?.d ? null) expiresAt: (seconds) -> if seconds is 0 then 0 @@ -52,17 +55,15 @@ class MemoryBackend # "now is greater than expires" return (new Date()).getTime() > (new Date(expires)).getTime() - set: (key, value, options, callback) -> + set: (key, value, options) -> @cache[key] = d: value e: @expiresAt(options.expire) - callback(null, value) if callback? - null + Promise.resolve value - unset: (key, callback) -> + unset: (key) -> delete @cache[key] - callback(null) if callback? - null + Promise.resolve() module.exports = MemoryBackend diff --git a/src/backends/noop.coffee b/src/backends/noop.coffee index 9402e73..7d21467 100644 --- a/src/backends/noop.coffee +++ b/src/backends/noop.coffee @@ -29,14 +29,16 @@ 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. ### +'use strict' +Promise = require 'bluebird' class NoopBackend description = "Simple backend doing nothing" constructor: -> @type = 'noop' - get: (key, callback) -> callback(null, null) - set: (key, value, options, callback) -> callback(null, value) - unset: (key, callback) -> callback(null) + get: (key) -> Promise.resolve(null) + set: (key, value) -> Promise.resolve(value) + unset: (key) -> Promise.resolve() module.exports = NoopBackend diff --git a/src/cache.coffee b/src/cache.coffee index 44c8dd6..efdce17 100644 --- a/src/cache.coffee +++ b/src/cache.coffee @@ -29,16 +29,17 @@ 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. ### - +'use strict' {extend} = require 'lodash' -Q = require 'q' +Promise = require 'bluebird' + Backend = require './backend' toPromise = (val) -> # If val is a function, evaluate it first, convert into promise afterwards if 'function' is typeof val - Q val() - else Q val + Promise.resolve val() + else Promise.resolve val expiresAt = (seconds) -> if seconds is 0 then 0 @@ -95,16 +96,15 @@ class Cache key = @applyPrefix key - backend = @backend opts = @prepareOptions opts - toPromise(val).then( (resolvedValue) -> - wrappedValue = - b: expiresAt(opts.freshFor) - d: resolvedValue - - Q.npost backend, 'set', [ key, wrappedValue, opts ] - ).nodeify cb + toPromise(val) + .then (resolvedValue) => + @backend.set key, { + b: expiresAt(opts.freshFor) + d: resolvedValue + }, opts + .nodeify cb # Every value we cache is wrapped to enable graceful expire: # { @@ -114,15 +114,15 @@ class Cache # This allows us to have stale values stored in the cache and fetch a # replacement in the background. getWrapped: (key) -> - Q.npost(@backend, 'get', [ key ]) + @backend.get key get: (rawKey, cb) -> key = @applyPrefix rawKey - @getWrapped(key).then( - (wrappedValue) -> + @getWrapped(key) + .then (wrappedValue) -> # blindly return the wrapped value, ignoring freshness wrappedValue?.d ? null - ).nodeify cb + .nodeify cb # Get from a cache or generate if not present or stale. # A value is stale when it was generated more than `freshFor` seconds ago diff --git a/src/cached.coffee b/src/cached.coffee index 98688e8..098b789 100644 --- a/src/cached.coffee +++ b/src/cached.coffee @@ -29,19 +29,13 @@ 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. ### - -try - # This makes sure we don't spam the CPU if we have our own Q - Q = require '../node_modules/q' - Q.stopUnhandledRejectionTracking() -catch - Q = require 'q' +'use strict' +Promise = require 'bluebird' +{extend} = require 'lodash' Cache = require './cache' -{extend} = require 'lodash' - -namedCaches = {} +namedCaches = Object.create null cached = (name="default", options={}) -> options = extend { name }, options @@ -51,7 +45,7 @@ cached.createCache = (options={}) -> new Cache(options) cached.dropNamedCaches = () -> - namedCaches = {} + namedCaches = Object.create null return cached cached.dropNamedCache = (name) -> @@ -64,7 +58,6 @@ cached.knownCaches = -> cached.deferred = (fn) -> # a simple function that returns a promise of the execution of a # given nodejs callback-style function `fn` - -> - Q.nfcall fn + Promise.promisify fn module.exports = cached diff --git a/test/cache.coffee b/test/cache.coffee index bf119c8..19fd2c0 100644 --- a/test/cache.coffee +++ b/test/cache.coffee @@ -1,89 +1,93 @@ +'use strict' +assert = require 'assertive' -expect = require 'expect.js' -bond = require 'bondjs' - -Q = require 'q' +Promise = require 'bluebird' {defaults} = require 'lodash' Cache = require '../lib/cache' cached = require '../lib/cached' -cache = null values = key1: 'Value 1' key2: 'Value 2' key3: 'Value 3' backendOptions = - hosts: if process.env.MEMCACHED__HOST then "#{process.env.MEMCACHED__HOST}:11211" else '127.0.0.1:11211' + hosts: + if process.env.MEMCACHED__HOST + "#{process.env.MEMCACHED__HOST}:11211" + else + '127.0.0.1:11211' -wait = (ms) -> - deferred = Q.defer() - setTimeout deferred.resolve, ms - deferred.promise +waterfall = (fns) -> + next = (prev, fn) -> prev.then fn + fns.reduce next, Promise.resolve() describe 'Cache', -> it 'always has a backend', -> cache = new Cache {} - expect(cache.backend).not.to.be undefined + assert.notEqual undefined, cache.backend it 'has a "noop" backend by default', -> cache = new Cache {} - expect(cache.backend.type).to.equal 'noop' + assert.equal 'noop', cache.backend.type describe 'Cache#set', -> beforeEach -> - cache = new Cache backend: 'memory' + @cache = new Cache backend: 'memory' it 'supports callback style', (done) -> - cache.set 'key1', values.key1, done + @cache.set 'key1', values.key1, done it 'supports promise style', (done) -> - cache.set('key2', values.key2, { expire: 1 }).nodeify done + @cache.set('key2', values.key2, { expire: 1 }).nodeify done [ 'memory', 'memcached' ].map (backendType) -> describe "with backend \"#{backendType}\"", -> - - beforeEach -> - cache = new Cache backend: defaults({ type: backendType }, backendOptions), name: 'awesome-name', debug: true - afterEach -> - cache.end() + before -> + @cache = new Cache backend: defaults({ type: backendType }, backendOptions), name: 'awesome-name', debug: true + after -> + @cache.end() describe 'Cache#get', -> - it 'gets a previously set key', (done) -> - [ - -> - cache.set 'key1', values.key1 - -> cache.get 'key1' + it 'gets a previously set key', -> + waterfall [ + => + @cache.set 'key1', values.key1 + => + @cache.get 'key1' (val) -> - expect(val).to.be values.key1 - ].reduce(Q.when, Q()).nodeify done - - it 'is aware of expires', (done) -> - [ - -> Q.all [ - cache.set 'key1', values.key1, expire: 1 - cache.set 'key2', values.key2, expire: 0 - cache.set 'key3', values.key3, expire: 4 + assert.equal values.key1, val + ] + + it 'is aware of expires', -> + stored = Promise.all [ + @cache.set 'key1', values.key1, expire: 1 + @cache.set 'key2', values.key2, expire: 0 + @cache.set 'key3', values.key3, expire: 4 + ] + + retrieve = stored.delay(2000).then => + Promise.all [ + @cache.get 'key1' + @cache.get 'key2' + @cache.get 'key3' ] - -> wait 2000 - -> Q.all [ - cache.get 'key1' - cache.get 'key2' - cache.get 'key3' - ] - ([ val1, val2, val3 ]) -> - expect(val1).to.be null # less than 2 seconds lifetime - expect(val2).to.equal values.key2 # eternal lifetime - expect(val3).to.equal values.key3 # more than 2 seconds lifetime - ].reduce(Q.when, Q()).nodeify done + + retrieve.spread (val1, val2, val3) -> + # less than 2 seconds lifetime + assert.equal null, val1 + # eternal lifetime + assert.equal values.key2, val2 + # more than 2 seconds lifetime + assert.equal values.key3, val3 describe 'Cache#getOrElse', -> - it 'replaces values lazily', (done) -> + it 'replaces values lazily', -> generatorCalled = 0 # generate a value in a certain time valueGenerator = (v, ms) -> -> ++generatorCalled - Q.delay(ms).then -> v + Promise.resolve(v).delay(ms) originalValue = values.key1 generatedValue = 'G1' @@ -107,60 +111,84 @@ describe 'Cache', -> # - return immediately with the stale value # * After generating the value is done we call #getOrElse a 3rd time. We should # be getting the generated value and not be starting another generator - [ - -> cache.set 'key1', originalValue, freshFor: 1 - -> wait 1200 - -> cache.get('key1') - (v) -> expect(v).to.be originalValue + waterfall [ + => + @cache.set 'key1', originalValue, freshFor: 1 + -> + Promise.delay 1200 + => + @cache.get('key1') + (v) -> + assert.equal originalValue, v - -> cache.getOrElse 'key1', valueGenerator(generatedValue, 100), freshFor: 5 + => + @cache.getOrElse 'key1', valueGenerator(generatedValue, 100), freshFor: 5 (v) -> - expect(v).to.be originalValue - -> wait 50 # while generating - -> cache.getOrElse 'key1', valueGenerator('G2', 5000), freshFor: 5 + assert.equal originalValue, v + -> + Promise.delay 50 # while generating + => + @cache.getOrElse 'key1', valueGenerator('G2', 5000), freshFor: 5 (v) -> - expect(v).to.be originalValue - -> wait 100 - -> cache.getOrElse 'key1', valueGenerator('G3', 5000), freshFor: 5 + assert.equal originalValue, v + -> + Promise.delay 100 + => + @cache.getOrElse 'key1', valueGenerator('G3', 5000), freshFor: 5 (v) -> - expect(v).to.be generatedValue - expect(generatorCalled).to.be 1 - ].reduce(Q.when, Q()).nodeify done + assert.equal generatedValue, v + assert.equal 1, generatorCalled + ] it 'throws errors', (done) -> errorGenerator = cached.deferred (cb) -> cb new Error 'Big Error' theCallback = (err, data) -> - expect(err) - expect(err.message).to.be 'Big Error' - expect(data).to.be undefined + assert.equal 'Big Error', err?.message + assert.equal undefined, data done() - cache.getOrElse 'bad_keys', errorGenerator, freshFor: 1, theCallback - - it 'handles thrown get errors by falling back on the value refresher', (done) -> - valueGenerator = cached.deferred (cb) -> - cb null, 'fresh cats' - - theCallback = (err, data) -> - expect(err).to.be null - expect(data).to.be 'fresh cats' - done() - - bond(cache, 'getWrapped').return Q.reject new Error('backend get troubles') - - cache.getOrElse 'bad_get', valueGenerator, freshFor: 5, theCallback - - it 'handles thrown set errors by falling back on the generated value', (done) -> - valueGenerator = cached.deferred (cb) -> - cb null, 'generated bunnies' - - theCallback = (err, data) -> - expect(err).to.be null - expect(data).to.be 'generated bunnies' - done() - - bond(cache, 'set').return Q.reject new Error('backend set troubles') - - cache.getOrElse 'bad_set', valueGenerator, freshFor: 5, theCallback + @cache.getOrElse 'bad_keys', errorGenerator, freshFor: 1, theCallback + + describe 'backed.get failing', -> + before -> + @failCache = new Cache { + backend: @cache.backend + name: 'awesome-name' + debug: true + } + @failCache.getWrapped = -> + Promise.reject new Error('backend get troubles') + + it 'falls back on the value refresher', (done) -> + valueGenerator = cached.deferred (cb) -> + cb null, 'fresh cats' + + theCallback = (err, data) -> + assert.equal null, err + assert.equal 'fresh cats', data + done() + + @failCache.getOrElse 'bad_get', valueGenerator, freshFor: 5, theCallback + + describe 'backend.set failing', -> + before -> + @failCache = new Cache { + backend: @cache.backend + name: 'awesome-name' + debug: true + } + @failCache.set = -> + Promise.reject new Error('backend set troubles') + + it 'falls back on the generated value', (done) -> + valueGenerator = cached.deferred (cb) -> + cb null, 'generated bunnies' + + theCallback = (err, data) -> + assert.equal null, err + assert.equal 'generated bunnies', data + done() + + @failCache.getOrElse 'bad_set', valueGenerator, freshFor: 5, theCallback diff --git a/test/cached.coffee b/test/cached.coffee index d041d7d..ebee424 100644 --- a/test/cached.coffee +++ b/test/cached.coffee @@ -1,5 +1,5 @@ - -expect = require 'expect.js' +'use strict' +assert = require 'assertive' cached = require '..' @@ -8,18 +8,20 @@ describe 'cached', -> cached.dropNamedCaches() it 'is a function', -> - expect(typeof cached).to.be 'function' + assert.hasType Function, cached it 'can create different named caches', -> - expect(cached('foo')).not.to.be(cached('bar')) - expect(cached('foo')).not.to.be(cached()) - expect(cached.knownCaches()).to.eql [ 'foo', 'bar', 'default' ] + assert.notEqual cached('bar'), cached('foo') + assert.notEqual cached(), cached('foo') + assert.deepEqual [ + 'bar', 'foo', 'default' + ], cached.knownCaches() it 'the default cache is named "default"', -> - expect(cached()).to.be(cached('default')) + assert.equal cached('default'), cached() it 'returns the same named cache for subsequent calls', -> - expect(cached('foo')).to.be(cached('foo')) + assert.equal cached('foo'), cached('foo') it 'knows no caches', -> - expect(cached.knownCaches()).to.eql [] + assert.deepEqual [], cached.knownCaches() diff --git a/test/prefix.coffee b/test/prefix.coffee index c6d9bf0..2ff1aef 100644 --- a/test/prefix.coffee +++ b/test/prefix.coffee @@ -1,11 +1,15 @@ - -expect = require 'expect.js' -Q = require 'q' +'use strict' +assert = require 'assertive' +Promise = require 'bluebird' cached = require '..' +waterfall = (fns) -> + next = (prev, fn) -> prev.then fn + fns.reduce next, Promise.resolve() + describe 'cache prefix', -> - it 'adds a prefix to named caches', (done) -> + it 'adds a prefix to named caches', -> cacheA = cached 'a', backend: { type: 'memory' } cacheB = cached 'b' # simulate "writing to the same store" @@ -14,11 +18,11 @@ describe 'cache prefix', -> aValue = 'a-value' bValue = 'b-value' - [ + waterfall [ -> cacheA.set 'key', aValue -> cacheB.set 'key', bValue -> cacheA.get 'key' - (v) -> expect(v).to.be(aValue) + (v) -> assert.equal aValue, v -> cacheB.get 'key' - (v) -> expect(v).to.be(bValue) - ].reduce(Q.when, Q()).nodeify done + (v) -> assert.equal bValue, v + ] From 541ae83d109458954bceadcf3bb3dc6b004779d1 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 20 Feb 2015 16:13:45 -0800 Subject: [PATCH 08/55] Recompiled using cs 1.9.1 --- lib/backend.js | 6 +++--- lib/backends/memcached.js | 6 +++--- lib/backends/memory.js | 8 ++++---- lib/backends/noop.js | 2 +- lib/cache.js | 30 +++++++++++++++--------------- lib/cached.js | 2 +- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/backend.js b/lib/backend.js index 83d8831..07575cf 100644 --- a/lib/backend.js +++ b/lib/backend.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.0 +// Generated by CoffeeScript 1.9.1 /* Copyright (c) 2014, Groupon, Inc. @@ -41,14 +41,14 @@ exports.addType = function(type, klass) { }; exports.create = function(options) { - var klass, type, _ref; + var klass, ref, type; if (options == null) { options = {}; } if ('function' === typeof options.get && 'function' === typeof options.set) { return options; } - type = (_ref = options.type) != null ? _ref : 'noop'; + type = (ref = options.type) != null ? ref : 'noop'; klass = typeMap[type]; if (klass == null) { throw new Error(type + " is not a supported cache backend type"); diff --git a/lib/backends/memcached.js b/lib/backends/memcached.js index 90147d9..294a591 100644 --- a/lib/backends/memcached.js +++ b/lib/backends/memcached.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.0 +// Generated by CoffeeScript 1.9.1 /* Copyright (c) 2014, Groupon, Inc. @@ -44,12 +44,12 @@ MemcachedBackend = (function() { description = "Uses anything supporting the memcache protocol"; function MemcachedBackend(options) { - var hosts, _ref; + var hosts, ref; this.type = 'memcached'; if (options.client != null) { this.client = options.client; } else { - hosts = (_ref = options.hosts) != null ? _ref : '127.0.0.1:11211'; + hosts = (ref = options.hosts) != null ? ref : '127.0.0.1:11211'; this.client = new Memcached(hosts, options); } this._clientGet = promisify(this.client.get, this.client); diff --git a/lib/backends/memory.js b/lib/backends/memory.js index 8de4ab7..a17db45 100644 --- a/lib/backends/memory.js +++ b/lib/backends/memory.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.0 +// Generated by CoffeeScript 1.9.1 /* Copyright (c) 2014, Groupon, Inc. @@ -47,11 +47,11 @@ MemoryBackend = (function() { } MemoryBackend.prototype.get = function(key) { - var _ref, _ref1, _ref2; - if (this.isExpired((_ref = this.cache[key]) != null ? _ref.e : void 0)) { + var ref, ref1, ref2; + if (this.isExpired((ref = this.cache[key]) != null ? ref.e : void 0)) { delete this.cache[key]; } - return Promise.resolve((_ref1 = (_ref2 = this.cache[key]) != null ? _ref2.d : void 0) != null ? _ref1 : null); + return Promise.resolve((ref1 = (ref2 = this.cache[key]) != null ? ref2.d : void 0) != null ? ref1 : null); }; MemoryBackend.prototype.expiresAt = function(seconds) { diff --git a/lib/backends/noop.js b/lib/backends/noop.js index dcc4158..65e3975 100644 --- a/lib/backends/noop.js +++ b/lib/backends/noop.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.0 +// Generated by CoffeeScript 1.9.1 /* Copyright (c) 2014, Groupon, Inc. diff --git a/lib/cache.js b/lib/cache.js index a1987fc..146bb80 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.0 +// Generated by CoffeeScript 1.9.1 /* Copyright (c) 2014, Groupon, Inc. @@ -78,9 +78,9 @@ optionalOpts = function(opts, cb) { }; Cache = (function() { - function Cache(_arg) { + function Cache(arg) { var backend, defaults, name; - backend = _arg.backend, defaults = _arg.defaults, name = _arg.name; + backend = arg.backend, defaults = arg.defaults, name = arg.name; this.defaults = { freshFor: 0, expire: 0 @@ -109,8 +109,8 @@ Cache = (function() { }; Cache.prototype.end = function() { - var _ref; - if (((_ref = this.backend) != null ? _ref.end : void 0) != null) { + var ref; + if (((ref = this.backend) != null ? ref.end : void 0) != null) { return this.backend.end(); } }; @@ -120,8 +120,8 @@ Cache = (function() { }; Cache.prototype.set = function(key, val, opts, cb) { - var _ref; - _ref = optionalOpts(opts, cb), cb = _ref.cb, opts = _ref.opts; + var ref; + ref = optionalOpts(opts, cb), cb = ref.cb, opts = ref.opts; key = this.applyPrefix(key); opts = this.prepareOptions(opts); return toPromise(val).then((function(_this) { @@ -142,24 +142,24 @@ Cache = (function() { var key; key = this.applyPrefix(rawKey); return this.getWrapped(key).then(function(wrappedValue) { - var _ref; - return (_ref = wrappedValue != null ? wrappedValue.d : void 0) != null ? _ref : null; + var ref; + return (ref = wrappedValue != null ? wrappedValue.d : void 0) != null ? ref : null; }).nodeify(cb); }; Cache.prototype.getOrElse = function(rawKey, val, opts, cb) { - var handleError, key, refreshValue, verifyFreshness, _ref; + var handleError, key, ref, refreshValue, verifyFreshness; key = this.applyPrefix(rawKey); - _ref = optionalOpts(opts, cb), cb = _ref.cb, opts = _ref.opts; + ref = optionalOpts(opts, cb), cb = ref.cb, opts = ref.opts; opts = this.prepareOptions(opts); refreshValue = (function(_this) { return function() { var generatedValue; generatedValue = toPromise(val); return _this.set(rawKey, generatedValue, opts).then(function(rawValue) { - var _ref1; + var ref1; delete _this.staleOrPending[key]; - return (_ref1 = rawValue != null ? rawValue.d : void 0) != null ? _ref1 : null; + return (ref1 = rawValue != null ? rawValue.d : void 0) != null ? ref1 : null; }, function(err) { delete _this.staleOrPending[key]; return generatedValue != null ? generatedValue : null; @@ -168,14 +168,14 @@ Cache = (function() { })(this); verifyFreshness = (function(_this) { return function(wrappedValue) { - var expired, hit, loadingNewValue, _ref1; + var expired, hit, loadingNewValue, ref1; hit = wrappedValue != null; expired = isExpired(wrappedValue != null ? wrappedValue.b : void 0); loadingNewValue = _this.staleOrPending[key] != null; if ((!hit || expired) && !loadingNewValue) { _this.staleOrPending[key] = refreshValue(); } - return (_ref1 = wrappedValue != null ? wrappedValue.d : void 0) != null ? _ref1 : _this.staleOrPending[key]; + return (ref1 = wrappedValue != null ? wrappedValue.d : void 0) != null ? ref1 : _this.staleOrPending[key]; }; })(this); handleError = function(error) { diff --git a/lib/cached.js b/lib/cached.js index c26f25f..bc3de95 100644 --- a/lib/cached.js +++ b/lib/cached.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.0 +// Generated by CoffeeScript 1.9.1 /* Copyright (c) 2014, Groupon, Inc. From 09fd4b2537be126381ae74861b64c5da8ed8a701 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Mon, 23 Feb 2015 10:03:15 -0800 Subject: [PATCH 09/55] npub wants an empty line after the license --- src/backend.coffee | 1 + src/backends/memcached.coffee | 1 + src/backends/memory.coffee | 1 + src/backends/noop.coffee | 1 + src/cache.coffee | 1 + src/cached.coffee | 1 + 6 files changed, 6 insertions(+) diff --git a/src/backend.coffee b/src/backend.coffee index 97468cd..5d54e84 100644 --- a/src/backend.coffee +++ b/src/backend.coffee @@ -29,6 +29,7 @@ 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. ### + 'use strict' typeMap = Object.create null diff --git a/src/backends/memcached.coffee b/src/backends/memcached.coffee index 697fa82..021ff6a 100644 --- a/src/backends/memcached.coffee +++ b/src/backends/memcached.coffee @@ -29,6 +29,7 @@ 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. ### + 'use strict' Memcached = require 'memcached' {promisify} = require 'bluebird' diff --git a/src/backends/memory.coffee b/src/backends/memory.coffee index 2e65524..cec4f7c 100644 --- a/src/backends/memory.coffee +++ b/src/backends/memory.coffee @@ -29,6 +29,7 @@ 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. ### + 'use strict' Promise = require 'bluebird' diff --git a/src/backends/noop.coffee b/src/backends/noop.coffee index 7d21467..3ece0d0 100644 --- a/src/backends/noop.coffee +++ b/src/backends/noop.coffee @@ -29,6 +29,7 @@ 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. ### + 'use strict' Promise = require 'bluebird' diff --git a/src/cache.coffee b/src/cache.coffee index efdce17..2fe6e7d 100644 --- a/src/cache.coffee +++ b/src/cache.coffee @@ -29,6 +29,7 @@ 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. ### + 'use strict' {extend} = require 'lodash' Promise = require 'bluebird' diff --git a/src/cached.coffee b/src/cached.coffee index 098b789..49dd757 100644 --- a/src/cached.coffee +++ b/src/cached.coffee @@ -29,6 +29,7 @@ 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. ### + 'use strict' Promise = require 'bluebird' {extend} = require 'lodash' From 3e2bd99bb8808789932b9c0d3c539622ff42ed58 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Mon, 23 Feb 2015 10:14:19 -0800 Subject: [PATCH 10/55] v4.0.0 --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67ced2b..5b3d50a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +4.0.0 +----- +* Recompiled using cs 1.9.1 - @jkrems #11 +* Bringing this package into the future, io.js support - @jkrems #10 + v3.0.1 ------ * exchange cs (for csr) and lodash (for underscore) - @Kofia5 #8 diff --git a/package.json b/package.json index 7504419..810b09f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cached", - "version": "3.0.1", + "version": "4.0.0", "description": "Simple access to a cache", "main": "lib/cached.js", "keywords": [ From 8d44048d632525d9963afef667b44e2518676069 Mon Sep 17 00:00:00 2001 From: Chris Khoo Date: Mon, 9 Mar 2015 21:13:48 -0700 Subject: [PATCH 11/55] Fixing memcached.set slowness Fixes #14 --- lib/cache.js | 2 +- src/cache.coffee | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/cache.js b/lib/cache.js index 146bb80..60c9411 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -93,7 +93,7 @@ Cache = (function() { } Cache.prototype.applyPrefix = function(key) { - return "" + this.prefix + key; + return [this.prefix, key].join(''); }; Cache.prototype.setDefaults = function(defaults) { diff --git a/src/cache.coffee b/src/cache.coffee index 2fe6e7d..036e2da 100644 --- a/src/cache.coffee +++ b/src/cache.coffee @@ -71,7 +71,10 @@ class Cache @setDefaults defaults @setBackend backend - applyPrefix: (key) -> "#{@prefix}#{key}" + applyPrefix: (key) -> + [ @prefix, key ].join '' + # don't refactor the above line to a concatenation + # see https://github.com/3rd-Eden/node-memcached/pull/205 for details setDefaults: (defaults) -> @defaults = @prepareOptions defaults From eeca16d913d76dfcb00d8871ee61e98fd6e3e53c Mon Sep 17 00:00:00 2001 From: Chris Khoo Date: Tue, 10 Mar 2015 10:54:02 -0700 Subject: [PATCH 12/55] v4.0.1 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b3d50a..9ca6414 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +4.0.1 +----- +* Fixing memcached.set slowness - @chkhoo #15 + 4.0.0 ----- * Recompiled using cs 1.9.1 - @jkrems #11 diff --git a/package.json b/package.json index 810b09f..468ceb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cached", - "version": "4.0.0", + "version": "4.0.1", "description": "Simple access to a cache", "main": "lib/cached.js", "keywords": [ From 6444fae6069e242137374d35f5ca47f46696e75d Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Thu, 26 Mar 2015 19:32:15 -0700 Subject: [PATCH 13/55] Fix unhandled rejections w/ lazy fetching Previously whenever a stale value was fetched in the background, a failing fetch lead to a rejected promise that was never properly handled. The new behavior is: * Track if a background-fetch-promise was ever returned to a caller via `@staleOrPending[key].wasEverReturned`. * When a background-fetch-promise is rejected, check if anybody cares (via `wasEverReturned`). Depending on that either forward the error or swallow it silently. The latter is fine because cached will just continue returning the last known value. --- lib/cache.js | 40 ++++++++++++++++++++++++++++++---------- src/cache.coffee | 32 +++++++++++++++++++++++--------- test/cache.coffee | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 19 deletions(-) diff --git a/lib/cache.js b/lib/cache.js index 60c9411..1882acb 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -148,34 +148,54 @@ Cache = (function() { }; Cache.prototype.getOrElse = function(rawKey, val, opts, cb) { - var handleError, key, ref, refreshValue, verifyFreshness; + var handleError, key, ref, refreshValue, resetStaleOrPending, verifyFreshness, writeValue; key = this.applyPrefix(rawKey); ref = optionalOpts(opts, cb), cb = ref.cb, opts = ref.opts; opts = this.prepareOptions(opts); - refreshValue = (function(_this) { - return function() { - var generatedValue; - generatedValue = toPromise(val); + resetStaleOrPending = (function(_this) { + return function(passThroughData) { + delete _this.staleOrPending[key]; + return passThroughData; + }; + })(this); + writeValue = (function(_this) { + return function(generatedValue) { return _this.set(rawKey, generatedValue, opts).then(function(rawValue) { var ref1; - delete _this.staleOrPending[key]; return (ref1 = rawValue != null ? rawValue.d : void 0) != null ? ref1 : null; - }, function(err) { - delete _this.staleOrPending[key]; + }, function() { return generatedValue != null ? generatedValue : null; }); }; })(this); + refreshValue = function() { + var refreshed; + return refreshed = toPromise(val).then(writeValue).then(resetStaleOrPending, function(err) { + resetStaleOrPending(); + if (refreshed.wasEverReturned) { + return Promise.reject(err); + } else { + return null; + } + }); + }; verifyFreshness = (function(_this) { return function(wrappedValue) { - var expired, hit, loadingNewValue, ref1; + var dataFromCache, expired, hit, loadingNewValue; hit = wrappedValue != null; expired = isExpired(wrappedValue != null ? wrappedValue.b : void 0); loadingNewValue = _this.staleOrPending[key] != null; + dataFromCache = wrappedValue != null ? wrappedValue.d : void 0; if ((!hit || expired) && !loadingNewValue) { _this.staleOrPending[key] = refreshValue(); + loadingNewValue = true; + } + if ((dataFromCache == null) && loadingNewValue) { + _this.staleOrPending[key].wasEverReturned = true; + return _this.staleOrPending[key]; + } else { + return dataFromCache; } - return (ref1 = wrappedValue != null ? wrappedValue.d : void 0) != null ? ref1 : _this.staleOrPending[key]; }; })(this); handleError = function(error) { diff --git a/src/cache.coffee b/src/cache.coffee index 036e2da..eb850e0 100644 --- a/src/cache.coffee +++ b/src/cache.coffee @@ -136,32 +136,46 @@ class Cache {cb,opts} = optionalOpts(opts, cb) opts = @prepareOptions opts - refreshValue = => - generatedValue = toPromise(val) + resetStaleOrPending = (passThroughData) => + delete @staleOrPending[key] + passThroughData + writeValue = (generatedValue) => @set(rawKey, generatedValue, opts).then( - (rawValue) => - delete @staleOrPending[key] - rawValue?.d ? null - - (err) => + (rawValue) -> rawValue?.d ? null + -> # return generated value instead of error # tracking backend errors should be done with wrapping your backend clients - delete @staleOrPending[key] generatedValue ? null ) + refreshValue = -> + refreshed = toPromise(val) + .then writeValue + .then resetStaleOrPending, (err) -> + resetStaleOrPending() # always reset + if refreshed.wasEverReturned + Promise.reject err + else + null # just ignore + verifyFreshness = (wrappedValue) => # best before is expired, we have to reload hit = wrappedValue? expired = isExpired wrappedValue?.b loadingNewValue = @staleOrPending[key]? + dataFromCache = wrappedValue?.d if (!hit or expired) && !loadingNewValue @staleOrPending[key] = refreshValue() + loadingNewValue = true # Return the value even if it's stale, we want the result ASAP - wrappedValue?.d ? @staleOrPending[key] + if !dataFromCache? && loadingNewValue + @staleOrPending[key].wasEverReturned = true + @staleOrPending[key] + else + dataFromCache handleError = (error) -> # we should let the refreshValue method work if getWrapped has problems diff --git a/test/cache.coffee b/test/cache.coffee index 19fd2c0..6a63908 100644 --- a/test/cache.coffee +++ b/test/cache.coffee @@ -22,6 +22,20 @@ waterfall = (fns) -> next = (prev, fn) -> prev.then fn fns.reduce next, Promise.resolve() +unexpected = (value) -> + console.error value + throw new Error 'Unexpected value' + +unhandledRejections = [] +Promise.onPossiblyUnhandledRejection (err) -> + console.error 'Possibly unhandled rejection:', err.stack + unhandledRejections.push err + +after 'Check for unhandled rejections', -> + if unhandledRejections.length + console.error 'Found %d unhandled rejections', unhandledRejections.length + throw unhandledRejections[0] + describe 'Cache', -> it 'always has a backend', -> cache = new Cache {} @@ -151,6 +165,26 @@ describe 'Cache', -> @cache.getOrElse 'bad_keys', errorGenerator, freshFor: 1, theCallback + describe 'refresh of expired value failing', -> + before 'set value that is stale after a second', -> + @cache.set 'key1', values.key1, freshFor: 1, expire: 3 + + before 'wait >1 seconds', (done) -> setTimeout(done, 1100) + + it 'returns the original value if generating a new value fails', -> + generator = -> Promise.reject new Error 'Oops' + @cache.getOrElse 'key1', generator + .then assert.equal.bind(null, values.key1) + + describe 'after two more second', -> + before 'wait >2 seconds', (done) -> setTimeout(done, 2100) + + it 'fails to return a value if generating fails again', -> + generator = -> Promise.reject new Error 'Oops' + @cache.getOrElse 'key1', generator + .then unexpected, (err) -> + assert.equal 'Oops', err.message + describe 'backed.get failing', -> before -> @failCache = new Cache { From f6ab82874a943f37ab87f2fa2197c65d7d1af589 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 27 Mar 2015 10:30:02 -0700 Subject: [PATCH 14/55] v4.0.2 --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ca6414..90798d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +4.0.2 +----- +* Fix unhandled rejections w/ lazy fetching - @jkrems + https://github.com/groupon/node-cached/pull/16 + 4.0.1 ----- * Fixing memcached.set slowness - @chkhoo #15 diff --git a/package.json b/package.json index 468ceb2..2de2c48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cached", - "version": "4.0.1", + "version": "4.0.2", "description": "Simple access to a cache", "main": "lib/cached.js", "keywords": [ From 973d712c16784f4a77addbb61dfcaec0c07a5f18 Mon Sep 17 00:00:00 2001 From: Chris Khoo Date: Mon, 2 Nov 2015 14:08:01 -0800 Subject: [PATCH 15/55] update bluebird & do some cleanup --- lib/backend.js | 2 +- lib/backends/memcached.js | 14 ++++++++++---- lib/backends/memory.js | 2 +- lib/backends/noop.js | 2 +- lib/cache.js | 4 ++-- lib/cached.js | 2 +- package.json | 5 +++-- src/backends/memcached.coffee | 6 +++--- src/cache.coffee | 9 ++++----- 9 files changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/backend.js b/lib/backend.js index 07575cf..9efafbc 100644 --- a/lib/backend.js +++ b/lib/backend.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.1 +// Generated by CoffeeScript 1.10.0 /* Copyright (c) 2014, Groupon, Inc. diff --git a/lib/backends/memcached.js b/lib/backends/memcached.js index 294a591..3eac1fa 100644 --- a/lib/backends/memcached.js +++ b/lib/backends/memcached.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.1 +// Generated by CoffeeScript 1.10.0 /* Copyright (c) 2014, Groupon, Inc. @@ -52,9 +52,15 @@ MemcachedBackend = (function() { hosts = (ref = options.hosts) != null ? ref : '127.0.0.1:11211'; this.client = new Memcached(hosts, options); } - this._clientGet = promisify(this.client.get, this.client); - this._clientSet = promisify(this.client.set, this.client); - this._clientDel = promisify(this.client.del, this.client); + this._clientGet = promisify(this.client.get, { + context: this.client + }); + this._clientSet = promisify(this.client.set, { + context: this.client + }); + this._clientDel = promisify(this.client.del, { + context: this.client + }); } MemcachedBackend.prototype.get = function(key) { diff --git a/lib/backends/memory.js b/lib/backends/memory.js index a17db45..443eb1e 100644 --- a/lib/backends/memory.js +++ b/lib/backends/memory.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.1 +// Generated by CoffeeScript 1.10.0 /* Copyright (c) 2014, Groupon, Inc. diff --git a/lib/backends/noop.js b/lib/backends/noop.js index 65e3975..1521482 100644 --- a/lib/backends/noop.js +++ b/lib/backends/noop.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.1 +// Generated by CoffeeScript 1.10.0 /* Copyright (c) 2014, Groupon, Inc. diff --git a/lib/cache.js b/lib/cache.js index 1882acb..c968f3c 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.1 +// Generated by CoffeeScript 1.10.0 /* Copyright (c) 2014, Groupon, Inc. @@ -163,7 +163,7 @@ Cache = (function() { return _this.set(rawKey, generatedValue, opts).then(function(rawValue) { var ref1; return (ref1 = rawValue != null ? rawValue.d : void 0) != null ? ref1 : null; - }, function() { + })["catch"](function() { return generatedValue != null ? generatedValue : null; }); }; diff --git a/lib/cached.js b/lib/cached.js index bc3de95..337038e 100644 --- a/lib/cached.js +++ b/lib/cached.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.9.1 +// Generated by CoffeeScript 1.10.0 /* Copyright (c) 2014, Groupon, Inc. diff --git a/package.json b/package.json index 2de2c48..21feb41 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "scripts": { "build": "coffee -cbo lib src", - "watch": "coffee -wcbo lib src", + "watch": "coffee -wcbo lib src & nodemon -w src -w test -e coffee,js,json -x mocha", "prepublish": "rm -rf lib && npm run build", "pretest": "npm run build", "test": "mocha", @@ -34,7 +34,7 @@ } }, "dependencies": { - "bluebird": "^2.9.7", + "bluebird": "^3.0.5", "lodash": "^3.1.0", "memcached": "^2.1.0" }, @@ -42,6 +42,7 @@ "assertive": "^1.4.1", "coffee-script": "^1.9.0", "mocha": "^2.0.1", + "nodemon": "^1.8.0", "npub": "~0.5.1" } } diff --git a/src/backends/memcached.coffee b/src/backends/memcached.coffee index 021ff6a..84b87ec 100644 --- a/src/backends/memcached.coffee +++ b/src/backends/memcached.coffee @@ -46,9 +46,9 @@ class MemcachedBackend hosts = options.hosts ? '127.0.0.1:11211' @client = new Memcached hosts, options - @_clientGet = promisify @client.get, @client - @_clientSet = promisify @client.set, @client - @_clientDel = promisify @client.del, @client + @_clientGet = promisify @client.get, context: @client + @_clientSet = promisify @client.set, context: @client + @_clientDel = promisify @client.del, context: @client get: (key) -> @_clientGet(key).then (answer) -> diff --git a/src/cache.coffee b/src/cache.coffee index eb850e0..4a547a4 100644 --- a/src/cache.coffee +++ b/src/cache.coffee @@ -108,7 +108,7 @@ class Cache b: expiresAt(opts.freshFor) d: resolvedValue }, opts - .nodeify cb + .nodeify cb # Every value we cache is wrapped to enable graceful expire: # { @@ -141,13 +141,12 @@ class Cache passThroughData writeValue = (generatedValue) => - @set(rawKey, generatedValue, opts).then( - (rawValue) -> rawValue?.d ? null - -> + @set(rawKey, generatedValue, opts) + .then (rawValue) -> rawValue?.d ? null + .catch -> # return generated value instead of error # tracking backend errors should be done with wrapping your backend clients generatedValue ? null - ) refreshValue = -> refreshed = toPromise(val) From af96680ac94c4a6db657629879fe13f0e1f182c2 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 6 Nov 2015 09:47:11 -0800 Subject: [PATCH 16/55] Remove coffee, add JS linting --- .eslintrc | 9 ++ .npmignore | 3 - .travis.yml | 3 +- Makefile | 10 -- lib/backend.js | 44 +++--- lib/cache.js | 284 +++++++++++++++++----------------- package.json | 17 +- src/backend.coffee | 52 ------- src/backends/memcached.coffee | 67 -------- src/backends/memory.coffee | 70 --------- src/backends/noop.coffee | 45 ------ src/cache.coffee | 186 ---------------------- src/cached.coffee | 64 -------- test/cache.coffee | 2 +- 14 files changed, 181 insertions(+), 675 deletions(-) create mode 100644 .eslintrc delete mode 100644 .npmignore delete mode 100644 Makefile delete mode 100644 src/backend.coffee delete mode 100644 src/backends/memcached.coffee delete mode 100644 src/backends/memory.coffee delete mode 100644 src/backends/noop.coffee delete mode 100644 src/cache.coffee delete mode 100644 src/cached.coffee diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..68d14a4 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,9 @@ +{ + "extends": "airbnb/legacy", + "rules": { + "id-length": 0, + "vars-on-top": 0, + "strict": [2, "global"], + "no-param-reassign": 0 + } +} diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 366f223..0000000 --- a/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -/examples -/src -/test diff --git a/.travis.yml b/.travis.yml index 58c62fc..7d88594 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: node_js node_js: - "0.10" - - "0.12" - - "iojs" + - "4" services: memcached diff --git a/Makefile b/Makefile deleted file mode 100644 index c2850de..0000000 --- a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -.PHONY: clean setup - -setup: - npm install - -clean: - rm -rf node_modules - -release-%: clean setup - ./node_modules/.bin/npub publish $(subst release-,,$@) diff --git a/lib/backend.js b/lib/backend.js index 9efafbc..b64fcc7 100644 --- a/lib/backend.js +++ b/lib/backend.js @@ -1,5 +1,3 @@ -// Generated by CoffeeScript 1.10.0 - /* Copyright (c) 2014, Groupon, Inc. All rights reserved. @@ -32,32 +30,36 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 'use strict'; -var typeMap; -typeMap = Object.create(null); +var typeMap = Object.create(null); -exports.addType = function(type, klass) { - return typeMap[type] = klass; -}; +function isBackend(object) { + return typeof object.get === 'function' && typeof object.set === 'function'; +} -exports.create = function(options) { - var klass, ref, type; - if (options == null) { - options = {}; - } - if ('function' === typeof options.get && 'function' === typeof options.set) { +exports.create = function create(options) { + options = options || {}; + + if (isBackend(options)) { return options; } - type = (ref = options.type) != null ? ref : 'noop'; - klass = typeMap[type]; - if (klass == null) { - throw new Error(type + " is not a supported cache backend type"); + + var type = options.type || 'noop'; + var BackendClass = typeMap[type]; + if (!BackendClass) { + throw new Error(type + ' is not a supported cache backend type'); } - return new klass(options); + return new BackendClass(options); }; -exports.addType('noop', require("./backends/noop")); +function addType(type, BackendClass) { + typeMap[type] = BackendClass; + return BackendClass; +} +exports.addType = addType; + +addType('noop', require('./backends/noop')); -exports.addType('memory', require("./backends/memory")); +addType('memory', require('./backends/memory')); -exports.addType('memcached', require("./backends/memcached")); +addType('memcached', require('./backends/memcached')); diff --git a/lib/cache.js b/lib/cache.js index c968f3c..31022a4 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,5 +1,3 @@ -// Generated by CoffeeScript 1.10.0 - /* Copyright (c) 2014, Groupon, Inc. All rights reserved. @@ -32,180 +30,174 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 'use strict'; -var Backend, Cache, Promise, expiresAt, extend, isExpired, optionalOpts, toPromise; - -extend = require('lodash').extend; -Promise = require('bluebird'); +var Bluebird = require('bluebird'); +var _ = require('lodash'); -Backend = require('./backend'); +var Backend = require('./backend'); -toPromise = function(val) { - if ('function' === typeof val) { - return Promise.resolve(val()); - } else { - return Promise.resolve(val); +function toPromise(val) { + if (typeof val === 'function') { + return Bluebird.resolve(val()); } -}; + return Bluebird.resolve(val); +} -expiresAt = function(seconds) { +function expiresAt(seconds) { if (seconds === 0) { return 0; - } else { - return Date.now() + parseInt(seconds, 10) * 1000; } -}; + return Date.now() + parseInt(seconds, 10) * 1000; +} -isExpired = function(expires) { +function isExpired(expires) { if (expires === 0) { return false; } return Date.now() > new Date(expires).getTime(); -}; +} -optionalOpts = function(opts, cb) { - if ((cb == null) && 'function' === typeof opts) { - return { - cb: opts, - opts: null - }; - } else { - return { - cb: cb, - opts: opts - }; +function optionalOpts(opts, cb) { + if (!cb && typeof opts === 'function') { + return { cb: opts, opts: null }; } + return { cb: cb, opts: opts }; +} + +function extractValue(wrappedValue) { + var value = wrappedValue && wrappedValue.d; + // Normalize `undefined` into `null` + return value === undefined ? null : value; +} + +function defaultToNull(/* error */) { + return null; +} + +function Cache(options) { + this.defaults = { + freshFor: 0, + expire: 0, + }; + this.name = options.name || 'default'; + this.prefix = this.name + ':'; + this.staleOrPending = {}; + + this.setDefaults(options.defaults); + this.setBackend(options.backend); +} + +Cache.prototype.applyPrefix = function applyPrefix(key) { + return [this.prefix, key].join(''); +}; + +Cache.prototype.setDefaults = function setDefaults(defaults) { + this.defaults = this.prepareOptions(defaults); + return this.defaults; }; -Cache = (function() { - function Cache(arg) { - var backend, defaults, name; - backend = arg.backend, defaults = arg.defaults, name = arg.name; - this.defaults = { - freshFor: 0, - expire: 0 - }; - this.name = name || 'default'; - this.prefix = this.name + ":"; - this.staleOrPending = {}; - this.setDefaults(defaults); - this.setBackend(backend); +Cache.prototype.setBackend = function setBackend(backendOptions) { + backendOptions = typeof backendOptions === 'string' ? { + type: backendOptions, + } : backendOptions || {}; + this.end(); + this.backend = Backend.create(backendOptions); + return this.backend; +}; + +Cache.prototype.end = function end() { + if (this.backend && this.backend.end) { + return this.backend.end(); } +}; - Cache.prototype.applyPrefix = function(key) { - return [this.prefix, key].join(''); - }; +Cache.prototype.prepareOptions = function prepareOptions(options) { + return _.extend({}, this.defaults, options); +}; - Cache.prototype.setDefaults = function(defaults) { - return this.defaults = this.prepareOptions(defaults); - }; +Cache.prototype.set = function set(rawKey, val, _opts, _cb) { + var args = optionalOpts(_opts, _cb); + var key = this.applyPrefix(rawKey); + var optsWithDefaults = this.prepareOptions(args.opts); + + var self = this; + function writeToBackend(resolvedValue) { + return self.backend.set(key, { + b: expiresAt(optsWithDefaults.freshFor), + d: resolvedValue, + }, optsWithDefaults); + } - Cache.prototype.setBackend = function(backendOptions) { - backendOptions = 'string' === typeof backendOptions ? { - type: backendOptions - } : backendOptions != null ? backendOptions : {}; - this.end(); - return this.backend = Backend.create(backendOptions); - }; + return toPromise(val).then(writeToBackend).nodeify(args.cb); +}; - Cache.prototype.end = function() { - var ref; - if (((ref = this.backend) != null ? ref.end : void 0) != null) { - return this.backend.end(); - } - }; +Cache.prototype.getWrapped = function getWrapped(key) { + return this.backend.get(key); +}; - Cache.prototype.prepareOptions = function(options) { - return extend({}, this.defaults, options); - }; +Cache.prototype.get = function get(rawKey, cb) { + var key = this.applyPrefix(rawKey); - Cache.prototype.set = function(key, val, opts, cb) { - var ref; - ref = optionalOpts(opts, cb), cb = ref.cb, opts = ref.opts; - key = this.applyPrefix(key); - opts = this.prepareOptions(opts); - return toPromise(val).then((function(_this) { - return function(resolvedValue) { - return _this.backend.set(key, { - b: expiresAt(opts.freshFor), - d: resolvedValue - }, opts); - }; - })(this)).nodeify(cb); - }; + return this.getWrapped(key).then(extractValue).nodeify(cb); +}; - Cache.prototype.getWrapped = function(key) { - return this.backend.get(key); - }; +Cache.prototype.getOrElse = function getOrElse(rawKey, val, _opts, _cb) { + var key = this.applyPrefix(rawKey); + var args = optionalOpts(_opts, _cb); + var optsWithDefaults = this.prepareOptions(args.opts); + var self = this; - Cache.prototype.get = function(rawKey, cb) { - var key; - key = this.applyPrefix(rawKey); - return this.getWrapped(key).then(function(wrappedValue) { - var ref; - return (ref = wrappedValue != null ? wrappedValue.d : void 0) != null ? ref : null; - }).nodeify(cb); - }; + function resetStaleOrPending(passThroughData) { + delete self.staleOrPending[key]; + return passThroughData; + } - Cache.prototype.getOrElse = function(rawKey, val, opts, cb) { - var handleError, key, ref, refreshValue, resetStaleOrPending, verifyFreshness, writeValue; - key = this.applyPrefix(rawKey); - ref = optionalOpts(opts, cb), cb = ref.cb, opts = ref.opts; - opts = this.prepareOptions(opts); - resetStaleOrPending = (function(_this) { - return function(passThroughData) { - delete _this.staleOrPending[key]; - return passThroughData; - }; - })(this); - writeValue = (function(_this) { - return function(generatedValue) { - return _this.set(rawKey, generatedValue, opts).then(function(rawValue) { - var ref1; - return (ref1 = rawValue != null ? rawValue.d : void 0) != null ? ref1 : null; - })["catch"](function() { - return generatedValue != null ? generatedValue : null; - }); - }; - })(this); - refreshValue = function() { - var refreshed; - return refreshed = toPromise(val).then(writeValue).then(resetStaleOrPending, function(err) { - resetStaleOrPending(); - if (refreshed.wasEverReturned) { - return Promise.reject(err); - } else { - return null; - } + function writeValue(generatedValue) { + return self.set(rawKey, generatedValue, optsWithDefaults) + .then(extractValue) + .catch(function fallbackToLoadedValue() { + return generatedValue === undefined ? null : generatedValue; }); - }; - verifyFreshness = (function(_this) { - return function(wrappedValue) { - var dataFromCache, expired, hit, loadingNewValue; - hit = wrappedValue != null; - expired = isExpired(wrappedValue != null ? wrappedValue.b : void 0); - loadingNewValue = _this.staleOrPending[key] != null; - dataFromCache = wrappedValue != null ? wrappedValue.d : void 0; - if ((!hit || expired) && !loadingNewValue) { - _this.staleOrPending[key] = refreshValue(); - loadingNewValue = true; - } - if ((dataFromCache == null) && loadingNewValue) { - _this.staleOrPending[key].wasEverReturned = true; - return _this.staleOrPending[key]; - } else { - return dataFromCache; - } - }; - })(this); - handleError = function(error) { + } + + function refreshValue() { + var refreshed; + + function handleWriteError(err) { + resetStaleOrPending(); + if (refreshed.wasEverReturned) { + return Promise.reject(err); + } return null; - }; - return this.getWrapped(key)["catch"](handleError).then(verifyFreshness).nodeify(cb); - }; + } + + refreshed = toPromise(val) + .then(writeValue) + .then(resetStaleOrPending, handleWriteError); + + return refreshed; + } - return Cache; + function verifyFreshness(wrappedValue) { + var hit = !!wrappedValue; + var expired = isExpired(wrappedValue && wrappedValue.b); + var loadingNewValue = self.staleOrPending[key] !== undefined; + var dataFromCache = extractValue(wrappedValue); + if ((!hit || expired) && !loadingNewValue) { + self.staleOrPending[key] = refreshValue(); + loadingNewValue = true; + } + if ((dataFromCache === null) && loadingNewValue) { + self.staleOrPending[key].wasEverReturned = true; + return self.staleOrPending[key]; + } + return dataFromCache; + } -})(); + return this.getWrapped(key) + .catch(defaultToNull) + .then(verifyFreshness) + .nodeify(args.cb); +}; module.exports = Cache; diff --git a/package.json b/package.json index 21feb41..e71178d 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,14 @@ "cache" ], "scripts": { - "build": "coffee -cbo lib src", - "watch": "coffee -wcbo lib src & nodemon -w src -w test -e coffee,js,json -x mocha", - "prepublish": "rm -rf lib && npm run build", - "pretest": "npm run build", + "watch": "mocha --watch", + "pretest": "eslint lib || true", "test": "mocha", "posttest": "npub verify" }, + "files": [ + "lib" + ], "repository": { "type": "git", "url": "git://github.com/groupon/node-cached.git" @@ -28,7 +29,6 @@ "registry": "https://registry.npmjs.org", "license": { "exclude": [ - "lib", "test" ] } @@ -39,10 +39,11 @@ "memcached": "^2.1.0" }, "devDependencies": { - "assertive": "^1.4.1", + "assertive": "^2.0.0", "coffee-script": "^1.9.0", + "eslint": "~1.8.0", + "eslint-config-airbnb": "~0.1.0", "mocha": "^2.0.1", - "nodemon": "^1.8.0", - "npub": "~0.5.1" + "npub": "^2.0.0" } } diff --git a/src/backend.coffee b/src/backend.coffee deleted file mode 100644 index 5d54e84..0000000 --- a/src/backend.coffee +++ /dev/null @@ -1,52 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - -'use strict' -typeMap = Object.create null - -exports.addType = (type, klass) -> typeMap[type] = klass - -exports.create = (options) -> - options ?= {} - - # make the whole thing idempotent - if 'function' is typeof options.get and 'function' is typeof options.set - return options - - type = options.type ? 'noop' - klass = typeMap[type] - throw new Error("#{type} is not a supported cache backend type") unless klass? - new klass(options) - -exports.addType 'noop', require("./backends/noop") -exports.addType 'memory', require("./backends/memory") -exports.addType 'memcached', require("./backends/memcached") diff --git a/src/backends/memcached.coffee b/src/backends/memcached.coffee deleted file mode 100644 index 84b87ec..0000000 --- a/src/backends/memcached.coffee +++ /dev/null @@ -1,67 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - -'use strict' -Memcached = require 'memcached' -{promisify} = require 'bluebird' - -class MemcachedBackend - description = "Uses anything supporting the memcache protocol" - - constructor: (options) -> - @type = 'memcached' - - if options.client? - @client = options.client - else - hosts = options.hosts ? '127.0.0.1:11211' - @client = new Memcached hosts, options - - @_clientGet = promisify @client.get, context: @client - @_clientSet = promisify @client.set, context: @client - @_clientDel = promisify @client.del, context: @client - - get: (key) -> - @_clientGet(key).then (answer) -> - if answer == false then null - else answer - - set: (key, value, options) -> - @_clientSet(key, value, options.expire).then -> value - - unset: (key) -> - @_clientDel(key).then -> undefined - - end: -> - @client.end() - -module.exports = MemcachedBackend diff --git a/src/backends/memory.coffee b/src/backends/memory.coffee deleted file mode 100644 index cec4f7c..0000000 --- a/src/backends/memory.coffee +++ /dev/null @@ -1,70 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - -'use strict' -Promise = require 'bluebird' - -class MemoryBackend - description = "Stores everything just in memory" - - constructor: -> - @cache = Object.create null - @type = 'memory' - - get: (key) -> - if @isExpired(@cache[key]?.e) - delete @cache[key] # make sure it does not exist - - Promise.resolve(@cache[key]?.d ? null) - - expiresAt: (seconds) -> - if seconds is 0 then 0 - else (new Date()).getTime() + (parseInt(seconds) * 1000) - - isExpired: (expires) -> - return false unless expires? - return false if expires is 0 - # "now is greater than expires" - return (new Date()).getTime() > (new Date(expires)).getTime() - - set: (key, value, options) -> - @cache[key] = - d: value - e: @expiresAt(options.expire) - - Promise.resolve value - - unset: (key) -> - delete @cache[key] - Promise.resolve() - -module.exports = MemoryBackend diff --git a/src/backends/noop.coffee b/src/backends/noop.coffee deleted file mode 100644 index 3ece0d0..0000000 --- a/src/backends/noop.coffee +++ /dev/null @@ -1,45 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - -'use strict' -Promise = require 'bluebird' - -class NoopBackend - description = "Simple backend doing nothing" - - constructor: -> @type = 'noop' - - get: (key) -> Promise.resolve(null) - set: (key, value) -> Promise.resolve(value) - unset: (key) -> Promise.resolve() - -module.exports = NoopBackend diff --git a/src/cache.coffee b/src/cache.coffee deleted file mode 100644 index 4a547a4..0000000 --- a/src/cache.coffee +++ /dev/null @@ -1,186 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - -'use strict' -{extend} = require 'lodash' -Promise = require 'bluebird' - -Backend = require './backend' - -toPromise = (val) -> - # If val is a function, evaluate it first, convert into promise afterwards - if 'function' is typeof val - Promise.resolve val() - else Promise.resolve val - -expiresAt = (seconds) -> - if seconds is 0 then 0 - else Date.now() + parseInt(seconds, 10) * 1000 - -isExpired = (expires) -> - return false if expires is 0 - Date.now() > new Date(expires).getTime() - -optionalOpts = (opts, cb) -> - if not cb? and 'function' is typeof opts - { cb: opts, opts: null } - else - { cb, opts } - -class Cache - constructor: ({backend, defaults, name}) -> - @defaults = - freshFor: 0 - expire: 0 - - @name = name or 'default' - @prefix = "#{@name}:" - - # stale keys that are loaded right now - @staleOrPending = {} - - @setDefaults defaults - @setBackend backend - - applyPrefix: (key) -> - [ @prefix, key ].join '' - # don't refactor the above line to a concatenation - # see https://github.com/3rd-Eden/node-memcached/pull/205 for details - - setDefaults: (defaults) -> - @defaults = @prepareOptions defaults - - setBackend: (backendOptions) -> - backendOptions = - if 'string' is typeof backendOptions - { type: backendOptions } - else - backendOptions ? {} - - @end() - @backend = Backend.create backendOptions - - end: -> - @backend.end() if @backend?.end? - - prepareOptions: (options) -> - extend {}, @defaults, options - - set: (key, val, opts, cb) -> - {cb,opts} = optionalOpts(opts, cb) - - key = @applyPrefix key - - opts = @prepareOptions opts - - toPromise(val) - .then (resolvedValue) => - @backend.set key, { - b: expiresAt(opts.freshFor) - d: resolvedValue - }, opts - .nodeify cb - - # Every value we cache is wrapped to enable graceful expire: - # { - # "d": - # "b": - # } - # This allows us to have stale values stored in the cache and fetch a - # replacement in the background. - getWrapped: (key) -> - @backend.get key - - get: (rawKey, cb) -> - key = @applyPrefix rawKey - @getWrapped(key) - .then (wrappedValue) -> - # blindly return the wrapped value, ignoring freshness - wrappedValue?.d ? null - .nodeify cb - - # Get from a cache or generate if not present or stale. - # A value is stale when it was generated more than `freshFor` seconds ago - getOrElse: (rawKey, val, opts, cb) -> - key = @applyPrefix rawKey - - {cb,opts} = optionalOpts(opts, cb) - opts = @prepareOptions opts - - resetStaleOrPending = (passThroughData) => - delete @staleOrPending[key] - passThroughData - - writeValue = (generatedValue) => - @set(rawKey, generatedValue, opts) - .then (rawValue) -> rawValue?.d ? null - .catch -> - # return generated value instead of error - # tracking backend errors should be done with wrapping your backend clients - generatedValue ? null - - refreshValue = -> - refreshed = toPromise(val) - .then writeValue - .then resetStaleOrPending, (err) -> - resetStaleOrPending() # always reset - if refreshed.wasEverReturned - Promise.reject err - else - null # just ignore - - verifyFreshness = (wrappedValue) => - # best before is expired, we have to reload - hit = wrappedValue? - expired = isExpired wrappedValue?.b - loadingNewValue = @staleOrPending[key]? - dataFromCache = wrappedValue?.d - - if (!hit or expired) && !loadingNewValue - @staleOrPending[key] = refreshValue() - loadingNewValue = true - - # Return the value even if it's stale, we want the result ASAP - if !dataFromCache? && loadingNewValue - @staleOrPending[key].wasEverReturned = true - @staleOrPending[key] - else - dataFromCache - - handleError = (error) -> - # we should let the refreshValue method work if getWrapped has problems - # tracking backend errors should be done with wrapping your backend clients - return null - - @getWrapped(key).catch(handleError).then(verifyFreshness).nodeify cb - -module.exports = Cache diff --git a/src/cached.coffee b/src/cached.coffee deleted file mode 100644 index 49dd757..0000000 --- a/src/cached.coffee +++ /dev/null @@ -1,64 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - -'use strict' -Promise = require 'bluebird' -{extend} = require 'lodash' - -Cache = require './cache' - -namedCaches = Object.create null - -cached = (name="default", options={}) -> - options = extend { name }, options - namedCaches[name] ?= cached.createCache(options) - -cached.createCache = (options={}) -> - new Cache(options) - -cached.dropNamedCaches = () -> - namedCaches = Object.create null - return cached - -cached.dropNamedCache = (name) -> - delete namedCaches[name] - return cached - -cached.knownCaches = -> - Object.keys namedCaches - -cached.deferred = (fn) -> - # a simple function that returns a promise of the execution of a - # given nodejs callback-style function `fn` - Promise.promisify fn - -module.exports = cached diff --git a/test/cache.coffee b/test/cache.coffee index 6a63908..1819178 100644 --- a/test/cache.coffee +++ b/test/cache.coffee @@ -159,8 +159,8 @@ describe 'Cache', -> cb new Error 'Big Error' theCallback = (err, data) -> - assert.equal 'Big Error', err?.message assert.equal undefined, data + assert.equal 'Big Error', err?.message done() @cache.getOrElse 'bad_keys', errorGenerator, freshFor: 1, theCallback From 98c2f96ffc5852634f87351598e6e06f1879a026 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 6 Nov 2015 13:36:20 -0800 Subject: [PATCH 17/55] Port lib to cleanly linting JS --- lib/backends/memcached.js | 91 ++++++++++++++++----------------------- lib/backends/memory.js | 89 ++++++++++++++++---------------------- lib/backends/noop.js | 42 +++++++----------- lib/cached.js | 50 +++++++++------------ package.json | 2 +- 5 files changed, 109 insertions(+), 165 deletions(-) diff --git a/lib/backends/memcached.js b/lib/backends/memcached.js index 3eac1fa..92dcba9 100644 --- a/lib/backends/memcached.js +++ b/lib/backends/memcached.js @@ -32,65 +32,46 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 'use strict'; -var Memcached, MemcachedBackend, promisify; -Memcached = require('memcached'); +var promisify = require('bluebird').promisify; +var _ = require('lodash'); +var Memcached = require('memcached'); -promisify = require('bluebird').promisify; - -MemcachedBackend = (function() { - var description; - - description = "Uses anything supporting the memcache protocol"; - - function MemcachedBackend(options) { - var hosts, ref; - this.type = 'memcached'; - if (options.client != null) { - this.client = options.client; - } else { - hosts = (ref = options.hosts) != null ? ref : '127.0.0.1:11211'; - this.client = new Memcached(hosts, options); - } - this._clientGet = promisify(this.client.get, { - context: this.client - }); - this._clientSet = promisify(this.client.set, { - context: this.client - }); - this._clientDel = promisify(this.client.del, { - context: this.client - }); +function createClient(options) { + if (options.client) { + return options.client; } + var hosts = options.hosts || '127.0.0.1:11211'; + return new Memcached(hosts, options); +} + +function normalizeValue(value) { + return value === false ? null : value; +} + +/* Uses anything supporting the memcache protocol */ +function MemcachedBackend(options) { + this.type = 'memcached'; + var client = this.client = createClient(options); + this._clientGet = promisify(client.get, { context: client }); + this._clientSet = promisify(client.set, { context: client }); + this._clientDel = promisify(client.del, { context: client }); +} +module.exports = MemcachedBackend; - MemcachedBackend.prototype.get = function(key) { - return this._clientGet(key).then(function(answer) { - if (answer === false) { - return null; - } else { - return answer; - } - }); - }; - - MemcachedBackend.prototype.set = function(key, value, options) { - return this._clientSet(key, value, options.expire).then(function() { - return value; - }); - }; - - MemcachedBackend.prototype.unset = function(key) { - return this._clientDel(key).then(function() { - return void 0; - }); - }; - - MemcachedBackend.prototype.end = function() { - return this.client.end(); - }; +MemcachedBackend.prototype.get = function get(key) { + return this._clientGet(key).then(normalizeValue); +}; - return MemcachedBackend; +MemcachedBackend.prototype.set = function set(key, value, options) { + return this._clientSet(key, value, options.expire) + .then(_.constant(value)); +}; -})(); +MemcachedBackend.prototype.unset = function unset(key) { + return this._clientDel(key).then(_.noop); +}; -module.exports = MemcachedBackend; +MemcachedBackend.prototype.end = function end() { + return this.client.end(); +}; diff --git a/lib/backends/memory.js b/lib/backends/memory.js index 443eb1e..b7dd32d 100644 --- a/lib/backends/memory.js +++ b/lib/backends/memory.js @@ -1,5 +1,3 @@ -// Generated by CoffeeScript 1.10.0 - /* Copyright (c) 2014, Groupon, Inc. All rights reserved. @@ -32,61 +30,48 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 'use strict'; -var MemoryBackend, Promise; - -Promise = require('bluebird'); - -MemoryBackend = (function() { - var description; - description = "Stores everything just in memory"; +var Bluebird = require('bluebird'); - function MemoryBackend() { - this.cache = Object.create(null); - this.type = 'memory'; +function expiresAt(seconds) { + if (seconds === 0) { + return 0; } + return Date.now() + parseInt(seconds, 10) * 1000; +} - MemoryBackend.prototype.get = function(key) { - var ref, ref1, ref2; - if (this.isExpired((ref = this.cache[key]) != null ? ref.e : void 0)) { - delete this.cache[key]; - } - return Promise.resolve((ref1 = (ref2 = this.cache[key]) != null ? ref2.d : void 0) != null ? ref1 : null); - }; - - MemoryBackend.prototype.expiresAt = function(seconds) { - if (seconds === 0) { - return 0; - } else { - return (new Date()).getTime() + (parseInt(seconds) * 1000); - } - }; - - MemoryBackend.prototype.isExpired = function(expires) { - if (expires == null) { - return false; - } - if (expires === 0) { - return false; - } - return (new Date()).getTime() > (new Date(expires)).getTime(); - }; - - MemoryBackend.prototype.set = function(key, value, options) { - this.cache[key] = { - d: value, - e: this.expiresAt(options.expire) - }; - return Promise.resolve(value); - }; +function isExpired(expires) { + if (!expires) { + return false; + } + return Date.now() > new Date(expires).getTime(); +} + +/* Stores everything just in memory */ +function MemoryBackend() { + this.cache = Object.create(null); + this.type = 'memory'; +} +module.exports = MemoryBackend; - MemoryBackend.prototype.unset = function(key) { +MemoryBackend.prototype.get = function get(key) { + var wrappedValue = this.cache[key] || null; + if (isExpired(wrappedValue && wrappedValue.e)) { + wrappedValue = null; delete this.cache[key]; - return Promise.resolve(); - }; - - return MemoryBackend; + } + return Bluebird.resolve(wrappedValue ? wrappedValue.d : null); +}; -})(); +MemoryBackend.prototype.set = function set(key, value, options) { + this.cache[key] = { + d: value, + e: expiresAt(options.expire), + }; + return Bluebird.resolve(value); +}; -module.exports = MemoryBackend; +MemoryBackend.prototype.unset = function unset(key) { + delete this.cache[key]; + return Bluebird.resolve(); +}; diff --git a/lib/backends/noop.js b/lib/backends/noop.js index 1521482..701ede2 100644 --- a/lib/backends/noop.js +++ b/lib/backends/noop.js @@ -1,5 +1,3 @@ -// Generated by CoffeeScript 1.10.0 - /* Copyright (c) 2014, Groupon, Inc. All rights reserved. @@ -32,33 +30,23 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 'use strict'; -var NoopBackend, Promise; - -Promise = require('bluebird'); - -NoopBackend = (function() { - var description; - - description = "Simple backend doing nothing"; - function NoopBackend() { - this.type = 'noop'; - } +var Bluebird = require('bluebird'); - NoopBackend.prototype.get = function(key) { - return Promise.resolve(null); - }; - - NoopBackend.prototype.set = function(key, value) { - return Promise.resolve(value); - }; - - NoopBackend.prototype.unset = function(key) { - return Promise.resolve(); - }; +/* Simple backend doing nothing */ +function NoopBackend() { + this.type = 'noop'; +} +module.exports = NoopBackend; - return NoopBackend; +NoopBackend.prototype.get = function get(/* key */) { + return Bluebird.resolve(null); +}; -})(); +NoopBackend.prototype.set = function set(key, value) { + return Bluebird.resolve(value); +}; -module.exports = NoopBackend; +NoopBackend.prototype.unset = function unset(/* key */) { + return Bluebird.resolve(); +}; diff --git a/lib/cached.js b/lib/cached.js index 337038e..6b8fbd4 100644 --- a/lib/cached.js +++ b/lib/cached.js @@ -1,5 +1,3 @@ -// Generated by CoffeeScript 1.10.0 - /* Copyright (c) 2014, Groupon, Inc. All rights reserved. @@ -32,52 +30,44 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 'use strict'; -var Cache, Promise, cached, extend, namedCaches; -Promise = require('bluebird'); +var Bluebird = require('bluebird'); +var _ = require('lodash'); -extend = require('lodash').extend; +var Cache = require('./cache'); -Cache = require('./cache'); +var namedCaches = Object.create(null); -namedCaches = Object.create(null); +function cached(name, options) { + name = name || 'default'; -cached = function(name, options) { - if (name == null) { - name = "default"; - } - if (options == null) { - options = {}; + if (!(name in namedCaches)) { + namedCaches[name] = cached.createCache(_.extend({ + name: name, + }, options || {})); } - options = extend({ - name: name - }, options); - return namedCaches[name] != null ? namedCaches[name] : namedCaches[name] = cached.createCache(options); -}; + return namedCaches[name]; +} +module.exports = cached; -cached.createCache = function(options) { - if (options == null) { - options = {}; - } - return new Cache(options); +cached.createCache = function createCache(options) { + return new Cache(options || {}); }; -cached.dropNamedCaches = function() { +cached.dropNamedCaches = function dropNamedCaches() { namedCaches = Object.create(null); return cached; }; -cached.dropNamedCache = function(name) { +cached.dropNamedCache = function dropNamedCache(name) { delete namedCaches[name]; return cached; }; -cached.knownCaches = function() { +cached.knownCaches = function knownCaches() { return Object.keys(namedCaches); }; -cached.deferred = function(fn) { - return Promise.promisify(fn); +cached.deferred = function deferred(fn) { + return Bluebird.promisify(fn); }; - -module.exports = cached; diff --git a/package.json b/package.json index e71178d..5e83e3c 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "scripts": { "watch": "mocha --watch", - "pretest": "eslint lib || true", + "pretest": "eslint lib", "test": "mocha", "posttest": "npub verify" }, From d7e54be4386077d71cf0cf5d8790e1bef41fcbe1 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 6 Nov 2015 13:39:51 -0800 Subject: [PATCH 18/55] Remove references to node v4-only Promise --- lib/cache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cache.js b/lib/cache.js index 31022a4..4e76e31 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -166,7 +166,7 @@ Cache.prototype.getOrElse = function getOrElse(rawKey, val, _opts, _cb) { function handleWriteError(err) { resetStaleOrPending(); if (refreshed.wasEverReturned) { - return Promise.reject(err); + return Bluebird.reject(err); } return null; } From 73a96bdfe0d221536808357bb5ca233534116de7 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 6 Nov 2015 14:16:39 -0800 Subject: [PATCH 19/55] Port first test to ES6+babel --- .babelrc | 3 +++ package.json | 6 ++++-- test/.eslintrc | 9 +++++++++ test/mocha.opts | 3 +-- test/prefix.coffee | 28 ---------------------------- test/prefix.js | 21 +++++++++++++++++++++ 6 files changed, 38 insertions(+), 32 deletions(-) create mode 100644 .babelrc create mode 100644 test/.eslintrc delete mode 100644 test/prefix.coffee create mode 100644 test/prefix.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..50f2ab3 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "only": "test" +} diff --git a/package.json b/package.json index 5e83e3c..64ff3db 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ ], "scripts": { "watch": "mocha --watch", - "pretest": "eslint lib", + "pretest": "eslint lib test", "test": "mocha", "posttest": "npub verify" }, @@ -40,8 +40,10 @@ }, "devDependencies": { "assertive": "^2.0.0", + "babel-core": "^5.8.33", + "babel-eslint": "^4.1.4", "coffee-script": "^1.9.0", - "eslint": "~1.8.0", + "eslint": "^1.8.0", "eslint-config-airbnb": "~0.1.0", "mocha": "^2.0.1", "npub": "^2.0.0" diff --git a/test/.eslintrc b/test/.eslintrc new file mode 100644 index 0000000..cdb7351 --- /dev/null +++ b/test/.eslintrc @@ -0,0 +1,9 @@ +{ + "extends": "airbnb/base", + "env": { + "mocha": true + }, + "rules": { + "id-length": 0 + } +} diff --git a/test/mocha.opts b/test/mocha.opts index ee852df..7fe7475 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,3 +1,2 @@ ---recursive ---compilers coffee:coffee-script/register --timeout 6000 +--compilers coffee:coffee-script/register,js:babel-core/register diff --git a/test/prefix.coffee b/test/prefix.coffee deleted file mode 100644 index 2ff1aef..0000000 --- a/test/prefix.coffee +++ /dev/null @@ -1,28 +0,0 @@ -'use strict' -assert = require 'assertive' -Promise = require 'bluebird' - -cached = require '..' - -waterfall = (fns) -> - next = (prev, fn) -> prev.then fn - fns.reduce next, Promise.resolve() - -describe 'cache prefix', -> - it 'adds a prefix to named caches', -> - cacheA = cached 'a', backend: { type: 'memory' } - cacheB = cached 'b' - # simulate "writing to the same store" - cacheB.backend = cacheA.backend - - aValue = 'a-value' - bValue = 'b-value' - - waterfall [ - -> cacheA.set 'key', aValue - -> cacheB.set 'key', bValue - -> cacheA.get 'key' - (v) -> assert.equal aValue, v - -> cacheB.get 'key' - (v) -> assert.equal bValue, v - ] diff --git a/test/prefix.js b/test/prefix.js new file mode 100644 index 0000000..fed6365 --- /dev/null +++ b/test/prefix.js @@ -0,0 +1,21 @@ +import assert from 'assertive'; + +import cached from '..'; + +describe('cache prefix', () => { + it('adds a prefix to named cached', async () => { + const cacheA = cached('a', { backend: { type: 'memory' } }); + const cacheB = cached('b'); + // Simulate writing to the same store + cacheB.backend = cacheA.backend; + + const aValue = 'a-value'; + const bValue = 'b-value'; + + await cacheA.set('key', aValue); + await cacheB.set('key', bValue); + + assert.equal(aValue, await cacheA.get('key')); + assert.equal(bValue, await cacheB.get('key')); + }); +}); From 21d67c2eb28a7437183e10b3352039a655f536d1 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 6 Nov 2015 16:03:05 -0800 Subject: [PATCH 20/55] Port main module interface tests to JS --- test/cached.coffee | 27 --------------------------- test/cached.js | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 27 deletions(-) delete mode 100644 test/cached.coffee create mode 100644 test/cached.js diff --git a/test/cached.coffee b/test/cached.coffee deleted file mode 100644 index ebee424..0000000 --- a/test/cached.coffee +++ /dev/null @@ -1,27 +0,0 @@ -'use strict' -assert = require 'assertive' - -cached = require '..' - -describe 'cached', -> - beforeEach -> - cached.dropNamedCaches() - - it 'is a function', -> - assert.hasType Function, cached - - it 'can create different named caches', -> - assert.notEqual cached('bar'), cached('foo') - assert.notEqual cached(), cached('foo') - assert.deepEqual [ - 'bar', 'foo', 'default' - ], cached.knownCaches() - - it 'the default cache is named "default"', -> - assert.equal cached('default'), cached() - - it 'returns the same named cache for subsequent calls', -> - assert.equal cached('foo'), cached('foo') - - it 'knows no caches', -> - assert.deepEqual [], cached.knownCaches() diff --git a/test/cached.js b/test/cached.js new file mode 100644 index 0000000..3738477 --- /dev/null +++ b/test/cached.js @@ -0,0 +1,25 @@ +import assert from 'assertive'; + +import cached from '..'; + +describe('cached', () => { + beforeEach(() => cached.dropNamedCaches()); + + it('is a function', () => + assert.hasType(Function, cached)); + + it('starts out with no known caches', () => + assert.deepEqual([], cached.knownCaches())); + + it('can create different named caches', () => { + assert.notEqual(cached('bar'), cached('foo')); + assert.notEqual(cached(), cached('foo')); + assert.deepEqual([ 'bar', 'foo', 'default' ], cached.knownCaches()); + }); + + it('the default cache is named "default"', () => + assert.equal(cached('default'), cached())); + + it('returns the same named cache for subsequent calls', () => + assert.equal(cached('foo'), cached('foo'))); +}); From e99b27edac16926edd220cd333a1a50885b44e47 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 6 Nov 2015 17:37:52 -0800 Subject: [PATCH 21/55] Complete switch to JS, remove coffee-script --- lib/backends/memory.js | 18 +-- lib/cache.js | 125 ++++--------------- lib/get-or-else.js | 96 +++++++++++++++ lib/util.js | 68 +++++++++++ package.json | 2 +- test/_backends.js | 22 ++++ test/_unhandled-rejection.js | 15 +++ test/cache.coffee | 228 ----------------------------------- test/cache.js | 15 +++ test/get-or-else.js | 139 +++++++++++++++++++++ test/get-set.js | 52 ++++++++ test/mocha.opts | 3 +- 12 files changed, 435 insertions(+), 348 deletions(-) create mode 100644 lib/get-or-else.js create mode 100644 lib/util.js create mode 100644 test/_backends.js create mode 100644 test/_unhandled-rejection.js delete mode 100644 test/cache.coffee create mode 100644 test/cache.js create mode 100644 test/get-or-else.js create mode 100644 test/get-set.js diff --git a/lib/backends/memory.js b/lib/backends/memory.js index b7dd32d..a3ac714 100644 --- a/lib/backends/memory.js +++ b/lib/backends/memory.js @@ -33,19 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. var Bluebird = require('bluebird'); -function expiresAt(seconds) { - if (seconds === 0) { - return 0; - } - return Date.now() + parseInt(seconds, 10) * 1000; -} - -function isExpired(expires) { - if (!expires) { - return false; - } - return Date.now() > new Date(expires).getTime(); -} +var util = require('../util'); /* Stores everything just in memory */ function MemoryBackend() { @@ -56,7 +44,7 @@ module.exports = MemoryBackend; MemoryBackend.prototype.get = function get(key) { var wrappedValue = this.cache[key] || null; - if (isExpired(wrappedValue && wrappedValue.e)) { + if (util.isExpired(wrappedValue && wrappedValue.e)) { wrappedValue = null; delete this.cache[key]; } @@ -66,7 +54,7 @@ MemoryBackend.prototype.get = function get(key) { MemoryBackend.prototype.set = function set(key, value, options) { this.cache[key] = { d: value, - e: expiresAt(options.expire), + e: util.expiresAt(options.expire), }; return Bluebird.resolve(value); }; diff --git a/lib/cache.js b/lib/cache.js index 4e76e31..f17873f 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -31,48 +31,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 'use strict'; -var Bluebird = require('bluebird'); var _ = require('lodash'); var Backend = require('./backend'); - -function toPromise(val) { - if (typeof val === 'function') { - return Bluebird.resolve(val()); - } - return Bluebird.resolve(val); -} - -function expiresAt(seconds) { - if (seconds === 0) { - return 0; - } - return Date.now() + parseInt(seconds, 10) * 1000; -} - -function isExpired(expires) { - if (expires === 0) { - return false; - } - return Date.now() > new Date(expires).getTime(); -} - -function optionalOpts(opts, cb) { - if (!cb && typeof opts === 'function') { - return { cb: opts, opts: null }; - } - return { cb: cb, opts: opts }; -} - -function extractValue(wrappedValue) { - var value = wrappedValue && wrappedValue.d; - // Normalize `undefined` into `null` - return value === undefined ? null : value; -} - -function defaultToNull(/* error */) { - return null; -} +var getOrElse = require('./get-or-else'); +var util = require('./util'); function Cache(options) { this.defaults = { @@ -115,89 +78,45 @@ Cache.prototype.prepareOptions = function prepareOptions(options) { return _.extend({}, this.defaults, options); }; -Cache.prototype.set = function set(rawKey, val, _opts, _cb) { - var args = optionalOpts(_opts, _cb); - var key = this.applyPrefix(rawKey); - var optsWithDefaults = this.prepareOptions(args.opts); - +Cache.prototype._set = function _set(key, val, options) { var self = this; function writeToBackend(resolvedValue) { return self.backend.set(key, { - b: expiresAt(optsWithDefaults.freshFor), + b: util.expiresAt(options.freshFor), d: resolvedValue, - }, optsWithDefaults); + }, options); } - return toPromise(val).then(writeToBackend).nodeify(args.cb); + return util.toPromise(val).then(writeToBackend); +}; + +Cache.prototype.set = function set(rawKey, val, _opts, _cb) { + var args = util.optionalOpts(_opts, _cb); + var key = this.applyPrefix(rawKey); + var optsWithDefaults = this.prepareOptions(args.opts); + + return this._set(key, val, optsWithDefaults).nodeify(args.cb); }; -Cache.prototype.getWrapped = function getWrapped(key) { +Cache.prototype._getWrapped = function _getWrapped(key) { return this.backend.get(key); }; +// For backwards compatibility, eventually we should deprecate this. +// It *should* be a private API. +Cache.prototype.getWrapped = Cache.prototype._getWrapped; Cache.prototype.get = function get(rawKey, cb) { var key = this.applyPrefix(rawKey); - return this.getWrapped(key).then(extractValue).nodeify(cb); + return this._getWrapped(key).then(util.extractValue).nodeify(cb); }; -Cache.prototype.getOrElse = function getOrElse(rawKey, val, _opts, _cb) { +Cache.prototype.getOrElse = function _getOrElse(rawKey, val, _opts, _cb) { var key = this.applyPrefix(rawKey); - var args = optionalOpts(_opts, _cb); + var args = util.optionalOpts(_opts, _cb); var optsWithDefaults = this.prepareOptions(args.opts); - var self = this; - - function resetStaleOrPending(passThroughData) { - delete self.staleOrPending[key]; - return passThroughData; - } - - function writeValue(generatedValue) { - return self.set(rawKey, generatedValue, optsWithDefaults) - .then(extractValue) - .catch(function fallbackToLoadedValue() { - return generatedValue === undefined ? null : generatedValue; - }); - } - - function refreshValue() { - var refreshed; - - function handleWriteError(err) { - resetStaleOrPending(); - if (refreshed.wasEverReturned) { - return Bluebird.reject(err); - } - return null; - } - - refreshed = toPromise(val) - .then(writeValue) - .then(resetStaleOrPending, handleWriteError); - - return refreshed; - } - - function verifyFreshness(wrappedValue) { - var hit = !!wrappedValue; - var expired = isExpired(wrappedValue && wrappedValue.b); - var loadingNewValue = self.staleOrPending[key] !== undefined; - var dataFromCache = extractValue(wrappedValue); - if ((!hit || expired) && !loadingNewValue) { - self.staleOrPending[key] = refreshValue(); - loadingNewValue = true; - } - if ((dataFromCache === null) && loadingNewValue) { - self.staleOrPending[key].wasEverReturned = true; - return self.staleOrPending[key]; - } - return dataFromCache; - } - return this.getWrapped(key) - .catch(defaultToNull) - .then(verifyFreshness) - .nodeify(args.cb); + return getOrElse(this, key, val, optsWithDefaults).nodeify(args.cb); }; module.exports = Cache; diff --git a/lib/get-or-else.js b/lib/get-or-else.js new file mode 100644 index 0000000..01f62b9 --- /dev/null +++ b/lib/get-or-else.js @@ -0,0 +1,96 @@ +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +'use strict'; + +var Bluebird = require('bluebird'); +var _ = require('lodash'); + +var util = require('./util'); + +function getOrElse(cache, key, val, opts) { + function resetStaleOrPending(passThroughData) { + delete cache.staleOrPending[key]; + return passThroughData; + } + + function writeValue(generatedValue) { + function fallbackToLoadedValue() { + return generatedValue === undefined ? null : generatedValue; + } + + return cache._set(key, generatedValue, opts) + .then(util.extractValue) + .catch(fallbackToLoadedValue); + } + + function refreshValue() { + var refreshed; + + function handleWriteError(err) { + resetStaleOrPending(); + if (refreshed.wasEverReturned) { + return Bluebird.reject(err); + } + return null; + } + + refreshed = util.toPromise(val) + .then(writeValue) + .then(resetStaleOrPending, handleWriteError); + + return refreshed; + } + + function verifyFreshness(wrappedValue) { + var hit = !!wrappedValue; + var expired = util.isExpired(wrappedValue && wrappedValue.b); + var loadingNewValue = cache.staleOrPending[key] !== undefined; + + if ((!hit || expired) && !loadingNewValue) { + cache.staleOrPending[key] = refreshValue(); + loadingNewValue = true; + } + + var dataFromCache = util.extractValue(wrappedValue); + if ((dataFromCache === null) && loadingNewValue) { + cache.staleOrPending[key].wasEverReturned = true; + return cache.staleOrPending[key]; + } + + return dataFromCache; + } + + return cache._getWrapped(key) + .catch(_.constant(null)) + .then(verifyFreshness); +} +module.exports = getOrElse; diff --git a/lib/util.js b/lib/util.js new file mode 100644 index 0000000..daca492 --- /dev/null +++ b/lib/util.js @@ -0,0 +1,68 @@ +/* +Copyright (c) 2014, Groupon, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the name of GROUPON nor the names of its contributors may be +used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT +HOLDER 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. + */ +'use strict'; + +var Bluebird = require('bluebird'); + +exports.expiresAt = function expiresAt(seconds) { + if (seconds === 0) { + return 0; + } + return Date.now() + parseInt(seconds, 10) * 1000; +}; + +exports.isExpired = function isExpired(expires) { + if (!expires) { + return false; + } + return Date.now() > new Date(expires).getTime(); +}; + +exports.extractValue = function extractValue(wrappedValue) { + var value = wrappedValue && wrappedValue.d; + // Normalize `undefined` into `null` + return value === undefined ? null : value; +}; + +exports.toPromise = function toPromise(val) { + if (typeof val === 'function') { + return Bluebird.resolve(val()); + } + return Bluebird.resolve(val); +}; + +exports.optionalOpts = function optionalOpts(opts, cb) { + if (!cb && typeof opts === 'function') { + return { cb: opts, opts: null }; + } + return { cb: cb, opts: opts }; +}; diff --git a/package.json b/package.json index 64ff3db..8d161b1 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "cached", "version": "4.0.2", "description": "Simple access to a cache", + "license": "BSD-3-Clause", "main": "lib/cached.js", "keywords": [ "memcached", @@ -42,7 +43,6 @@ "assertive": "^2.0.0", "babel-core": "^5.8.33", "babel-eslint": "^4.1.4", - "coffee-script": "^1.9.0", "eslint": "^1.8.0", "eslint-config-airbnb": "~0.1.0", "mocha": "^2.0.1", diff --git a/test/_backends.js b/test/_backends.js new file mode 100644 index 0000000..9e64a33 --- /dev/null +++ b/test/_backends.js @@ -0,0 +1,22 @@ +import {defaults} from 'lodash'; + +import Cache from '../lib/cache'; + +const backendOptions = { + hosts: `${process.env.MEMCACHED__HOST || '127.0.0.1'}:11211`, +}; + +export default function withBackends(createTestCases) { + [ 'memory', 'memcached' ].forEach(backendType => { + describe(`with backend "${backendType}"`, () => { + const cache = new Cache({ + backend: defaults({ type: backendType }, backendOptions), + name: 'awesome-name', + debug: true, + }); + after(() => cache.end()); + + createTestCases(cache); + }); + }); +} diff --git a/test/_unhandled-rejection.js b/test/_unhandled-rejection.js new file mode 100644 index 0000000..1571cb5 --- /dev/null +++ b/test/_unhandled-rejection.js @@ -0,0 +1,15 @@ +/* eslint no-console:0 */ +import Bluebird from 'bluebird'; + +const unhandledRejections = []; +Bluebird.onPossiblyUnhandledRejection(error => { + console.error('Possibly unhandled rejection:', error.stack); + unhandledRejections.push(error); +}); + +after('Check for unhandled rejections', () => { + if (unhandledRejections.length) { + console.error('Found %d unhandled rejections', unhandledRejections.length); + throw unhandledRejections[0]; + } +}); diff --git a/test/cache.coffee b/test/cache.coffee deleted file mode 100644 index 1819178..0000000 --- a/test/cache.coffee +++ /dev/null @@ -1,228 +0,0 @@ -'use strict' -assert = require 'assertive' - -Promise = require 'bluebird' -{defaults} = require 'lodash' -Cache = require '../lib/cache' -cached = require '../lib/cached' - -values = - key1: 'Value 1' - key2: 'Value 2' - key3: 'Value 3' - -backendOptions = - hosts: - if process.env.MEMCACHED__HOST - "#{process.env.MEMCACHED__HOST}:11211" - else - '127.0.0.1:11211' - -waterfall = (fns) -> - next = (prev, fn) -> prev.then fn - fns.reduce next, Promise.resolve() - -unexpected = (value) -> - console.error value - throw new Error 'Unexpected value' - -unhandledRejections = [] -Promise.onPossiblyUnhandledRejection (err) -> - console.error 'Possibly unhandled rejection:', err.stack - unhandledRejections.push err - -after 'Check for unhandled rejections', -> - if unhandledRejections.length - console.error 'Found %d unhandled rejections', unhandledRejections.length - throw unhandledRejections[0] - -describe 'Cache', -> - it 'always has a backend', -> - cache = new Cache {} - assert.notEqual undefined, cache.backend - - it 'has a "noop" backend by default', -> - cache = new Cache {} - assert.equal 'noop', cache.backend.type - - describe 'Cache#set', -> - beforeEach -> - @cache = new Cache backend: 'memory' - - it 'supports callback style', (done) -> - @cache.set 'key1', values.key1, done - - it 'supports promise style', (done) -> - @cache.set('key2', values.key2, { expire: 1 }).nodeify done - - [ 'memory', 'memcached' ].map (backendType) -> - describe "with backend \"#{backendType}\"", -> - before -> - @cache = new Cache backend: defaults({ type: backendType }, backendOptions), name: 'awesome-name', debug: true - after -> - @cache.end() - - describe 'Cache#get', -> - it 'gets a previously set key', -> - waterfall [ - => - @cache.set 'key1', values.key1 - => - @cache.get 'key1' - (val) -> - assert.equal values.key1, val - ] - - it 'is aware of expires', -> - stored = Promise.all [ - @cache.set 'key1', values.key1, expire: 1 - @cache.set 'key2', values.key2, expire: 0 - @cache.set 'key3', values.key3, expire: 4 - ] - - retrieve = stored.delay(2000).then => - Promise.all [ - @cache.get 'key1' - @cache.get 'key2' - @cache.get 'key3' - ] - - retrieve.spread (val1, val2, val3) -> - # less than 2 seconds lifetime - assert.equal null, val1 - # eternal lifetime - assert.equal values.key2, val2 - # more than 2 seconds lifetime - assert.equal values.key3, val3 - - describe 'Cache#getOrElse', -> - it 'replaces values lazily', -> - generatorCalled = 0 - # generate a value in a certain time - valueGenerator = (v, ms) -> -> - ++generatorCalled - Promise.resolve(v).delay(ms) - - originalValue = values.key1 - generatedValue = 'G1' - - valueA = 'NOT_SET' # initial set - valueB = 'NOT_SET' # getOrElse #1 (should be original value) - valueC = 'NOT_SET' # getOrElse #2 (should be original value) - valueD = 'NOT_SET' # getOrElse #3 (should be generated value) - - chainIsOver = false - - # abstract: - # * First we set a value that is fresh for one second. - # * We then wait 1sec+ to be sure that the value is stale - # * When we #get the value now, it should be returned though it's stale - # * Then we call #getOrElse with an "expensive" value generator - # * #getOrElse should immediately return with the stale value while starting - # to generate the new value in the background - # * While generation is running, a second call to #getOrElse should - # - not start another value generator - # - return immediately with the stale value - # * After generating the value is done we call #getOrElse a 3rd time. We should - # be getting the generated value and not be starting another generator - waterfall [ - => - @cache.set 'key1', originalValue, freshFor: 1 - -> - Promise.delay 1200 - => - @cache.get('key1') - (v) -> - assert.equal originalValue, v - - => - @cache.getOrElse 'key1', valueGenerator(generatedValue, 100), freshFor: 5 - (v) -> - assert.equal originalValue, v - -> - Promise.delay 50 # while generating - => - @cache.getOrElse 'key1', valueGenerator('G2', 5000), freshFor: 5 - (v) -> - assert.equal originalValue, v - -> - Promise.delay 100 - => - @cache.getOrElse 'key1', valueGenerator('G3', 5000), freshFor: 5 - (v) -> - assert.equal generatedValue, v - assert.equal 1, generatorCalled - ] - - it 'throws errors', (done) -> - errorGenerator = cached.deferred (cb) -> - cb new Error 'Big Error' - - theCallback = (err, data) -> - assert.equal undefined, data - assert.equal 'Big Error', err?.message - done() - - @cache.getOrElse 'bad_keys', errorGenerator, freshFor: 1, theCallback - - describe 'refresh of expired value failing', -> - before 'set value that is stale after a second', -> - @cache.set 'key1', values.key1, freshFor: 1, expire: 3 - - before 'wait >1 seconds', (done) -> setTimeout(done, 1100) - - it 'returns the original value if generating a new value fails', -> - generator = -> Promise.reject new Error 'Oops' - @cache.getOrElse 'key1', generator - .then assert.equal.bind(null, values.key1) - - describe 'after two more second', -> - before 'wait >2 seconds', (done) -> setTimeout(done, 2100) - - it 'fails to return a value if generating fails again', -> - generator = -> Promise.reject new Error 'Oops' - @cache.getOrElse 'key1', generator - .then unexpected, (err) -> - assert.equal 'Oops', err.message - - describe 'backed.get failing', -> - before -> - @failCache = new Cache { - backend: @cache.backend - name: 'awesome-name' - debug: true - } - @failCache.getWrapped = -> - Promise.reject new Error('backend get troubles') - - it 'falls back on the value refresher', (done) -> - valueGenerator = cached.deferred (cb) -> - cb null, 'fresh cats' - - theCallback = (err, data) -> - assert.equal null, err - assert.equal 'fresh cats', data - done() - - @failCache.getOrElse 'bad_get', valueGenerator, freshFor: 5, theCallback - - describe 'backend.set failing', -> - before -> - @failCache = new Cache { - backend: @cache.backend - name: 'awesome-name' - debug: true - } - @failCache.set = -> - Promise.reject new Error('backend set troubles') - - it 'falls back on the generated value', (done) -> - valueGenerator = cached.deferred (cb) -> - cb null, 'generated bunnies' - - theCallback = (err, data) -> - assert.equal null, err - assert.equal 'generated bunnies', data - done() - - @failCache.getOrElse 'bad_set', valueGenerator, freshFor: 5, theCallback diff --git a/test/cache.js b/test/cache.js new file mode 100644 index 0000000..9c34914 --- /dev/null +++ b/test/cache.js @@ -0,0 +1,15 @@ +import assert from 'assertive'; + +import Cache from '../lib/cache'; + +describe('Cache', () => { + it('always has a backend', () => { + const cache = new Cache({}); + assert.truthy(cache.backend); + }); + + it('has a "noop" backend by default', () => { + const cache = new Cache({}); + assert.equal('noop', cache.backend.type); + }); +}); diff --git a/test/get-or-else.js b/test/get-or-else.js new file mode 100644 index 0000000..5f761e7 --- /dev/null +++ b/test/get-or-else.js @@ -0,0 +1,139 @@ +import assert from 'assertive'; +import Bluebird from 'bluebird'; + +import Cache from '../lib/cache'; + +import withBackends from './_backends'; + +function assertRejects(promise) { + return promise.then(() => { + throw new Error('Did not fail as expected'); + }, error => error); +} + +describe('Cache::getOrElse', () => { + describe('backed.get failing', () => { + let cache; + before(() => { + cache = new Cache({ backend: 'memory', name: 'awesome-name' }); + cache.getWrapped = () => + Bluebird.reject(new Error('backend get troubles')); + }); + + function generateCats() { + return 'fresh cats'; + } + + it('falls back on the value refresher', async () => { + const value = + await cache.getOrElse('bad_get', generateCats, { freshFor: 5 }); + assert.equal('fresh cats', value); + }); + }); + + describe('backend.set failing', () => { + let cache; + before(() => { + cache = new Cache({ backend: 'memory', name: 'awesome-name' }); + cache.set = () => + Bluebird.reject(new Error('backend set troubles')); + }); + + function generateBunnies() { + return 'generated bunnies'; + } + + it('falls back on the generated value', async () => { + const value = + await cache.getOrElse('bad_set', generateBunnies, { freshFor: 5 }); + assert.equal('generated bunnies', value); + }); + }); + + withBackends(cache => { + it('replaces values lazily', async () => { + let generatorCalled = 0; + // generate a value in a certain time + function valueGenerator(v, ms) { + return () => { + ++generatorCalled; + return Bluebird.resolve(v).delay(ms); + }; + } + + const originalValue = 'original-value'; + + // 1. Set the value with a freshFor of 1 second + await cache.set('key1', originalValue, { freshFor: 1 }); + // 2. Wait more than 1 second (the value is now stale) + await Bluebird.delay(1200); + // 3. Make sure we can still retrieve the original value. + // It's stale - but not expired/gone. + assert.equal(originalValue, await cache.get('key1')); + + // 4. The value is stale, so it should be calling the value generator. + // But it should *return* the original value asap. + assert.equal(originalValue, + await cache.getOrElse('key1', valueGenerator('G1', 100), { freshFor: 5 })); + + // Let the generator be generating... + await Bluebird.delay(50); + + // 5. Generating 'G1' in the last step takes 100ms but we only waited 50ms yet. + // This means we still expect to see the original value. + // 'G2' should never be generated since there's already a pending value. + assert.equal(originalValue, + await cache.getOrElse('key1', valueGenerator('G2', 5000), { freshFor: 5 })); + + // Let the generator be generating... + await Bluebird.delay(100); + + // 6. Now G1 is done generating (we waited a total of 150ms), so we shouldn't + // see the original value anymore but the new, improved 'G1'. + assert.equal('G1', + await cache.getOrElse('key1', valueGenerator('G3', 5000), { freshFor: 5 })); + + // 7. Making sure that the value generator was only called once during this test. + // We just generated 'G1', the other times we either had a pending value + // or the value was still fresh (last/'G3' call). + assert.equal(1, generatorCalled); + }); + + it('throws errors', async () => { + function errorGenerator() { + throw new Error('Big Error'); + } + + const error = await assertRejects( + cache.getOrElse('bad_keys', errorGenerator, { freshFor: 1 })); + assert.equal('Big Error', error.message); + }); + + describe('refresh of expired value failing', () => { + const key = 'refresh-key'; + const value = 'refresh-value'; + + before('set value that is stale after a second', () => + cache.set(key, value, { freshFor: 1, expire: 3 })); + + before('wait >1 seconds', () => Bluebird.delay(1100)); + + function generator() { + return Bluebird.reject(new Error('Oops')); + } + + it('returns the original value if generating a new value fails', async () => { + assert.equal(value, await cache.getOrElse(key, generator)); + }); + + describe('after two more second', () => { + before('wait >2 seconds', () => Bluebird.delay(2100)); + + it('fails to return a value if generating fails again', async () => { + const error = await assertRejects(cache.getOrElse(key, generator)); + assert.equal('Oops', error.message); + }); + }); + }); + }); +}); diff --git a/test/get-set.js b/test/get-set.js new file mode 100644 index 0000000..07cc7a2 --- /dev/null +++ b/test/get-set.js @@ -0,0 +1,52 @@ +import assert from 'assertive'; +import Bluebird from 'bluebird'; + +import withBackends from './_backends'; + +describe('Cache::{get,set}', () => { + withBackends(cache => { + it('get/set (callback style)', done => { + cache.set('callback-key', 'callback-value', setError => { + if (setError) return done(setError); + cache.get('callback-key', (getError, value) => { + if (getError) return done(getError); + let assertError = null; + try { + assert.equal('callback-value', value); + } catch (error) { + assertError = error; + } + done(assertError); + }); + }); + }); + + it('get/set (promise style)', async () => { + await cache.set('promise-key', 'promise-value', { expire: 1 }); + assert.equal('promise-value', await cache.get('promise-key')); + }); + + it('honors expires', async () => { + const values = { + key1: 'Value 1', + key2: 'Value 2', + key3: 'Value 3', + }; + + await Bluebird.all([ + cache.set('key1', values.key1, { expire: 1 }), + cache.set('key2', values.key2, { expire: 0 }), + cache.set('key3', values.key3, { expire: 4 }), + ]); + + await Bluebird.delay(2000); + + const [ expired, eternal, hit ] = + await Bluebird.map([ 'key', 'key2', 'key3' ], key => cache.get(key)); + + assert.equal(null, expired); + assert.equal(values.key2, eternal); + assert.equal(values.key3, hit); + }); + }); +}); diff --git a/test/mocha.opts b/test/mocha.opts index 7fe7475..6c65f67 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,2 +1,3 @@ --timeout 6000 ---compilers coffee:coffee-script/register,js:babel-core/register +--slow 4000 +--compilers js:babel-core/register From 254108273d405d021f9b8f9fe9ba838f03c7f6fe Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Fri, 6 Nov 2015 17:39:47 -0800 Subject: [PATCH 22/55] Remove examples, not maintained --- examples/cached-usage.coffee | 72 ------------------------------------ examples/memcached.coffee | 67 --------------------------------- examples/memory.coffee | 67 --------------------------------- 3 files changed, 206 deletions(-) delete mode 100644 examples/cached-usage.coffee delete mode 100644 examples/memcached.coffee delete mode 100644 examples/memory.coffee diff --git a/examples/cached-usage.coffee b/examples/cached-usage.coffee deleted file mode 100644 index a47321f..0000000 --- a/examples/cached-usage.coffee +++ /dev/null @@ -1,72 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - -# 1. Create a named cache -# Once created, you can retrieve the same cache-instance later by -# just calling `cached "divisions"` without any additional arguments. -cached = require ".." -divisionsCache = cached "divisions", backend: "memcached" - -# 2. Dump stuff in the cache -divisionsCache.set "chicago", { name: "Chicago" }, -> - console.log "Stored in cache." - - # 3. Get stuff from the cache - divisionsCache.get "chicago", (err, data) -> - console.log "Got data:", data - - # 4. Make it smarter: getOrElse - # This function allows you to (almost) always keep the cache populated - # and refetch the data in the background. It uses two settings: - # - # * freshFor: Age in seconds after which data in the cache will be replaced - # * expire: Age in seconds when data will be invalidated - # - # As long as you don't let data expire, you will always get the values - # directly from the cache and it will be updated asynchronously from getting. - callCounter = 0 - fetchSF = cached.deferred (cb) -> - ++callCounter - setTimeout (-> - # Some fetch operation - cb null, { name: "San Francisco" } - ), 1000 - - opts = { freshFor: 2, expire: 60 } - divisionsCache.getOrElse "san-francisco", fetchSF, opts, (err, data) -> - console.log "Got data:", data - - divisionsCache.getOrElse "san-francisco", fetchSF, opts, (err, data) -> - console.log "Got data:", data - - # It's smart enough to only fetch once. - console.log "Called the fetch function #{callCounter} times." diff --git a/examples/memcached.coffee b/examples/memcached.coffee deleted file mode 100644 index cfa77c4..0000000 --- a/examples/memcached.coffee +++ /dev/null @@ -1,67 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - - -cached = require '..' - -cache = cached 'my-cache', backend: 'memcached' - -values = - key1: 'Value 1' - key2: 'Value 2' - key3: 'Value 3' - -cache.set 'key1', values.key1, -> - console.log 'key1: Set callback style' - -cache.set('key2', values.key2, { expire: 1 }) -.then -> - console.log 'key2: Set promise style, expires after 1 second' - -cache.set('key3', values.key3, freshFor: 2) -.then -> - console.log 'key3: Fresh for 2 seconds' - -[ 100, 3000 ].map (timeout) -> - tryGetFromCache = -> - console.log "Trying to get values after #{timeout} msecs" - [ 'key1', 'key2', 'key3' ].map (key) -> - cache.get key, (err, data) -> - console.log "get (callback):\t#{key}: #{data}" - - cache.get(key).then (data) -> - console.log "get (promise):\t#{key}: #{data}" - - cache.getOrElse(key, "New value for #{key}").then (data) -> - console.log "getOrElse:\t#{key}: #{data}" - - setTimeout(tryGetFromCache, timeout) diff --git a/examples/memory.coffee b/examples/memory.coffee deleted file mode 100644 index f577327..0000000 --- a/examples/memory.coffee +++ /dev/null @@ -1,67 +0,0 @@ -### -Copyright (c) 2014, Groupon, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. - -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. - -Neither the name of GROUPON nor the names of its contributors may be -used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT -HOLDER 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. -### - - -cached = require '..' - -cache = cached 'my-cache', backend: 'memory' - -values = - key1: 'Value 1' - key2: 'Value 2' - key3: 'Value 3' - -cache.set 'key1', values.key1, -> - console.log 'key1: Set callback style' - -cache.set('key2', values.key2, { expire: 1 }) -.then -> - console.log 'key2: Set promise style, expires after 1 second' - -cache.set('key3', values.key3, freshFor: 2) -.then -> - console.log 'key3: Fresh for 2 seconds' - -[ 100, 3000 ].map (timeout) -> - tryGetFromCache = -> - console.log "Trying to get values after #{timeout} msecs" - [ 'key1', 'key2', 'key3' ].map (key) -> - cache.get key, (err, data) -> - console.log "get (callback):\t#{key}: #{data}" - - cache.get(key).then (data) -> - console.log "get (promise):\t#{key}: #{data}" - - cache.getOrElse(key, "New value for #{key}").then (data) -> - console.log "getOrElse:\t#{key}: #{data}" - - setTimeout(tryGetFromCache, timeout) From dfcf0aaabaa0ac86453b490342ada11807abfdf6 Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Tue, 15 Dec 2015 15:54:55 -0800 Subject: [PATCH 23/55] 4.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d161b1..0aea7a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cached", - "version": "4.0.2", + "version": "4.1.0", "description": "Simple access to a cache", "license": "BSD-3-Clause", "main": "lib/cached.js", From bdac8c6f1f68e6296abf513c941736c88771149a Mon Sep 17 00:00:00 2001 From: Jan Krems Date: Tue, 26 Jan 2016 12:33:20 -0800 Subject: [PATCH 24/55] chore: Switch to nlm --- .editorconfig | 11 ++ .eslintrc | 8 +- .gitignore | 4 +- .npmrc | 1 + .travis.yml | 16 +- CONTRIBUTING.md | 160 ++++++++++++++++--- lib/backend.js | 58 +++---- lib/backends/memcached.js | 60 ++++--- lib/backends/memory.js | 58 +++---- lib/backends/noop.js | 58 +++---- lib/cache.js | 58 +++---- lib/cached.js | 58 +++---- lib/get-or-else.js | 58 +++---- lib/util.js | 58 +++---- package.json | 59 +++---- test/.eslintrc | 4 +- test/_backends.js | 4 +- test/{cache.js => cache.test.js} | 0 test/{cached.js => cached.test.js} | 2 +- test/{get-or-else.js => get-or-else.test.js} | 0 test/{get-set.js => get-set.test.js} | 4 +- test/mocha.opts | 1 + test/{prefix.js => prefix.test.js} | 0 23 files changed, 440 insertions(+), 300 deletions(-) create mode 100644 .editorconfig create mode 100644 .npmrc rename test/{cache.js => cache.test.js} (100%) rename test/{cached.js => cached.test.js} (90%) rename test/{get-or-else.js => get-or-else.test.js} (100%) rename test/{get-set.js => get-set.test.js} (92%) rename test/{prefix.js => prefix.test.js} (100%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..beffa30 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintrc b/.eslintrc index 68d14a4..0026929 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,9 +1,3 @@ { - "extends": "airbnb/legacy", - "rules": { - "id-length": 0, - "vars-on-top": 0, - "strict": [2, "global"], - "no-param-reassign": 0 - } + "extends": "groupon/legacy" } diff --git a/.gitignore b/.gitignore index eb03e3e..0138158 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -node_modules +node_modules/ +npm-debug.log +/tmp *.log diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..38f11c6 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org diff --git a/.travis.yml b/.travis.yml index 7d88594..748132a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,17 @@ language: node_js node_js: - - "0.10" - - "4" + - '0.10' + - '4' services: memcached +before_install: +- npm install -g npm@latest-2 +before_deploy: + - git config --global user.email "opensource@groupon.com" + - git config --global user.name "Groupon" +deploy: + provider: script + script: './node_modules/.bin/nlm release' + skip_cleanup: true + on: + branch: master + node: '4' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bcf866b..9e412ba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,30 +1,146 @@ -# Contribution Guide + -Please follow this guide when -creating issues or pull requests. +# Contributing -## Reporting a Bug +🎉🏅 Thanks for helping us improve this project! 🙏 -Before reporting a bug, -make sure you are using the latest versions of cached. +This document outlines some of the practices we care about. +If you have any questions or suggestions about the process, +feel free to [open an issue](#reporting-issues). -When reporting a bug with cached, -please provide a minimal test case. -This can be a gist, -inline in the description, -or in the form of a pull request -that includes a failing test. +## How Can I Contribute? -If you are contributing a bug fix, -make sure it has a passing test -in your pull request. +### Reporting Issues -## Adding a Feature +If you find any mistakes in the docs or a bug in the code, +please [open an issue in Github](https://github.com/groupon/node-cached/issues/new) so we can look into it. +You can also [create a PR](#contributing-code) fixing it yourself, or course. -Before implementing features, -try to make sure that -(1) no one else is currently working on that and -(2) you have checked with the maintainers -that this is something they would like to see. +If you report a bug, please follow these guidelines: -All features should have tests. +* Make sure the bug exists in the latest version. +* Include instructions on how to reproduce the issue. + The instructions should be as minimal as possible + and answer the three big questions: + 1. What are the exact steps you took? This includes the exact versions of node, npm, and any packages involved. + 1. What result are you expecting? + 1. What is the actual result? + +### Improving Documentation + +For small documentation changes, you can use [Github's editing feature](https://help.github.com/articles/editing-files-in-another-user-s-repository/). +The only thing to keep in mind is to prefix the commit message with "docs: ". +The detault commit message generated by Github will lead to a failing CI build. + +For larger updates to the documentation +it might be better to follow the [instructions for contributing code below](#contributing-code). + +### Contributing Code + +**Note:** If you're planning on making substantial changes, +please [open an issue first to discuss your idea](#reporting-issues). +Otherwise you might end up investing a lot of work +only to discover that it conflicts with plans the maintainers might have. + +The general steps for creating a pull request are: + +1. Create a branch for your change. + Always start your branch from the latest `master`. + We often prefix the branch name with our initials, e.g. `jk-a-change`. +1. Run `npm install` to install the dependencies. +1. If you're fixing a bug, be sure to write a test *first*. + That way you can validate that the test actually catches the bug and doesn't pass. +1. Make your changes to the code. + Remember to update the tests if you add new features or change behavior. +1. Run the tests via `npm test`. This will also run style checks and other validations. + You might see errors about uncommitted files. + This is expected until you commit your changes. +1. Once you're done, `git add .` and `git commit`. + Please follow the [commit message conventions](#commits--commit-messages) described below. +1. Push your branch to Github & create a PR. + +#### Code Style + +In addition to any linting rules the project might include, +a few general rules of thumb: + +* Try to match the style of the rest of the code. +* We prefer simple code that is easy to understand over terse, expressive code. +* We try to structure projects by semantics instead of role. + E.g. we'd rather have a `tree.js` module that contains tree traversal-related helpers + than a `helpers.js` module. +* Actually, if you create helpers you might want to put those into a separate package. + That way it's easier to reuse them. + +#### Commits & Commit Messages + +Please follow the [angular commit message conventions](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#-git-commit-guidelines). +We use an automated tool for generating releases +that depends on the conventions to determine the next version and the content of the changelog. +Commit messages that don't follow the conventions will cause `npm test` (and thus CI) to fail. + +The short summary - a commit message should look like this: + +``` +: + + + + + +