foldspander
v1.0.0
Published
Utility to fold and expand complex JSON objects
Downloads
3
Maintainers
Readme
foldspander
Foldspander is a JavaScript utility to fold complex objects into simpler ones fit for serialization, and then expand them back into their originals.
Perfect for seamless object sharing between the client-side and the server-side!
Table of contents
- Installation
- Usage
- Native objects
- Replacer and revivers
- Helpers and custom objects
- [Nested objects] (#nested-objects)
- Tests
- TODO
- Performance
- Contributing
Installation
Install the lastest version of foldspander
from npm by executing npm install foldspander
in your shell.
Usage
Usage is simple and consists of creating an instance of foldspander and assigning different types to it.
Basic example showcasing many of the features in examples/showcase.js
:
var Foldspander = require(__dirname + '/../');
var should = require('should');
// Basic Class
function Fraction(numerator, denominator) {
this.numerator = numerator;
this.denominator = denominator;
};
var foldspand = new Foldspander({
// option that indicates that we want to have automatic support for some native Javascript types
native: true
});
// add Fraction as a foldspander type
foldspand.add(
// handle that should be unique
'fraction',
// determines if an encountered object should be folded with this routine (basic instanceof matcher)
function(obj) { return obj instanceof Fraction; },
// folds the object (breaks it into a basic JSON type)
function(frac) { return {numerator: frac.numerator, denominator: frac.denominator}; },
// expands the object (instantiates the complex type)
function(obj) { return new Fraction(obj.numerator, obj.denominator); }
);
var objs = [
{id: 1, value: new Fraction(1,3), created_at: new Date('2015-03-23')},
{id: 2, value: new Fraction(1,7), created_at: new Date('2015-03-24')}
];
// get a string of JSON from the list of objects
var str = foldspand.stringify(objs);
// parse the string and instantiate the contained objects
var exp = foldspand.parse(str);
// objs are equal to exp
exp.should.eql(objs);
// more verbose example to show that complex objects have indeed been instantiated
exp[0].value.should.be.instanceof(Fraction);
exp[1].created_at.should.be.instanceof(Date);
Native objects
Foldspander provides support for dealing with some native Javascript objects. A Foldspander instance can be prepared to accept these types by passing the option native
to the constuctor, or using the instance method native
.
The currently supported objects are:
Date
RegExp
NaN
Infinity
With more to come!
Replacer and Revivers
JSON.stringify
and JSON.parse
take optional arguments named replacer
and reviver
respectively. An instance of Foldspander provides hooks for these arguments that will apply the rules of the instance. Example in examples/revive_and_replace.js
:
var Foldspander = require(__dirname + '/../');
var should = require('should');
var foldspander = new Foldspander({native: true});
var obj = {id: 123, created_at: new Date()};
var str = JSON.stringify(obj, foldspander.getReplacer());
var exp = JSON.parse(str, foldspander.getReviver());
exp.should.eql(obj);
As a convenience, a Foldspander instance also provides a wrapper around JSON.stringify
and JSON.parse
. Example in examples/stringify_and_parse.js
:
var Foldspander = require(__dirname + '/../');
var should = require('should');
var foldspander = new Foldspander({native: true});
var obj = {id: 123, created_at: new Date()};
var str = foldspander.stringify(obj);
var exp = foldspander.parse(str);
exp.should.eql(obj);
Helpers and custom objects
It is simple to add your own custom objects. See examples/showcase.js
or look into the Usage section of this document.
In addition to the basic add
method on a Foldspander instance, some helpers are provided.
addClass
addClass
is a simple helper for basic types. It requires only a (named!) function (dubbed "class") as its first argument to work. It will add an object to a foldspander instance with the following properties:
name
- Name of the classmatcher
- Matches if an object is an instanceof the classfold
- Picks every enumerable property of the objectexpand
- Makes an instance of class and then copies every folded property into the instance
It works good for simple classes. Example in examples/add_class.js
:
var Foldspander = require(__dirname + '/../');
var should = require('should');
function Fraction(numerator, denominator) {
this.numerator = numerator;
this.denominator = denominator;
};
var foldspander = new Foldspander();
foldspander.addClass(Fraction);
var obj = new Fraction(1,3);
// 1) Every enumerable property was picked of obj
var fld = foldspander.fold(obj);
// 2) Fraction was instantiated with no arguments to the constructor
// 3) Every property picked in 1) was copied into instance from 2)
var exp = foldspander.expand(fld);
exp.should.eql(obj).and.not.equal(obj);
Nested objects
Nested objects may be serialized as well. The object walker will descend again into a folded object. Example involving a Collection of Model objects in examples/nested_objects.js
:
var Foldspander = require(__dirname + '/../');
var should = require('should');
// a model class (loosely based on Backbone.Model)
function Model(attrs) {
this.attributes = attrs || {};
}
// a collection of models class (loosely based on Backbone.Collection)
function Collection(models) {
this.models = models || [];
}
var foldspander = new Foldspander({
native: true
});
foldspander.add('collection', Foldspander.matchers.instanceof(Collection),
function(collection) { return {models: collection.models}; },
function(obj) { return new Collection(obj.models); }
);
foldspander.add('model', Foldspander.matchers.instanceof(Model),
function(model) { return {attributes: model.attributes}; },
function(obj) { return new Model(obj.attributes); }
);
var collection = new Collection([
new Model({id: 1, created_at: new Date()}),
new Model({id: 2, created_at: new Date()})
]);
var fld = foldspander.fold(collection);
var exp = foldspander.expand(fld);
// equal === strict equality (actually created a new object)
exp.should.eql(collection).and.not.equal(collection);
// verbose example to show that models are actually created
exp.models[0].should.be.eql(collection.models[0]).and.not.equal(collection.models[0]);
A similar setup might be used when folding and expanding Backbone objects.
Tests
To run the mocha.js tests, go the the project folder and run:
npm install --dev
node_modules/.bin/mocha
TODO
- Support more native types like WeakMap etc.
- Simpler functions for adding types that are instances of
- Client versions
Performance
Contributing
Highlighting issues or submitting pull requests on Github is most welcome.