API Docs for: 1.0.0
Show:

File: src/gallery-iterable-extras/js/iterable-extras.js

"use strict";

/**
 * @module gallery-iterable-extras
 */

/**********************************************************************
 * <p>Functional programming support for iterable classes.  The class must
 * implement the `iterator` and `newInstance` methods.</p>
 * 
 * <p>For most methods, the iterator only needs to implement `next` and
 * `atEnd`.  Backwards iterators like `reduceRight` require `prev` and
 * `atBeginning`.</p>
 * 
 * <p>Iterable classes must mix these functions:  `Y.mix(SomeClass,
 * Y.Iterable, false, null, 4);`  Passing false as the third argument
 * allows your class to provide optimized implementations of individual
 * functions.</p>
 * 
 * @main gallery-iterable-extras
 * @class Iterable
 */

Y.Iterable =
{
	/**
	 * Executes the supplied function on each item in the list.  The
	 * function receives the value, the index, and the list itself as
	 * parameters (in that order).
	 *
	 * @method each
	 * @param f {Function} the function to execute on each item
	 * @param c {Object} optional context object
	 */
	each: function(f, c)
	{
		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			f.call(c, iter.next(), i, this);
			i++;
		}
	},

	/**
	 * Executes the supplied function on each item in the list.  Iteration
	 * stops if the supplied function does not return a truthy value.  The
	 * function receives the value, the index, and the list itself as
	 * parameters (in that order).
	 *
	 * @method every
	 * @param f {Function} the function to execute on each item
	 * @param c {Object} optional context object
	 * @return {Boolean} true if every item in the array returns true from the supplied function, false otherwise
	 */
	every: function(f, c)
	{
		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			if (!f.call(c, iter.next(), i, this))
			{
				return false;
			}
			i++;
		}

		return true;
	},

	/**
	 * Executes the supplied function on each item in the list.  Returns a
	 * new list containing the items for which the supplied function
	 * returned a truthy value.  The function receives the value, the
	 * index, and the object itself as parameters (in that order).
	 *
	 * @method filter
	 * @param f {Function} the function to execute on each item
	 * @param c {Object} optional context object
	 * @return {Object} list of items for which the supplied function returned a truthy value (empty if it never returned a truthy value)
	 */
	filter: function(f, c)
	{
		var result = this.newInstance();

		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			var item = iter.next();
			if (f.call(c, item, i, this))
			{
				result.append(item);
			}
			i++;
		}

		return result;
	},

	/**
	 * Executes the supplied function on each item in the list, searching
	 * for the first item that matches the supplied function.  The function
	 * receives the value, the index, and the object itself as parameters
	 * (in that order).
	 *
	 * @method find
	 * @param f {Function} the function to execute on each item
	 * @param c {Object} optional context object
	 * @return {Mixed} the first item for which the supplied function returns true, or null if it never returns true
	 */
	find: function(f, c)
	{
		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			var item = iter.next();
			if (f.call(c, item, i, this))
			{
				return item;
			}
			i++;
		}

		return null;
	},

	/**
	 * Executes the supplied function on each item in the list and returns
	 * a new list with the results.  The function receives the value, the
	 * index, and the object itself as parameters (in that order).
	 *
	 * @method map
	 * @param f {String} the function to invoke
	 * @param c {Object} optional context object
	 * @return {Object} list of all return values
	 */
	map: function(f, c)
	{
		var result = this.newInstance();

		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			result.append(f.call(c, iter.next(), i, this));
			i++;
		}

		return result;
	},

	/**
	 * Partitions an list into two new list, one with the items for which
	 * the supplied function returns true, and one with the items for which
	 * the function returns false.  The function receives the value, the
	 * index, and the object itself as parameters (in that order).
	 *
	 * @method partition
	 * @param f {Function} the function to execute on each item
	 * @param c {Object} optional context object
	 * @return {Object} object with two properties: matches and rejects. Each is a list containing the items that were selected or rejected by the test function (or an empty object if none).
	 */
	partition: function(f, c)
	{
		var result =
		{
			matches: this.newInstance(),
			rejects: this.newInstance()
		};

		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			var item = iter.next();
			result[ f.call(c, item, i, this) ? 'matches' : 'rejects' ].append(item);
			i++;
		}

		return result;
	},

	/**
	 * Executes the supplied function on each item in the list, folding the
	 * list into a single value.  The function receives the value returned
	 * by the previous iteration (or the initial value if this is the first
	 * iteration), the value being iterated, the index, and the list itself
	 * as parameters (in that order).  The function must return the updated
	 * value.
	 *
	 * @method reduce
	 * @param init {Mixed} the initial value
	 * @param f {String} the function to invoke
	 * @param c {Object} optional context object
	 * @return {Mixed} final result from iteratively applying the given function to each item in the list
	 */
	reduce: function(init, f, c)
	{
		var result = init;

		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			result = f.call(c, result, iter.next(), i, this);
			i++;
		}

		return result;
	},

	/**
	 * Executes the supplied function on each item in the list, starting
	 * from the end and folding the list into a single value.  The function
	 * receives the value returned by the previous iteration (or the
	 * initial value if this is the first iteration), the value being
	 * iterated, the index, and the list itself as parameters (in that
	 * order).  The function must return the updated value.
	 *
	 * @method reduceRight
	 * @param init {Mixed} the initial value
	 * @param f {String} the function to invoke
	 * @param c {Object} optional context object
	 * @return {Mixed} final result from iteratively applying the given function to each item in the list
	 */
	reduceRight: function(init, f, c)
	{
		var result = init;

		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			iter.next();
			i++;
		}

		while (!iter.atBeginning())
		{
			i--;
			result = f.call(c, result, iter.prev(), i, this);
		}

		return result;
	},

	/**
	 * Executes the supplied function on each item in the list.  Returns a
	 * new list containing the items for which the supplied function
	 * returned a falsey value.  The function receives the value, the
	 * index, and the object itself as parameters (in that order).
	 *
	 * @method reject
	 * @param f {Function} the function to execute on each item
	 * @param c {Object} optional context object
	 * @return {Object} array or object of items for which the supplied function returned a falsey value (empty if it never returned a falsey value)
	 */
	reject: function(f, c)
	{
		var result = this.newInstance();

		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			var item = iter.next();
			if (!f.call(c, item, i, this))
			{
				result.append(item);
			}
			i++;
		}

		return result;
	},

	/**
	 * Executes the supplied function on each item in the list.  Iteration
	 * stops if the supplied function returns a truthy value.  The function
	 * receives the value, the index, and the list itself as parameters
	 * (in that order).
	 *
	 * @method some
	 * @param f {Function} the function to execute on each item
	 * @param c {Object} optional context object
	 * @return {Boolean} true if the function returns a truthy value on any of the items in the array, false otherwise
	 */
	some: function(f, c)
	{
		var iter = this.iterator(), i = 0;
		while (!iter.atEnd())
		{
			if (f.call(c, iter.next(), i, this))
			{
				return true;
			}
			i++;
		}

		return false;
	}
};