Giter Site home page Giter Site logo

cryo's Introduction

Cryo

JSON on steroids.

Built for node.js and browsers. Cryo is inspired by Python's pickle and works similarly to JSON.stringify() and JSON.parse(). Cryo.stringify() and Cryo.parse() improve on JSON in these circumstances:

Installation

node.js

$ npm install cryo

browser

With Bower:

bower install cryo

Add the latest minified build to your project as a script:

<script type='text/javascript' src='cryo-0.0.4.js'></script>

Use

Cryo has a very simple API that mimicks JSON:

  • Cryo.stringify(item, [callbacks])
  • Cryo.parse(string, [callbacks])
var Cryo = require('cryo');

var obj = {
  name: 'Hunter',
  created: new Date(),
  hello: function() {
    console.log(this.name + ' said hello in ' + this.created.getFullYear() + '!');
  }
};

var frozen = Cryo.stringify(obj);
var hydrated = Cryo.parse(frozen);

hydrated.hello(); // Hunter said hello in 2013!

More powerful JSON

Undefined

Cryo takes a verbatim snapshot of all your properties, including those that are undefined - which JSON ignores.

var Cryo = require('../lib/cryo');

var obj = {
  defaultValue: undefined
};

var withJSON = JSON.parse(JSON.stringify(obj));
console.log(withJSON.hasOwnProperty('defaultValue'));   // false

var withCryo = Cryo.parse(Cryo.stringify(obj));
console.log(withCryo.hasOwnProperty('defaultValue'));   // true

Date

Cryo successfully works with Date objects, which JSON.stringify() mangles into strings.

var Cryo = require('../lib/cryo');

var now = new Date();

var withJSON = JSON.parse(JSON.stringify(now));
console.log(withJSON instanceof Date);              // false

var withCryo = Cryo.parse(Cryo.stringify(now));
console.log(withCryo instanceof Date);              // true

References

JSON.stringify() makes multiple copies of single objects, losing object relationships. When several references to the same object are stringified with JSON, those references are turned into clones of each other. Cryo maintains object references so the restored objects are identical to the originals. This is easier to understand with an example:

var Cryo = require('../lib/cryo');

var userList = [{ name: 'Abe' }, { name: 'Bob' }, { name: 'Carl' }];
var state = {
  users: userList,
  activeUser: userList[1]
};

var withJSON = JSON.parse(JSON.stringify(state));
console.log(withJSON.activeUser === withJSON.users[1]);   // false

var withCryo = Cryo.parse(Cryo.stringify(state));
console.log(withCryo.activeUser === withCryo.users[1]);   // true

Infinity

Cryo successfully stringifies and parses Infinity, which JSON mangles into null.

var Cryo = require('../lib/cryo');

var number = Infinity;

var withJSON = JSON.parse(JSON.stringify(number));
console.log(withJSON === Infinity);                 // false

var withCryo = Cryo.parse(Cryo.stringify(number));
console.log(withCryo === Infinity);                 // true

Properties

Objects, Arrays, Dates, and Functions can all hold properties, but JSON will only stringify properties on Objects. Cryo will recover properties from all containers:

var Cryo = require('../lib/cryo');

function first() {}
first.second = new Date();
first.second.third = [1, 2, 3];
first.second.third.fourth = { name: 'Hunter' };

try {
  var withJSON = JSON.parse(JSON.stringify(first));
  console.log(withJSON.second.third.fourth.name === 'Hunter');
} catch(e) {
  console.log('error');                                       // error
}

var withCryo = Cryo.parse(Cryo.stringify(first));
console.log(withCryo.second.third.fourth.name === 'Hunter');  // true

Functions

Cryo will stringify functions, which JSON ignores.

Note: Usually, if you've come up with a solution that needs to serialize functions, a better solution exists that doesn't. However, sometimes this can be enormously useful. Cryo will make faithful hydrated functions and objects with properties that are functions.

var Cryo = require('../lib/cryo');

function fn() {
  console.log('Hello, world!');
}

try {
  var withJSON = JSON.parse(JSON.stringify(fn));
  withJSON();
} catch(e) {
  console.log('error');                             // error
}

var withCryo = Cryo.parse(Cryo.stringify(fn));
withCryo();                                         // Hello, world!

Custom Types

Cryo can allow you to stringify and parse custom types by using the optional callbacks argument. The prepare for stringify is called before each item is stringified, allowing you to alter an object just before it's serialized. The finalize callback for parse is called after each item is re-created, allowing you to alter an object just after it's de-serialized:

function Person() {}
var person = new Person();
person.friends = [new Person()];

var stringified = Cryo.stringify(person, { prepare: function(obj) {
  // store any object's constructor name under a variable called
  // __class__ which can later be be used to restore the object's
  // prototype.
  obj.__class__ = obj.constructor.name;
}});
var parsed = Cryo.parse(stringified, { finalize: function(obj) {
  // look for objects that define a __class__ and restore their
  // prototype by finding the class on the global window (you may need
  // to look elsewhere for the class).
  if (obj.__class__ && window[obj.__class__]) {
    obj.__proto__ = window[obj.__class__].prototype;
    delete obj.__class__;
  }
}});

