airbug/bugcore

View on GitHub
libraries/bugcore/js/src/reflect/Reflect.js

Summary

Maintainability
A
1 hr
Test Coverage
/*
 * Copyright (c) 2016 airbug Inc. http://airbug.com
 *
 * bugcore may be freely distributed under the MIT license.
 */


//-------------------------------------------------------------------------------
// Annotations
//-------------------------------------------------------------------------------

//@Export('Reflect')

//@Require('Class')
//@Require('Notifier')
//@Require('Obj')


//-------------------------------------------------------------------------------
// Context
//-------------------------------------------------------------------------------

require('bugpack').context("*", function(bugpack) {

    //-------------------------------------------------------------------------------
    // BugPack
    //-------------------------------------------------------------------------------

    var Class       = bugpack.require('Class');
    var Notifier    = bugpack.require('Notifier');
    var Obj         = bugpack.require('Obj');


    //-------------------------------------------------------------------------------
    // Declare Class
    //-------------------------------------------------------------------------------

    /**
     * @class
     * @extends {Obj}
     */
    var Reflect = Class.extend(Obj, /** @lends {Reflect.prototype} */{

        _name: "Reflect",


        //-------------------------------------------------------------------------------
        // Constructor
        //-------------------------------------------------------------------------------

        /**
         * @constructs
         */
        _constructor: function() {

            this._super();


            //-------------------------------------------------------------------------------
            // Private Properties
            //-------------------------------------------------------------------------------

            /**
             * @private
             * @type {Notifier}
             */
            this.notifier = null;
        },


        //-------------------------------------------------------------------------------
        // Getters and Setters
        //-------------------------------------------------------------------------------

        /**
         * @return {Notifier}
         */
        getNotifier: function() {
            if (!this.notifier) {
                this.notifier = new Notifier();
            }
            return this.notifier;
        },


        //-------------------------------------------------------------------------------
        // Public Methods
        //-------------------------------------------------------------------------------

        /**
         * @return {boolean}
         */
        hasNotifier: function() {
            return !!this.notifier;
        },

        /**
         * @param {function()} callback
         * @param {Array.<string>} acceptList
         */
        observe: function(callback, acceptList) {
            var notifier = this.getNotifier();
            notifier.addObserver(callback, acceptList);
        },

        /**
         * @param {function()} callback
         */
        unobserve: function(callback) {
            var notifier = this.getNotifier();
            notifier.removeObserver(callback);
        }
    });


    //-------------------------------------------------------------------------------
    // Static Methods
    //-------------------------------------------------------------------------------

    //TODO BRN: These methods need to be redone
    /**
     * @static
     * @param {function(...):*} target
     * @param {Object} receiver
     * @param {Array.<*>} args
     * @return {*}
     */
    Reflect.apply = function(target, receiver, args) {
        return Function.prototype.apply.call(target, this, args);
    };

    /**
     * @static
     * @param {function(...):*} target
     * @param {Array.<*>} args
     * @return {*}
     */
    Reflect.construct = function(target, args) {
        function F(args) {
            return Function.prototype.apply.call(target, this, args);
        }
        F.prototype = target.prototype;
        return new F(arguments);
    };

    /**
     * @static
     * @param {Object} target
     * @param {string} name
     * @param {{}} desc
     * @return {boolean}
     */
    Reflect.defineProperty = function(target, name, desc) {
        try {
            Object.defineProperty(target, name, desc);
            Object.getNotifier(target).notify({
                name: name,
                object: target,
                type: "reconfigure"
            });
            return true;
        } catch (error) {
            return false;
        }
    };

    /**
     * @static
     * @param {Object} target
     * @param {string} name
     * @return {boolean}
     */
    Reflect.deleteProperty = function(target, name) {
        try {
            if (Reflect.has(target, name)) {
                var oldValue = target[name];
                delete target[name];
                Object.getNotifier(target).notify({
                    name: name,
                    object: target,
                    oldValue: oldValue,
                    type: "delete"
                });
                return true;
            }
        } catch(error) {
           //do nothing
        }
        return false;
    };

    /**
     * @static
     * @param {Object} target
     * @return {Iterator}
     */
    Reflect.enumerate = function(target) {
        //TODO BRN: Return an iterator of the target object that iterates the properties
    };

    /**
     * DOES include inherited properties
     * @static
     * @param {Object} target
     * @param name
     * @param receiver
     * @return {*}
     */
    Reflect.get = function(target, name, receiver) {

        //TODO BRN: What to do with receiver?

        return target[name];
    };

    /**
     * @static
     * @param {Object} target
     * @param {string} name
     * @return {Object}
     */
    Reflect.getOwnPropertyDescriptor = function(target, name) {
        return Object.getOwnPropertyDescriptor(target, name);
    };

    /**
     * @static
     * @param {Object} target
     * @return {Object}
     */
    Reflect.getPrototypeOf = function(target) {
        return Object.getPrototypeOf(target);
    };

    /**
     * DOES include inherited properties
     * @static
     * @param {Object} target
     * @param {string} name
     * @return {boolean}
     */
    Reflect.has = function(target, name) {
        return (name in target);
    };

    /**
     * @static
     * @param {Object} target
     * @return {boolean}
     */
    Reflect.isExtensible = function(target) {
        return Object.isExtensible(target);
    };

    /**
     * Does not include inherited properties
     * @static
     * @param {Object} target
     * @return {Array}
     */
    Reflect.ownKeys = function(target) {
        return Object.keys(target);
    };

    /**
     * @static
     * @param {Object} target
     * @return {boolean}
     */
    Reflect.preventExtensions = function(target) {
        try {
            Object.preventExtensions(target);
            Object.getNotifier(target).notify({
                object: target,
                type: "preventExtensions"
            });
            return true;
        } catch(error) {
            return false;
        }
    };

    /**
     * @static
     * @param {Object} target
     * @param {string} name
     * @param {*} value
     * @param {*} receiver
     * @return {boolean}
     */
    Reflect.set = function(target, name, value, receiver) {
        try {
            var oldValue = target[name];
            var changeType = "add";
            if (Reflect.has(target, name)) {
                changeType = "update";
            }
            target[name] = value;
            Object.getNotifier(target).notify({
                name: name,
                object: target,
                oldValue: oldValue,
                type: changeType
            });
            return true;
        } catch(error) {
            return false;
        }
    };

    /**
     * @static
     * @param {Object} target
     * @param {Object} newProto
     * @return {boolean}
     */
    Reflect.setPrototypeOf = function(target, newProto) {
        try {
            target.__proto__ = newProto;
            Object.getNotifier(target).notify({
                object: target,
                type: "setPrototype"
            });
            return true;
        } catch (error) {
            return false;
        }
    };



    //-------------------------------------------------------------------------------
    // Exports
    //-------------------------------------------------------------------------------

    bugpack.export('Reflect', Reflect);
});