rhaboo
v3.2.2
Published
Persistent JS Objects
Downloads
14
Maintainers
Readme
Rhaboo
Website at http://rhaboo.org
Please star the repo if you use it - Thx.
Thanks to brasofilo for the logo.
What is it?
This library gives a JS programmer persistence whilst staying close to the JS object model. In other words, it makes ordinary JS objects (including deeply nested ones) persist as if by magic. The underlying storage is either localStorage or sessionStorage, as you choose.
The usual approach to this problem is to stringify and parse the entire object, but that gives lousy performance on large datasets. For instance, if you had an array of 999 diary entries and the user added a 1000th, then the entire history would have to be parsed and re-stringified. Rhaboo is more cunning than that.
Another problem with stringify/parse is that they innacurately recreate objects, especially arrays. For instance, properties of arrays with non-numeric names are ignored and all sparse positions are filled with null. This library recreates objects and arrays more precisely.
It's highly portable because it only relies on HTML5's localStorage. So you can use it on these browsers: http://caniuse.com/#feat=namevalue-storage
Persistence code is deferred with setTimeout so the user interface remains snappy even when a lot of data changes are occuring.
Quick Installation
Download rhaboo.min.js and include it with a script tag.
Install with
npm install rhaboo
and point your browser at:
file://<wherever you npm-installed it>/node_modules/rhaboo/generate-tests/generated-pages/page.0.html
to check that it installed ok. Include the library in your HTML file:
<script src="node_modules/rhaboo/rhaboo.min.js"></script>
Installation for building or generating tests
Clone the rhaboo repo and then in its directory do:
npm install grunt grunt-contrib-uglify grunt-browserify seedrandom ajon parunpar
grunt # be patient with this
firefox generate-tests/generated-pages/page.0.html
(If grunt just exits immediately without output, you may have mistakenly installed a debian package called node.
You need to uninstall that and do this instead.
If you installed grunt while that package was installed, you can hack the #! of which grunt
to say nodejs instead of node.)
Usage
Make a persistent object like this:
var mystore = Rhaboo.persistent("Some unique name"); //localStorage
//or
var mystore = Rhaboo.perishable("Some unique name"); //sessionStorage
(Honestly, 'new' is not desired here.)
The library immediately attempts to restore this object from localStorage. If it remains empty then this must be the first time your program was run on this machine, so you detect that fact and populate your store. On subsequent runs the contents of mystore will be as you left them.
You can read from it exactly like any other object:
console.log(mystore.foo);
but to modify it, instead of writing:
mystore.foo = 123; //Wrong!!!
or equivalently:
mystore["foo"] = 123; //Wrong!!!
you should write:
mystore.write("foo", 123); //Right!!!
It's an ugly substitution but at least it's one-to-one so it doesn't affect your overall design.
You use that same write function for inserting new properties and modifying existing ones.
Deletion of properties calls for another substitution. Instead of:
delete mystore.foo; //Wrong!!!
you should write:
mystore.erase("foo"); //Right!!!
(Contrary to popular belief, setting a property to undefined is not the same as deleting it.) For arrays, splice should be used.
You can also pass a complex object to write
:
mystore.write("foo", {
pinky: [],
perky: true,
porky: [
"The",
3,
"Musketeers",
new Date(),
{}
]
} );
and apply write
to its nested objects:
mystore.foo.porky.write(1, 4);
All the standard array modifying functions work persistently:
mystore.foo.pinky.push("bar");
mystore.foo.pinky.reverse();
There's no function to delete everything in a persistent, but that could be made simple by keeping everything in a single property of the persistent:
mystore.write('killable', {
game: 'tiddlywinks',
player: { name: 'zorro', gender: 'm', hiscore: 10
} );
mystore.erase('killable');
You may have multiple root persistents, i.e. calls to Rhaboo.persistent/perishable - there's no performance penalty for this. You may have multiple persistent references to the same persistent object or sub-object within a given persistent or perishable, but please don't put references to perishable objects inside persistent ones or vice versa (there's no check for this - it will just go bonkers.) You may put non-numerically named properties into arrays or set object or array entries to null, undefined or non-existent. The persisted objects will behave just like those im memory. Regex- and function-valued properties are not supported.
Rhaboo adds a property called _rhaboo
to each object it makes persistent, but this won't show up in standard iterations of the form:
for ( var key in object ) {
if ( object.hasOwnProperty(key) ) {
var val = object[key];
...
}
}
because Object.prototype.hasOwnProperty has been replaced with one that returns false for _rhaboo
.
Browserification
If you use node.js modules or browserify, you can treat src/arr.js as the module which delivers all of rhaboo. In src/unbrowserify.js (which is what browserify renders into ./rhaboo.max.js) you can see how the module.exports from arr.js is assigned to something called Rhaboo at global scope. This is to hand rhaboo's facilities to people who can't write "require" cos they're in a browser and don't use browserify.
Variants
'Sand' and 'rocks' are two different strategies for optimising the internal storage format. Both are subject to ongoing experiments. You can include e.g. 'rhaboo.rocks.min.js' if you have a special preference, but for the time being, 'rhaboo.min.js' provides something that works.