Skip to content

Instantly share code, notes, and snippets.

@WebReflection
Created May 13, 2016 10:16
Show Gist options
  • Select an option

  • Save WebReflection/e9803a8c05ebf0947fc665159a88772c to your computer and use it in GitHub Desktop.

Select an option

Save WebReflection/e9803a8c05ebf0947fc665159a88772c to your computer and use it in GitHub Desktop.

Revisions

  1. WebReflection created this gist May 13, 2016.
    95 changes: 95 additions & 0 deletions state.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,95 @@
    /*! (c) 2016 Andrea Giammarchi - MIT Style License */

    // simple state-like objects handler
    // based on prototypal inheritance

    function State() {'use strict';}

    // States are serializable dictionaries
    // toJSON and toString are the only reserved keywords
    // every other name can be used as name (included __proto__)
    State.prototype = Object.create(null, {
    toJSON: {value: function toJSON() {
    return State.merge(this);
    }},
    toString: {value: function toString() {
    return '[object State]';
    }}
    });

    // to create a new State
    // a fresh new one State.create();
    // or from another object State.create(prev);
    // and optionally with overrides State.create(prev, {data: 'overrides'});
    State.create = function create(obj, overrides) {
    switch (arguments.length) {
    case 2: return State.fork(obj, overrides);
    case 1: return obj instanceof State ?
    Object.create(obj) : State.merge(obj);
    default:return new State();
    }
    };

    // returns the amount of previous available states
    State.count = function count(obj) {
    var i = 0;
    while (obj = Object.getPrototypeOf(obj)) i++;
    return i - 1;
    };

    // flags properties as undefined
    State['delete'] = function del(obj, properties) {
    for (var p = [].concat(properties), i = 0; i < p.length; i++)
    obj[p[i]] = void 0;
    return obj;
    };

    // create a diff object between two states
    State.diff = function diff(s1, s2) {
    var k, diff = Object.create(null);
    for (k in s1) {
    if (!(k in s2) || s1[k] !== s2[k]) {
    diff[k] = [s1[k], s2[k]];
    }
    }
    for (k in s2) {
    if (!(k in diff) && s1[k] !== s2[k]) {
    diff[k] = [s1[k], s2[k]];
    }
    }
    return diff;
    };

    // create a new state from another state
    // and with optional overrides
    State.fork = function fork(proto, overrides) {
    var k, obj = Object.create(proto);
    for (k in overrides) obj[k] = overrides[k];
    return obj;
    };

    // merges one or more states into a single state
    State.merge = function merge() {
    for (var
    k, tmp,
    obj = new State(),
    l = arguments.length,
    i = 0; i < l; i++
    ) {
    tmp = arguments[i];
    for (k in tmp) obj[k] = tmp[k];
    }
    return obj;
    };

    // returns the previous state or null
    State.prev = function prev(obj) {
    obj = Object.getPrototypeOf(obj);
    return obj === State.prototype || obj === Object.prototype ? null : obj;
    };

    try {
    module.exports = State;
    // reachable as `require('state').State too`
    State.State = State;
    } catch(meh) {}