Skip to main content
3 of 11
deleted 1887 characters in body
user avatar
user avatar

A package for basic utility functions

Compare to underscorejs if it pleases you. Once again, I hope this is well commented. Please let me know what comments/improvements I can add.

Please review all aspects of this code.

/***************************************************************************************************
**UTILITY
 - additional coverage for looping, type checking, extending ...
 - consistent ordering, naming conventions ...
 - fewer function branches
 - increased type checking and modularity
 - vector based unit testing
***************************************************************************************************/

// self used to hold client or server side global ( window or exports )
(function (self, undef) {

    "use strict";

    // holds (P)ublic properties
    var $P = {},

    // holds p(R)ivate properties
        $R = {},

        // native methods (alphabetical order)
        nativeFilter = Array.prototype.filter,
        nativeIsArray = Array.isArray,
        nativeSlice = Array.prototype.slice,
        nativeSome = Array.prototype.some,
        nativeToString = Object.prototype.toString;

    $P.noConflict = (function () {

        // $R.g holds the single global variable, used to hold all packages
        // methods
        $R.g = '$A';
        $R.previous = self[$R.g];

        // utility is required by all other packages
        // start the "pack"age list
        $P.pack = {
            utility: true
        };

        return function () {
            var temp = self[$R.g];
            self[$R.g] = $R.previous;
            return temp;
        };
    }());

    $P.isType = function (type, obj) {
        return $P.getType(obj) === type;
    };

    // returns type in a captialized string form
    // typeof is only accurate for function, string, number, boolean, and
    // undefined.  null and array are both incorrectly reported as object
    $P.getType = function (obj) {
        return nativeToString.call(obj).slice(8, -1);
    };

    $P.isFalse = function (obj) {
        return obj === false;
    };

    $P.isUndefined = function (obj) {
        return obj === undef;
    };

    $P.isNull = function (obj) {
        return obj === null;
    };

    $P.isNumber = function (value) {
        return (typeof value === 'number') && isFinite(value);
    };

    // detects null or undefined
    $P.isGone = function (obj) {
        return obj == null;
    };

    // detects anything but null or undefined
    $P.isHere = function (obj) {
        return obj != null;
    };

    // detects null, undefined, NaN, ('' ""), 0, -0, false
    $P.isFalsy = function (obj) {
        return !obj;
    };

    // detects any thing but null, undefined, NaN, ('' ""), 0, -0, false
    $P.isTruthy = function (obj) {
        return !!obj;
    };

    // shortcut as their are only two primitive boolean values
    // detects a "boxed" boolean as well
    $P.isBoolean = function (obj) {
        return obj === true || obj === false ||
            nativeToString.call(obj) === '[object Boolean]';
    };

    // delegates to native
    $P.isArray = nativeIsArray || function (obj) {
        return nativeToString.call(obj) === '[object Array]';
    };

    // jslint prefers {}.constructor(obj) over Object(obj)
    $P.isObjectAbstract = function (obj) {
        // return obj === Object(obj);
        return !!(obj && (obj === {}.constructor(obj)));
    };

    // has a numeric length property
    $P.isArrayAbstract = function (obj) {
        return !!(obj && obj.length === +obj.length);
    };

    $P.someIndex = function (arr, func, con) {
        var ind,
            len;

        // prevent type errors, note function is validated
        if ((arr == null) || (arr.length !== +arr.length) || (typeof func !== 'function')) {
            return;
        }

        // delegate to native some()
        if (nativeSome && arr.some === nativeSome) {
            return arr.some(func, con);
        }

        // if the function passes back a truthy value, the loop will terminate
        for (ind = 0, len = arr.length; ind < len; ind++) {
            if (func.call(con, arr[ind], ind, arr)) {
                return true;
            }
        }
        return false;
    };

    $P.someKey = function (obj, func, con) {
        var key;

        // prevent type errors
        // for-in will filter out null and undefined
        if ((obj == null) || (typeof func !== 'function')) {
            return;
        }
        for (key in obj) {
            if (obj.hasOwnProperty(key)) {

                // if the function passes back a truthy value,
                // the loop will terminate
                if (func.call(con, obj[key], key, obj)) {
                    return true;
                }
            }
        }
        return false;
    };

    // loop through space separated "tokens" in a string
    $P.eachString = function (str, func, con) {

        // prevent type errors
        if (typeof str !== 'string' || str === "" ||
                typeof func !== 'function') {
            return;
        }
        $P.someIndex(str.split(/\s+/), func, con);
    };

    // does not extend through the prototype chain
    // implemented for objects only
    $P.extend = function (obj) {

        // loop througth elements beyond obj
        $P.someIndex(nativeSlice.call(arguments, 1), function (val) {

            // extend it
            $P.someKey(val, function (val_inner, key) {
                obj[key] = val_inner;
            });
        });
        return obj;
    };

    // extends non-prototype properties from obj2 on to obj1
    $P.extendSafe = function (obj1, obj2) {
        var key;
        for (key in obj2) {
            if (obj2.hasOwnProperty(key)) {
                if (obj1.hasOwnProperty(key)) {
                    throw "naming collision: " + key;
                }
                obj1[key] = obj2[key];
            }
        }
        return obj1;
    };

    // if incorrect types are passed, it will return an empty array
    // arrays only
    $P.filter = function (arr, func, con) {
        var results = [];
        if ((arr == null) || (typeof func !== 'function')) {
            return results;
        }
        if (nativeFilter && arr.filter === nativeFilter) {
            return arr.filter(func, con);
        }
        $P.someIndex(arr, function (val, ind, arr) {
            if (func.call(con, val, ind, arr)) {
                results.push(val);
            }
        });
        return results;
    };

    $P.clone = function (obj) {
        return $P.extend({}, obj);
    };

    $P.someIndex(['Arguments', 'Function', 'String', 'Number',
        'Date', 'RegExp', 'Object'], function (val) {
        $P['is' + val] = function (obj) {
            return $P.isType(val, obj);
        };
    });

    $P.addU = function (str, suf) {
        return str + '_' + suf;
    };

    $P.removeU = function (str) {
        if (typeof str !== 'string' || str === "") {
            return false;
        }
        return str.slice(str, str.lastIndexOf("_"));
    };

    $P.removeSuffix = function (str, len) {
        if (typeof str !== 'string' || str === "") {
            return false;
        }
        return str.slice(0, -len);
    };

    // equivalent to IIFE but "nicer" syntax
    $P.runTest = (function () {
        var tests = {};
        return function (name, arr, func) {
            tests[name] = func.apply(this, arr);
        };
    }());

    self[$R.g] = $P.extendSafe($P, {});

// this will hold the global object - window or exports
}(this));
anon