I really like the Prototype Framework and the functionality that comes with it, but I like Mootools even more because it’s so damn small and lightweight. Sometimes the minimalistic framework is just too light. Recently I needed some of Prototypes’ Enumerable functions for an Array but the app was implemented using Mootools. So I decided to take a look at the Array.each functions provided by the two frameworks. They’re implemented in different ways but by changing the Mootools Array.each I was able to treat a Mootools Array like a Prototype Enumerable. In this article I’ll describe how to ‘hack’ the Enumerable functionality into Mootools. If you just want the code you should take a look at my EnumArray.js.

Changing Array.each

The Array.each function can be used to loop through all elements of an Array. This functions is used by all Enumerable functions. Here’s the javascript to let you Mootools’ Array.each work with Enumerable functions:

//needed for adding breaks in Enumerable functions
$break = new Object();
//function that just returns it argument,
//needed in Enumerable functions
Class.ret = function(arg) {return arg};

Array.extend({
	//copy 'native' Mootools Array.each to Array._each
	_each: Array.prototype.each,

	//'overwrite' Array.each to handle a
	//$break thrown by Enumerable functions
	each: function(fn, bind){
		try{
			//try to iterate the Array
			this._each(fn,bind);
		}catch(e){
			//handling a break
			if(e != $break) return e;
		}
	},

	//return the last element of an Array (used in Array.zip())
	last: function() {
   		return this[this.length - 1];
  	}
});

This code enables us to add Prototype’s Enumerable functions to an Array. Actually the only thing we’ve done is enabling our Mootools Array.each to handle a Prototype $break thrown by Enumerable functions.

Adding Enumerable functionality

Let’s start adding some functions. The first function we’ll add is Enumerable.all().

/**
 * Calls an iterator function to test the values in a
 * list to see if they are all true.
 * @name Array.all()
 * @param {Function} iterator
 *  -Iterator function to call. Arguments elementValue, and elementIndex
 * @return {Boolean} Returns
 *  -true if the iterator returns true for all elements.
 */
Array.extend({
	all: function(iterator) {
	    var result = true;
	    this.each(function(value, index) {
	      result = result && !!(iterator || Class.ret)(value, index);
	      if (!result) throw $break;
	    });
	    return result;
  	}
});

Ok, great job, but what does it do? Here’s an example:

//our sample array containing three strings
var sample = ['foo','bar','baz'];

//an iterator function that returns false
//when it's argument is equal to 'bar'
var iterator = function(obj, index){
	if(obj == 'bar'){
		return false;
	}
	return true;
};

//iterate the sample array with the iterator function
sample.all(iterator); // => returns false

//iterate the sample array with an anonymous function
//that returns true when it's argument is a string
sample.all(function(obj, index){
	if(typeof obj != 'string'){
		return false;
	}
	return true;
});// => returns true

The only thing I changed in the Enumerable.all() code was replacing Prototype.K with Class.ret which are basically the same functions with different names. They bot return their arguments. To see how I added the rest of the Enumerable functions take a look at my EnumArray.js file. And if you want some examples using these functions you really have to take a look at the ‘Prototype Meets Ruby: A Look at Enumerable, Array and Hash’ article written by Justin Palmer. Eventually you can take a look at my ajax resource site for more Prototype related links.

Smaller filesize?

The EnumArray.js’s filesize is quite large (10.5 kb). I’m pretty sure you don’t need all the Enumerable functions for your arrays so you could remove the function you don’t need. Let’s say we only need the Array.findAll and Array.zip function, then our code will look something like this:

$break = new Object();
Class.ret = function(arg) {return arg};

Array.extend({
	//always include this function
	_each: Array.prototype.each,

	//always include this function
	each: function(fn, bind){
		try{
			this._each(fn,bind);
		}catch(e){
			if(e != $break) return e;
		}
	},

	//needed by Array.zip
	last: function() {
   		return this[this.length - 1];
  	},

	findAll: function(iterator) {
		var results = [];
		this.each(function(value, index) {
	    	if (iterator(value, index))
	        	results.push(value);
	    });
	    return results;
	},

	//zip needs Array.last
	zip: function() {
	    var iterator = Class.ret, args = $A(arguments);
	    if (typeof args.last() == 'function')
			iterator = args.pop();

	    var collections = [this].concat(args).map($A);
	    return this.map(function(value, index) {
	      	iterator(value = collections.pluck(index));
	      	return value;
	    });
	}
});

This is a lot less code than the full EnumArray.js. For further compression you should use Dean Edward’s packer tool.