Source: MultiLens.js

"use strict";

var _ = require('lodash'),
    Lens = require('./Lens'),

    get,
    over,

    MultiLens;

get = function (lenses) {
    return function (obj) {
        var gets;

        if (_.isArray(lenses)) {
            gets = [];

            _.forEach(lenses, function (lens) {
                gets.push(lens.get(obj));
            });
        } else {
            if (_.isObject(lenses)) {
                gets = {};

                _.forEach(_.keys(lenses), function (key) {
                    gets[key] = lenses[key].get(obj);
                });
            }
        }

        return gets;
    };
};

over = function (lenses) {
    return function (obj, func) {
        var newObj = _.cloneDeep(obj);

        if (_.isArray(lenses)) {
            _.forEach(lenses, function (lens) {
                newObj = lens.over(newObj, func);
            });
        } else {
            if (_.isObject(lenses)) {
                _.forEach(_.values(lenses), function (lens) {
                    newObj = lens.over(newObj, func);
                });
            }
        }
        return newObj;
    };
};

/**
 * A `MultiLens` is a `Lens` that can focus on multiple things at once. It takes
 * an array of `Lens`es or an object with `Lens`es as values; `get`, `set` and `over`
 * run corresponding functions over the input object for each internal lens.
 *
 * @param {object|Array} lenses Lenses used to focus on input objects.
 * @param {object} flags Additional flags to add to the Lens instance
 * @returns {MultiLens}
 * @constructor
 */
MultiLens = function (lenses, flags) {
    flags = flags || {};

    // Guard against no 'new'
    if (!this instanceof MultiLens) {
        return new MultiLens(lenses, flags);
    }

    flags._multi = true;

    if (_.isObject(lenses)) {
        _.forEach(_.keys(lenses), function (key) {
            if (!((lenses[key] instanceof Lens) || (lenses[key] instanceof MultiLens))) {
                throw new Error('Cannot construct MultiLens from non-lens');
            }
        });

        this._lenses = lenses;
    }

    if (_.isArray(lenses)) {
        _.forEach(lenses, function (lens) {
            if (!((lens instanceof Lens) || (lens instanceof MultiLens))) {
                throw new Error('Cannot construct MultiLens from non-lens');
            }
        });

        this._lenses = lenses;
    }

    this.base = Lens;
    this.base(get(lenses), over(lenses), flags);
};

MultiLens.prototype = new Lens;

module.exports = MultiLens;