diff --git a/README.md b/README.md index e25a093..54c2abe 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ -![Lockr logo](http://i.imgur.com/m5kPjkB.png) -[![Code +![Lockr logo](http://i.imgur.com/m5kPjkB.png)[![Code Climate](https://codeclimate.com/github/tsironis/lockr/badges/gpa.svg)](https://codeclimate.com/github/tsironis/lockr) - > A minimal API wrapper for localStorage. Simple as your high-school locker. Lockr (pronounced /ˈlɒkəʳ/) is an extremely lightweight library (<2kb when minified), designed to facilitate how you interact with localStorage. Saving objects and arrays, numbers or other data types, accessible via a Redis-like API, heavily inspired by [node_redis](https://github.com/mranney/node_redis/). -## How to use lockr +How to use lockr +---------------- In order to user lockr, you firstly need to install it in your project. @@ -15,7 +14,7 @@ In order to user lockr, you firstly need to install it in your project. bower install lockr ``` -or you use npm to install +or you use npm to install ```js npm i lockr --save @@ -27,11 +26,12 @@ or maybe download it manually from [here](https://raw.github.com/tsironis/lockr/ ``` -## API reference +API reference +------------- -```Lockr.set``` - arguments: *[ key, value ]* {String, Number, Array or Object} +`Lockr.set` - arguments: *[ key, value ]* {String, Number, Array or Object} -> Set a key to a particular value or a hash object (```Object``` or ```Array```) under a hash key. +> Set a key to a particular value or a hash object (`Object` or `Array`) under a hash key. You can set the local-key expires; *Example* @@ -39,15 +39,17 @@ or maybe download it manually from [here](https://raw.github.com/tsironis/lockr/ Lockr.set('username', 'Coyote'); // Saved as string Lockr.set('user_id', 12345); // Saved as number Lockr.set('users', [{name: 'John Doe', age: 18}, {name: 'Jane Doe', age: 19}]); +Lockr.set('username', 'Coyote', {expires: 6}); //expires: 6 minutes ``` --- -```Lockr.get``` - arguments: *[ key or hash_key, default value ]* +`Lockr.get` - arguments: *[ key or hash_key, default value ]* > Returns the saved value for given key, even if the saved value is hash object. If value is null or undefined it returns a default value. *Example* + ```js Lockr.get('username'); > "Coyote" @@ -68,9 +70,9 @@ Lockr.get('score', 0): --- -```Lockr.rm``` - arguments: *[ key ]* {String} +`Lockr.rm` - arguments: *[ key ]* {String} -> Remove a key from ```localStorage``` entirely. +> Remove a key from `localStorage` entirely. *Example* @@ -85,7 +87,7 @@ Lockr.get('username'); --- -```Lockr.sadd``` - arguments *[ key, value ]*{String, Number, Array or Object} +`Lockr.sadd` - arguments *[ key, value ]*{String, Number, Array or Object} > Adds a unique value to a particular set under a hash key. @@ -99,7 +101,7 @@ Lockr.sadd("wat", 1); // [1, 2] --- -```Lockr.smembers``` - arguments *[ key ]* +`Lockr.smembers` - arguments *[ key ]* > Returns the values of a particular set under a hash key. @@ -113,7 +115,7 @@ Lockr.smembers("wat"); // [42, 1337] --- -```Lockr.sismember``` - arguments *[ key, value ]* +`Lockr.sismember` - arguments *[ key, value ]* > Returns whether the value exists in a particular set under a hash key. @@ -127,7 +129,7 @@ Lockr.sismember("wat", 2); // false --- -```Lockr.srem``` - arguments *[ key, value ]* +`Lockr.srem` - arguments *[ key, value ]* > Removes a value from a particular set under a hash key. @@ -142,9 +144,9 @@ Lockr.smembers("wat"); // [2] --- -```Lockr.getAll``` - arguments: *null* +`Lockr.getAll` - arguments: *null* -> Returns all saved values & objects, in an ```Array``` +> Returns all saved values & objects, in an `Array` *Example* @@ -152,9 +154,10 @@ Lockr.smembers("wat"); // [2] Lockr.getAll(); > ["Coyote", 12345, [{name: 'John Doe', age: 18}, {name: 'Jane Doe', age: 19}]] ``` + --- -```Lockr.flush()``` - arguments: *null* +`Lockr.flush()` - arguments: *null* > Empties localStorage(). diff --git a/gruntfile.js b/gruntfile.js index f7c924d..6e3a018 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -13,6 +13,7 @@ module.exports = function(grunt) { // Task configuration. jshint: { options: { + asi: false, curly: true, eqeqeq: true, immed: true, @@ -25,6 +26,7 @@ module.exports = function(grunt) { boss: true, eqnull: true, browser: true, + indent: 2, globals: { jQuery: true } diff --git a/lockr.js b/lockr.js index b475cb1..b344319 100644 --- a/lockr.js +++ b/lockr.js @@ -16,21 +16,17 @@ 'use strict'; if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function(elt /*, from*/) - { + Array.prototype.indexOf = function(elt /*, from*/ ) { var len = this.length >>> 0; var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); + from = (from < 0) ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; - for (; from < len; from++) - { + for (; from < len; from++) { if (from in this && - this[from] === elt) + this[from] === elt) return from; } return -1; @@ -38,44 +34,55 @@ } Lockr.prefix = ""; + Lockr.expires = new Date().getTime()+1e6*6*6*24*365; //the default expires more than 10 years Lockr._getPrefixedKey = function(key, options) { options = options || {}; - if (options.noPrefix) { return key; } else { return this.prefix + key; } - }; - Lockr.set = function (key, value, options) { - var query_key = this._getPrefixedKey(key, options); + Lockr.getExpirationTime = function(options) { + options = options || {}; + if (options.expires) { + return new Date().getTime() + options.expires * 60 * 1000; + } else { + return this.expires; + }; + } - try { - localStorage.setItem(query_key, JSON.stringify({"data": value})); + Lockr.set = function(key, value, options) { + var query_key = this._getPrefixedKey(key, options), + expires = this.getExpirationTime(options); + try { + localStorage.setItem(query_key, JSON.stringify({"data": value, "timestamp":expires})); } catch (e) { - if (console) console.warn("Lockr didn't successfully save the '{"+ key +": "+ value +"}' pair, because the localStorage is full."); + if (console) console.warn("Lockr didn't successfully save the '{" + key + ": " + value + "}' pair, because the localStorage is full."); } }; - Lockr.get = function (key, missing, options) { + Lockr.get = function(key, missing, options) { var query_key = this._getPrefixedKey(key, options), - value; + value; try { value = JSON.parse(localStorage.getItem(query_key)); + if (!value.timestamp) { + value.timestamp = this.getExpirationTime(options); + }; } catch (e) { - if(localStorage[query_key]) { - value = {data: localStorage.getItem(query_key)}; - } else{ - value = null; - } + if (localStorage[query_key]) { + value = { data: localStorage.getItem(query_key), timestamp: this.getExpirationTime(options) }; + } else { + value = null; + } } - if(value === null) { + if (value === null) { return missing; - } else if (typeof value === 'object' && typeof value.data !== 'undefined') { + } else if (typeof value === 'object' && typeof value.data !== 'undefined' && new Date().getTime() < value.timestamp) { return value.data; } else { return missing; @@ -84,7 +91,7 @@ Lockr.sadd = function(key, value, options) { var query_key = this._getPrefixedKey(key, options), - json; + json; var values = Lockr.smembers(key); @@ -94,17 +101,17 @@ try { values.push(value); - json = JSON.stringify({"data": values}); + json = JSON.stringify({ "data": values }); localStorage.setItem(query_key, json); } catch (e) { console.log(e); - if (console) console.warn("Lockr didn't successfully add the "+ value +" to "+ key +" set, because the localStorage is full."); + if (console) console.warn("Lockr didn't successfully add the " + value + " to " + key + " set, because the localStorage is full."); } }; Lockr.smembers = function(key, options) { var query_key = this._getPrefixedKey(key, options), - value; + value; try { value = JSON.parse(localStorage.getItem(query_key)); @@ -119,8 +126,6 @@ }; Lockr.sismember = function(key, value, options) { - var query_key = this._getPrefixedKey(key, options); - return Lockr.smembers(key).indexOf(value) > -1; }; @@ -132,7 +137,7 @@ return allKeys; } - allKeys.forEach(function (key) { + allKeys.forEach(function(key) { if (key.indexOf(Lockr.prefix) !== -1) { keys.push(key.replace(Lockr.prefix, '')); } @@ -141,17 +146,17 @@ return keys; }; - Lockr.getAll = function () { + Lockr.getAll = function() { var keys = Lockr.keys(); - return keys.map(function (key) { + return keys.map(function(key) { return Lockr.get(key); }); }; Lockr.srem = function(key, value, options) { var query_key = this._getPrefixedKey(key, options), - json, - index; + json, + index; var values = Lockr.smembers(key, value); @@ -160,20 +165,20 @@ if (index > -1) values.splice(index, 1); - json = JSON.stringify({"data": values}); + json = JSON.stringify({ "data": values }); try { localStorage.setItem(query_key, json); } catch (e) { - if (console) console.warn("Lockr couldn't remove the "+ value +" from the set "+ key); + if (console) console.warn("Lockr couldn't remove the " + value + " from the set " + key); } }; - Lockr.rm = function (key) { + Lockr.rm = function(key) { localStorage.removeItem(key); }; - Lockr.flush = function () { + Lockr.flush = function() { if (Lockr.prefix.length) { Lockr.keys().forEach(function(key) { localStorage.removeItem(Lockr._getPrefixedKey(key)); diff --git a/lockr.min.js b/lockr.min.js index 7105ea9..5423cbb 100644 --- a/lockr.min.js +++ b/lockr.min.js @@ -1 +1 @@ -!function(root,factory){"undefined"!=typeof exports?"undefined"!=typeof module&&module.exports&&(exports=module.exports=factory(root,exports)):"function"==typeof define&&define.amd?define(["exports"],function(exports){root.Lockr=factory(root,exports)}):root.Lockr=factory(root,{})}(this,function(root,Lockr){"use strict";return Array.prototype.indexOf||(Array.prototype.indexOf=function(elt){var len=this.length>>>0,from=Number(arguments[1])||0;for(from=0>from?Math.ceil(from):Math.floor(from),0>from&&(from+=len);len>from;from++)if(from in this&&this[from]===elt)return from;return-1}),Lockr.prefix="",Lockr._getPrefixedKey=function(key,options){return options=options||{},options.noPrefix?key:this.prefix+key},Lockr.set=function(key,value,options){var query_key=this._getPrefixedKey(key,options);try{localStorage.setItem(query_key,JSON.stringify({data:value}))}catch(e){console&&console.warn("Lockr didn't successfully save the '{"+key+": "+value+"}' pair, because the localStorage is full.")}},Lockr.get=function(key,missing,options){var value,query_key=this._getPrefixedKey(key,options);try{value=JSON.parse(localStorage.getItem(query_key))}catch(e){value=localStorage[query_key]?{data:localStorage.getItem(query_key)}:null}return null===value?missing:"object"==typeof value&&"undefined"!=typeof value.data?value.data:missing},Lockr.sadd=function(key,value,options){var json,query_key=this._getPrefixedKey(key,options),values=Lockr.smembers(key);if(values.indexOf(value)>-1)return null;try{values.push(value),json=JSON.stringify({data:values}),localStorage.setItem(query_key,json)}catch(e){console.log(e),console&&console.warn("Lockr didn't successfully add the "+value+" to "+key+" set, because the localStorage is full.")}},Lockr.smembers=function(key,options){var value,query_key=this._getPrefixedKey(key,options);try{value=JSON.parse(localStorage.getItem(query_key))}catch(e){value=null}return null===value?[]:value.data||[]},Lockr.sismember=function(key,value,options){this._getPrefixedKey(key,options);return Lockr.smembers(key).indexOf(value)>-1},Lockr.keys=function(){var keys=[],allKeys=Object.keys(localStorage);return 0===Lockr.prefix.length?allKeys:(allKeys.forEach(function(key){-1!==key.indexOf(Lockr.prefix)&&keys.push(key.replace(Lockr.prefix,""))}),keys)},Lockr.getAll=function(){var keys=Lockr.keys();return keys.map(function(key){return Lockr.get(key)})},Lockr.srem=function(key,value,options){var json,index,query_key=this._getPrefixedKey(key,options),values=Lockr.smembers(key,value);index=values.indexOf(value),index>-1&&values.splice(index,1),json=JSON.stringify({data:values});try{localStorage.setItem(query_key,json)}catch(e){console&&console.warn("Lockr couldn't remove the "+value+" from the set "+key)}},Lockr.rm=function(key){localStorage.removeItem(key)},Lockr.flush=function(){Lockr.prefix.length?Lockr.keys().forEach(function(key){localStorage.removeItem(Lockr._getPrefixedKey(key))}):localStorage.clear()},Lockr}); \ No newline at end of file +!function(root,factory){"undefined"!=typeof exports?"undefined"!=typeof module&&module.exports&&(exports=module.exports=factory(root,exports)):"function"==typeof define&&define.amd?define(["exports"],function(exports){root.Lockr=factory(root,exports)}):root.Lockr=factory(root,{})}(this,function(root,Lockr){"use strict";return Array.prototype.indexOf||(Array.prototype.indexOf=function(elt){var len=this.length>>>0,from=Number(arguments[1])||0;for(from=from<0?Math.ceil(from):Math.floor(from),from<0&&(from+=len);from-1)return null;try{values.push(value),json=JSON.stringify({data:values}),localStorage.setItem(query_key,json)}catch(e){console.log(e),console&&console.warn("Lockr didn't successfully add the "+value+" to "+key+" set, because the localStorage is full.")}},Lockr.smembers=function(key,options){var value,query_key=this._getPrefixedKey(key,options);try{value=JSON.parse(localStorage.getItem(query_key))}catch(e){value=null}return null===value?[]:value.data||[]},Lockr.sismember=function(key,value,options){return Lockr.smembers(key).indexOf(value)>-1},Lockr.keys=function(){var keys=[],allKeys=Object.keys(localStorage);return 0===Lockr.prefix.length?allKeys:(allKeys.forEach(function(key){key.indexOf(Lockr.prefix)!==-1&&keys.push(key.replace(Lockr.prefix,""))}),keys)},Lockr.getAll=function(){var keys=Lockr.keys();return keys.map(function(key){return Lockr.get(key)})},Lockr.srem=function(key,value,options){var json,index,query_key=this._getPrefixedKey(key,options),values=Lockr.smembers(key,value);index=values.indexOf(value),index>-1&&values.splice(index,1),json=JSON.stringify({data:values});try{localStorage.setItem(query_key,json)}catch(e){console&&console.warn("Lockr couldn't remove the "+value+" from the set "+key)}},Lockr.rm=function(key){localStorage.removeItem(key)},Lockr.flush=function(){Lockr.prefix.length?Lockr.keys().forEach(function(key){localStorage.removeItem(Lockr._getPrefixedKey(key))}):localStorage.clear()},Lockr}); \ No newline at end of file diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 0000000..1330e6e --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,23 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/usr/local/bin/iojs', '/usr/local/bin/npm', 'run', 'dev' ] +2 info using npm@3.3.12 +3 info using node@v5.4.1 +4 verbose stack Error: missing script: dev +4 verbose stack at run (/usr/local/lib/node_modules/npm/lib/run-script.js:147:19) +4 verbose stack at /usr/local/lib/node_modules/npm/lib/run-script.js:57:5 +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:345:5 +4 verbose stack at checkBinReferences_ (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:309:45) +4 verbose stack at final (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:343:3) +4 verbose stack at then (/usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:113:5) +4 verbose stack at /usr/local/lib/node_modules/npm/node_modules/read-package-json/read-json.js:300:12 +4 verbose stack at tryToString (evalmachine.:414:3) +4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (evalmachine.:401:12) +5 verbose cwd /Users/Tom/Sites/github/lockr +6 error Darwin 15.5.0 +7 error argv "/usr/local/bin/iojs" "/usr/local/bin/npm" "run" "dev" +8 error node v5.4.1 +9 error npm v3.3.12 +10 error missing script: dev +11 error If you need help, you may report this error at: +11 error +12 verbose exit [ 1, true ] diff --git a/specs/lockrSpecs.js b/specs/lockrSpecs.js index dc57870..67d51de 100644 --- a/specs/lockrSpecs.js +++ b/specs/lockrSpecs.js @@ -1,16 +1,21 @@ +beforeEach(function() { + timerCallback = jasmine.createSpy('timerCallback'); + jasmine.clock().install(); +}) afterEach(function() { localStorage.clear(); + jasmine.clock().uninstall(); }); -describe('Lockr.set', function () { - it('saves a key-value pair in the localStorage', function () { +describe('Lockr.set', function() { + it('saves a key-value pair in the localStorage', function() { Lockr.set('test', 123); - expect(localStorage.getItem('test')).toEqual('{"data":123}'); + expect(localStorage.getItem('test')).toContain('"data":123,'); }); - it('should save a hash object in the localStorage', function () { - Lockr.set('my_hash', {"test": 123, "hey": "whatsup"}); + it('should save a hash object in the localStorage', function() { + Lockr.set('my_hash', { "test": 123, "hey": "whatsup" }); expect(localStorage.getItem('my_hash')).toContain('data'); expect(localStorage.getItem('my_hash')).toContain('test'); @@ -20,20 +25,19 @@ describe('Lockr.set', function () { }); }); -describe('Lockr.get', function () { +describe('Lockr.get', function() { beforeEach(function() { Lockr.set('test', 123); Lockr.sadd('array', 2); Lockr.sadd('array', 3); - Lockr.set('hash', {"test": 123, "hey": "whatsup"}); + Lockr.set('hash', { "test": 123, "hey": "whatsup" }); localStorage.nativemethod = 'NativeMethod' Lockr.set('valueFalse', false) Lockr.set('value0', 0) }); - it('returns the value for the given key from the localStorage', function () { + it('returns the value for the given key from the localStorage', function() { var value = Lockr.get('test'); - expect(value).toEqual(123); }); @@ -44,19 +48,18 @@ describe('Lockr.get', function () { expect(value).toBeUndefined(); }); - it('returns the value for the given key from the localStorage which set by native method', function () { + it('returns the value for the given key from the localStorage which set by native method', function() { var value = Lockr.get('nativemethod'); - expect(value).toEqual('NativeMethod'); }); - it('returns the value for the given key from the localStorage which equals false', function () { + it('returns the value for the given key from the localStorage which equals false', function() { var value = Lockr.get('valueFalse'); expect(value).toEqual(false); }); - it('returns the value for the given key from the localStorage which equals 0', function () { + it('returns the value for the given key from the localStorage which equals 0', function() { var value = Lockr.get('value0'); expect(value).toEqual(0); @@ -75,11 +78,10 @@ describe('Lockr.get', function () { expect(keys).toContain('one', 'two', 'three', 'four'); }); - it('gets all contents of the localStorage', function () { + it('gets all contents of the localStorage', function() { var contents = Lockr.getAll(); - expect(contents.length).toBe(6); - expect(contents).toContain({"test": 123, "hey": "whatsup"}); + expect(contents).toContain({ "test": 123, "hey": "whatsup" }); expect(contents).toContain(123); expect(contents).toContain([2, 3]); }); @@ -90,24 +92,48 @@ describe('Lockr.get', function () { localStorage.setItem('unescaped', 'a " double-quote'); }); - it("if it's not a json we get as-is", function () { + it("if it's not a json we get as-is", function() { var wrongData = Lockr.get("wrong"); expect(wrongData).toBe(',fluffy,truffly,commas,hell'); }); - it('works with unescaped characters', function () { + it('works with unescaped characters', function() { var unescaped = Lockr.get('unescaped'); expect(unescaped).toBe('a " double-quote'); }); }); + + describe('set the expiration time', function() { + beforeEach(function() { + Lockr.set('tom', '28', { expires: .1 }); //6s + + var now = new Date(); + jasmine.clock().mockDate(now); + }); + + it('works in the expiration time', function() { + jasmine.clock().tick(7000); //7s + var value = Lockr.get('tom'); + + expect(value).toBeUndefined(); + }); + + it('works in the effective time', function(){ + jasmine.clock().tick(5000); //5s + var value = Lockr.get('tom'); + + expect(value).toEqual('28'); + }); + + }); }); -describe('Lockr.rm', function () { +describe('Lockr.rm', function() { beforeEach(function() { Lockr.set('test', 123); Lockr.sadd('array', 2); Lockr.sadd('array', 3); - Lockr.set('hash', {"test": 123, "hey": "whatsup"}); + Lockr.set('hash', { "test": 123, "hey": "whatsup" }); }); it('removes succesfully a key-value pair', function() { @@ -122,15 +148,15 @@ describe('Lockr.rm', function () { }); }); -describe('Lockr.flush', function () { +describe('Lockr.flush', function() { beforeEach(function() { Lockr.set('test', 123); Lockr.sadd('array', 2); Lockr.sadd('array', 3); - Lockr.set('hash', {"test": 123, "hey": "whatsup"}); + Lockr.set('hash', { "test": 123, "hey": "whatsup" }); }); - it('clears all contents of the localStorage', function () { + it('clears all contents of the localStorage', function() { var oldContents = Lockr.getAll(); expect(oldContents.length).not.toBe(0); @@ -147,8 +173,8 @@ describe('Sets', function() { Lockr.sadd('test_set', 2); }); - describe('Lockr.sadd', function () { - it('saves a set under the given key in the localStorage', function () { + describe('Lockr.sadd', function() { + it('saves a set under the given key in the localStorage', function() { Lockr.sadd('a_set', 1); Lockr.sadd('a_set', 2); @@ -171,7 +197,7 @@ describe('Sets', function() { }); describe('Lock.sismember', function() { - it('returns true if the value exists in the given set(key)', function () { + it('returns true if the value exists in the given set(key)', function() { expect(Lockr.sismember('test_set', 1)).toEqual(true); expect(Lockr.sismember('test_set', 34)).toEqual(false); }); @@ -185,6 +211,20 @@ describe('Sets', function() { }); }); +describe('Lockr::Timestamp', function() { + it('returns the default after 10 years', function() { + //new Date(1e6 * 6 * 6 * 24 * 364); less 1 day than 10 year + expect(Lockr.getExpirationTime()).toBeGreaterThan(new Date().getTime() + 1e6 * 6 * 6 * 24 * 364); + }); + + it('should set global expires time', function() { + Lockr.expires = 10; //1m == 60s + + expect(Lockr.expires).toEqual(10); + }); + +}); + describe('Lockr::Prefixed', function() { it('should set a prefix', function() { Lockr.prefix = "imaprefix"; @@ -194,7 +234,7 @@ describe('Lockr::Prefixed', function() { expect(Lockr._getPrefixedKey('lalala')).toEqual('imaprefixlalala'); }); it('should return a non-prefixed key', function() { - expect(Lockr._getPrefixedKey('lalala', {noPrefix: true})).toEqual("lalala"); + expect(Lockr._getPrefixedKey('lalala', { noPrefix: true })).toEqual("lalala"); }); it('should save a key-value pair, prefixed', function() { Lockr.set("justlikeyou", true); @@ -215,13 +255,13 @@ describe('Lockr::Prefixed', function() { expect(keys).toContain('one', 'two', 'three', 'four'); }); - describe('Lockr.flush', function () { - it('clears all contents of the localStorage with prefix', function () { + describe('Lockr.flush', function() { + it('clears all contents of the localStorage with prefix', function() { localStorage.setItem('noprefix', false); Lockr.set('test', 123); Lockr.sadd('array', 2); Lockr.sadd('array', 3); - Lockr.set('hash', {"test": 123, "hey": "whatsup"}); + Lockr.set('hash', { "test": 123, "hey": "whatsup" }); var oldContents = Lockr.getAll(); var keys = Object.keys(localStorage);