parsed instanceof Person; // true
parsed.friends[0] instanceof Person; // true

Controlling Serialization

By default, all own properties of an object will be serialized. However, you can specify a custom isSerializable method as part of callbacks to pass to stringify to change this behavior. By default it is defined as such:

Cryo.stringify(data, { isSerializable: function(item, key) {
  return item.hasOwnProperty(key);
}});

DOM

JSON chokes when you try to stringify an object with a reference to a DOM node, giving Uncaught TypeError: Converting circular structure to JSON. Cryo will ignore DOM nodes so you can serialize such objects without hassle.

var obj = {
  button: document.getElementById('my-button');
  message: 'Hello'
};

try {
  var withJSON = JSON.parse(JSON.stringify(obj));
  console.log(withJSON.message === 'Hello');
} catch(e) {
  console.log('error');                             // error
}

var withCryo = Cryo.parse(Cryo.stringify(obj));
console.log(withCryo.message === 'Hello');          // true

Stringified Output

Cryo.stringify() returns valid JSON data with non-compatible types encoded as strings. Thus, anything you can do with JSON, you can do with Cryo.

Here is the stringified result from the hello, world example:

{
  "root":"_CRYO_REF_2",
  "references":[
    {
      "contents": {},
      "value":"_CRYO_DATE_1358245390835"
    },
    {
      "contents": {},
      "value":"_CRYO_FUNCTION_function () {\n    console.log(this.name + ' said hello in ' + this.created.getFullYear() + '!');\n  }"
    },
    {
      "contents":{
        "name":"Hunter",
        "created":"_CRYO_REF_0",
        "hello":"_CRYO_REF_1"
      },
      "value":"_CRYO_OBJECT_"
    }
  ]
}

Tests

Tests require node.js.

$ git clone git://github.com/hunterloftis/cryo.git
$ cd cryo
$ make setup
$ make test

cryo's People

Contributors

booleangate avatar hunterloftis avatar wbyoung avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cryo's Issues

Objects of a given class

As it stands, cryo can re-create objects, but recreates vanilla objects, not those of their original type.

Would you be open to a pull request that added functionality so that something like this would be possible:

function Shape() {
  this.x = 0;
  this.y = 0;
}

var shape = new Shape();
var cryoShape = Cryo.parse(Cryo.stringify(shape));

shape instanceof Shape; // true
cryoShape instanceof Shape; // true

It would likely use __proto__ and/or setPrototypeOf and may require a way for types to be found during Cryo.parse.

RangeError: Maximum call stack size exceeded

I am trying to stringify objects slightly larger than the example object that I have posted. And I receive the following error.

Error:

RangeError: Maximum call stack size exceeded
    at Process.hasOwnProperty (native)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:57:20)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)
    at cloneWithReferences (/Users/Alex/code/systems/alive/node_modules/cryo/lib/cryo.js:58:26)

Object:

{"root":"_CRYO_REF_5","references":[{"contents":{},"value":"_CRYO_OBJECT_"},{"contents":{"0":"node","1":"app.js"},"value":"_CRYO_ARRAY_"},{"contents":{"port":9000},"value":"_CRYO_OBJECT_"},{"contents":{"0":"ignore","1":10,"2":11},"value":"_CRYO_ARRAY_"},{"contents":{},"value":"_CRYO_FUNCTION_function (restarts) {\n    return sleep[restarts - 1] || sleep[sleep.length - 1]\n  }"},{"contents":{"domain":null,"_events":"_CRYO_REF_0","_eventsCount":0,"_maxListeners":"_CRYO_UNDEFINED_","id":null,"status":"stopped","command":"_CRYO_REF_1","name":"test","cwd":"/Users/Alex/psudo-server/www/node/_test","env":"_CRYO_REF_2","uid":"_CRYO_UNDEFINED_","gid":"_CRYO_UNDEFINED_","pid":0,"stdio":"_CRYO_REF_3","stdout":"_CRYO_UNDEFINED_","stderr":"_CRYO_UNDEFINED_","windowsVerbatimArguments":"_CRYO_UNDEFINED_","crashed":false,"sleep":"_CRYO_REF_4","maxRestarts":5,"kill":30000,"child":null,"started":null,"timeout":null},"value":"_CRYO_OBJECT_"}]}

Support ES6 Class

I was just wondering if anyone has looked into adding this before and not done it for any reason, and if not, @hunterloftis would you accept a PR to add this?

Security issue

Hi,

I'm a member of the Node.js Security WG and we received a report regarding a security issue with this module. We tried inviting the author by e-mail but received no response so I'm opening this issue and inviting anyone with commit and npm publish rights to collaborate with us on a fix.

Support ES6 Map and Set

Certainly these can be done in a custom way, but it would be nice to support these structures by default, since they are often used.

Prototype functions

Does it work with functions defined on an object's prototype? At a first look it doesn't seem so.

status of this project?

Looks like the last commit was in 2017. Is this project still maintained or should it be considered EOL? @hunterloftis
Also, I couldn't find a license listed for your project. Can you make one publicly available?

Example output of stringify?

Looked through most of the tests, examples, and docs and still can't find an example of what the output looks like.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.