Source: eva.js

/*
 * eva
 * https://github.com/gamtiq/eva
 *
 * Copyright (c) 2014 Denis Sikuler
 * Licensed under the MIT license.
 */


/**
 * Functions to create and call functions and evaluate expressions.
 * 
 * @module eva
 */


"use strict";


/**
 * Create function to further use.
 * 
 * @param {String} sCode
 *      Function's code.
 * @param {Object} [settings]
 *     Operation settings. Keys are settings names, values are corresponding settings values.
 *     The following settings are supported (setting's default value is specified in parentheses):
 *     
 *   * `debug`: `Boolean` (`false`) - specifies whether simple means for debugging should be added into function;
 *      when `true` value is specified (debug mode), the function's code is enclosed in `try` statement;
 *      the corresponding `catch` block contains `console.log` statement to display message
 *      (namely, value of `debugMessage` setting) and details about error
 *   * `debugFunc`: `String` (`console.log`) - expression specifying a function that should be used to process error
 *      when the error is caught in debug mode; the expression should be resolvable in global scope;
 *      debug message (value of `debugMessage` setting) and error object will be passed into the function
 *   * `debugMessage`: `String` (`Error in created function:`) - specifies message that should be shown/passed
 *      before data about error when the error is caught in debug mode
 *   * `expression`: `Boolean` (`false`) - specifies whether function's code is an expression;
 *      when `true` value is specified, `return` statement is added at the beginning of function's code
 *   * `paramNames`: `String` (`''`) - specifies names of function parameters
 *   * `scope`: `Boolean` (`false`) - specifies whether function's code should be wrapped in `with` statement;
 *      the value of function's first parameter is used as expression for `with` statement
 * @return {Function}
 *      Created function.
 * @alias module:eva.createFunction
 */
function createFunction(sCode, settings) {
    /*jshint evil:true, laxbreak:true, quotmark:false*/
    var nI, params, sName;
    if (! settings) {
        settings = {};
    }
    params = settings.paramNames;
    if (settings.expression) {
        sCode = "return (" + sCode + ");";
    }
    if (settings.scope) {
        if (params) {
            nI = params.indexOf(",");
            if (nI > -1) {
                sName = params.substring(0, nI);
            }
            else {
                sName = params;
            }
        }
        else {
            params = sName = "sc";
        }
        sCode = "with(" + sName + ") {" + sCode + "}";
    }
    if (settings.debug && (settings.debugFunc 
                            || (typeof console === "object" && console && typeof console.log === "function"))) {
        sCode = 'try{'
                    + sCode
                    + '}catch(_e_){'
                    + (settings.debugFunc || 'console.log')
                    + '("'
                    + (settings.debugMessage
                            ? settings.debugMessage.replace(/"/g, '\\\"')
                            : 'Error in created function:')
                    + '", _e_);}';
    }
    return params ? new Function(params, sCode) : new Function(sCode);
}

/**
 * Calculate/evaluate value of specified expression using given context and scope.
 * 
 * @param {String} sExpression
 *      Expression whose value should be calculated.
 * @param {Object} [context]
 *      Object that should be used as context (`this`) when expression is evaluated.
 * @param {Object} [scope]
 *      Object that should be used as scope when expression is evaluated.
 * @return {Any}
 *      Result of expression evaluation.
 * @see {@link module:eva.createFunction createFunction}
 * @alias module:eva.evalWith
 */
function evalWith(sExpression, context, scope) {
    var f = createFunction(sExpression, {expression: true, scope: Boolean(scope)});
    return f.apply(context || null, scope ? [scope] : []);
}

/**
 * Create function that executes specified method of the given object.
 * 
 * @param {Object} delegate
 *      Object whose method will be executed when created function is called.
 * @param {String} sMethod
 *      Name of method that will be executed.
 * @param {Object} [settings]
 *     Operation settings. Keys are settings names, values are corresponding settings values.
 *     The following settings are supported:
 *     
 *   * `destination`: `Object` - target object into which the method will be added that should be used 
 *      to access the created function
 *   * `destinationMethod`: `String` - name of method of the target object that will be used to access 
 *      the created function; the value of `sMethod` parameter by default
 * @return {Function}
 *      Created function.
 * @alias module:eva.createDelegateMethod
 */
function createDelegateMethod(delegate, sMethod, settings) {
    var result = function() {
        return delegate[sMethod].apply(delegate, arguments);
    };
    if (settings && settings.destination) {
        settings.destination[settings.destinationMethod || sMethod] = result;
    }
    return result;
}

/**
 * Create function that executes specified function with given parameters and context and returns result of call.
 * 
 * @param {Function} action
 *      Target function that will be executed when created function is called.
 * @param {Array} [paramList]
 *      Array-like object representing parameters that should be passed into the target function specified in `action` argument.
 * @param {Object} [context]
 *     Object that will be used as `this` value when calling the target function specified in `action` argument.
 *     Default value is `null`.
 * @param {Object} [settings]
 *     Operation settings. Keys are settings names, values are corresponding settings values.
 *     The following settings are supported:
 *     
 *   * `ignoreArgs`: `Boolean` - Whether arguments passed into the created function should be ignored.
 *     Default value is `false` and means that arguments will be included in parameters list for the target function
 *     depending of the value of `prependArgs` setting.
 *   * `prependArgs`: `Boolean` - Whether arguments passed into the created function should be passed into the target function
 *     before parameters specified in `paramList` argument. Default value is `false` and means that parameters list
 *     for the target function will contain values from `paramList` argument followed by arguments passed into the created function
 *     (this is similar to `Function.prototype.bind` behavior).
 * @return {Function}
 *      Created function.
 * @alias module:eva.closure
 */
function closure(action, paramList, context, settings) {
    if (! settings) {
        settings = {};
    }
    var bUseArgs = ! settings.ignoreArgs,
        bAppendArgs = ! settings.prependArgs;
    
    return function() {
        var params;
        if (bUseArgs) {
            params = paramList ? Array.prototype.slice.call(paramList, 0) : [];
            if (bAppendArgs) {
                params.push.apply(params, arguments);
            }
            else {
                params = Array.prototype.slice.call(arguments, 0).concat(params);
            }
        }
        else {
            params = paramList || [];
        }
        return action.apply(context || null, params);
    };
}

/**
 * Call each function from specified list and return array containing results of calls.
 * 
 * @param {Array} funcList
 *      Target functions that should be called.
 * @param {Array | Function} [paramList]
 *      Parameters that should be passed into each target function.
 *      If function is specified it should return array that will be used as parameters for target functions.
 *      The following parameters will be passed into the function:
 *     
 *   * a target function for which parameters list should be returned
 *   * index of the target function
 *   * array of all target functions
 * @param {Object | Function} [context]
 *     Object that will be used as `this` value when calling each target function.
 *     Default value is `null`.
 *     If function is specified it should return object that will be used as `this` value.
 *     Parameters of the function are equal to parameters of `paramList` function (see above).
 * @param {Object} [settings]
 *     Operation settings. Keys are settings names, values are corresponding settings values.
 *     The following settings are supported:
 *     
 *   * `funcContext`: `Boolean` - Whether function that is specified as `context` parameter should be used directly
 *     as `this` value. Default value is `false`.
 * @return {Array}
 *      Results of functions calling.
 * @alias module:eva.map
 */
function map(funcList, paramList, context, settings) {
    /*jshint laxbreak:true*/
    var result = [],
        nL = funcList.length,
        bGetContext, bGetParamList, func, nI;
    if (! paramList) {
        paramList = [];
    }
    if (! context) {
        context = null;
    }
    if (! settings) {
        settings = {};
    }
    bGetContext = typeof context === "function" && ! settings.funcContext;
    bGetParamList = typeof paramList === "function";
    for (nI = 0; nI < nL; nI++) {
        func = funcList[nI];
        result[nI] = func.apply(bGetContext
                                    ? context(func, nI, funcList)
                                    : context, 
                                bGetParamList
                                    ? paramList(func, nI, funcList)
                                    : paramList);
    }
    return result;
}


// Exports

module.exports = {
    createFunction: createFunction,
    evalWith: evalWith,
    createDelegateMethod: createDelegateMethod,
    closure: closure,
    map: map
};
Copyright (c) 2014 Denis Sikuler
Documentation generated by JSDoc 3.2.2 on Thu Oct 02 2014 23:48:18 GMT+0400 (MSK) using the DocStrap template.